diff --git a/.env.example b/.env.example index 083ccf4a90..2d51aff4b0 100644 --- a/.env.example +++ b/.env.example @@ -43,4 +43,4 @@ SEND_LOGS=1 LOGS_LEVEL_DEBUG=1 # Network identification -NETWORK_ID=TestnetV1.0.1b +NETWORK_ID=TestnetV1.0.2b diff --git a/importers/xml_examples/Retail/03_Pink_to_Orange_shipment.xml b/importers/xml_examples/Retail/03_Pink_to_Orange_shipment.xml index c01e3f4c96..94a43b92aa 100755 --- a/importers/xml_examples/Retail/03_Pink_to_Orange_shipment.xml +++ b/importers/xml_examples/Retail/03_Pink_to_Orange_shipment.xml @@ -40,7 +40,7 @@ Green Company Retail - 0xCcAB7BD40602B78C0649032D2532dEFa23A4C0 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A Pink @@ -136,4 +136,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail/04_Pink_to_Orange_receipt.xml b/importers/xml_examples/Retail/04_Pink_to_Orange_receipt.xml index 56240e2b3c..1758f262c6 100755 --- a/importers/xml_examples/Retail/04_Pink_to_Orange_receipt.xml +++ b/importers/xml_examples/Retail/04_Pink_to_Orange_receipt.xml @@ -40,7 +40,7 @@ Green Company Retail - 0xCcAB7BD40602B78C0649032D2532dEFa23A4C0 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A Pink @@ -135,4 +135,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail/05_Pink_to_Red_shipment.xml b/importers/xml_examples/Retail/05_Pink_to_Red_shipment.xml index 4835d7db03..fc6fba586b 100755 --- a/importers/xml_examples/Retail/05_Pink_to_Red_shipment.xml +++ b/importers/xml_examples/Retail/05_Pink_to_Red_shipment.xml @@ -38,9 +38,9 @@ - Green + Red Company Retail - 0xCcAB7BD40602B78C0649032D2532dEFa23A4C0 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A Pink @@ -136,4 +136,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail/06_Pink_to_Red_receipt.xml b/importers/xml_examples/Retail/06_Pink_to_Red_receipt.xml index 4f68d84ffa..443485f2be 100755 --- a/importers/xml_examples/Retail/06_Pink_to_Red_receipt.xml +++ b/importers/xml_examples/Retail/06_Pink_to_Red_receipt.xml @@ -40,7 +40,7 @@ Red Company Retail - 0xCcAB7BD40602B78C0649032D2532dEFa23A4C0 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A Pink diff --git a/importers/xml_examples/Retail_with_Zk/04_Pink_to_Orange_shipment.xml b/importers/xml_examples/Retail_with_Zk/04_Pink_to_Orange_shipment.xml index c01e3f4c96..e21db68b7a 100755 --- a/importers/xml_examples/Retail_with_Zk/04_Pink_to_Orange_shipment.xml +++ b/importers/xml_examples/Retail_with_Zk/04_Pink_to_Orange_shipment.xml @@ -38,9 +38,9 @@ - Green + Orange Company Retail - 0xCcAB7BD40602B78C0649032D2532dEFa23A4C0 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A Pink @@ -136,4 +136,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail_with_Zk/05_Pink_to_Orange_receipt.xml b/importers/xml_examples/Retail_with_Zk/05_Pink_to_Orange_receipt.xml index 56240e2b3c..c3e7cdb7d2 100755 --- a/importers/xml_examples/Retail_with_Zk/05_Pink_to_Orange_receipt.xml +++ b/importers/xml_examples/Retail_with_Zk/05_Pink_to_Orange_receipt.xml @@ -38,9 +38,9 @@ - Green + Orange Company Retail - 0xCcAB7BD40602B78C0649032D2532dEFa23A4C0 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A Pink diff --git a/importers/xml_examples/Retail_with_Zk/06_Pink_to_Red_shipment.xml b/importers/xml_examples/Retail_with_Zk/06_Pink_to_Red_shipment.xml index 4835d7db03..fc6fba586b 100755 --- a/importers/xml_examples/Retail_with_Zk/06_Pink_to_Red_shipment.xml +++ b/importers/xml_examples/Retail_with_Zk/06_Pink_to_Red_shipment.xml @@ -38,9 +38,9 @@ - Green + Red Company Retail - 0xCcAB7BD40602B78C0649032D2532dEFa23A4C0 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A Pink @@ -136,4 +136,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail_with_Zk/07_Pink_to_Red_receipt.xml b/importers/xml_examples/Retail_with_Zk/07_Pink_to_Red_receipt.xml index 075d465f39..0cd8c5cfd7 100755 --- a/importers/xml_examples/Retail_with_Zk/07_Pink_to_Red_receipt.xml +++ b/importers/xml_examples/Retail_with_Zk/07_Pink_to_Red_receipt.xml @@ -38,9 +38,9 @@ - Green + Red Company Retail - 0xCcAB7BD40602B78C0649032D2532dEFa23A4C0 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A Pink @@ -135,4 +135,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail_with_aggregation/01_Green_packing.xml b/importers/xml_examples/Retail_with_aggregation/01_Green_packing.xml index a36d4e51fe..ba3571306c 100644 --- a/importers/xml_examples/Retail_with_aggregation/01_Green_packing.xml +++ b/importers/xml_examples/Retail_with_aggregation/01_Green_packing.xml @@ -36,15 +36,10 @@ 0xAaBbAd7BD40602B78C0649032D2532dEFa23A4C0 - Green + Pink Company producer 0xBbAaAd7BD40602B78C0649032D2532dEFa24323 - - Green - Company producer - 0xCcCcAd7BD40602B78C0649032D2532dEFa212345 - @@ -59,27 +54,6 @@ urn:epc:id:sgln:Building_Green_V2 - - - Building - Distributor - urn:ot:object:actor:id:Company_Pink - - urn:epc:id:sgln:Building_Pink_V3 - urn:epc:id:sgln:Building_Pink_V4 - - - - - Building - Retail store - urn:ot:object:actor:id:Company_Orange - - urn:epc:id:sgln:Building_Orange_V5 - urn:epc:id:sgln:Building_Orange_V6 - - - @@ -173,4 +147,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail_with_aggregation/02_Green_to_pink_shipment.xml b/importers/xml_examples/Retail_with_aggregation/02_Green_to_pink_shipment.xml index f1bf802b5e..515104d016 100644 --- a/importers/xml_examples/Retail_with_aggregation/02_Green_to_pink_shipment.xml +++ b/importers/xml_examples/Retail_with_aggregation/02_Green_to_pink_shipment.xml @@ -36,15 +36,10 @@ 0xAaBbAd7BD40602B78C0649032D2532dEFa23A4C0 - Green + Pink Company producer 0xBbAaAd7BD40602B78C0649032D2532dEFa24323 - - Green - Company producer - 0xCcCcAd7BD40602B78C0649032D2532dEFa212345 - diff --git a/importers/xml_examples/Retail_with_aggregation/03_Green_to_pink_receipt.xml b/importers/xml_examples/Retail_with_aggregation/03_Green_to_pink_receipt.xml index 9eaa20d7d2..f4eb6fc856 100644 --- a/importers/xml_examples/Retail_with_aggregation/03_Green_to_pink_receipt.xml +++ b/importers/xml_examples/Retail_with_aggregation/03_Green_to_pink_receipt.xml @@ -36,15 +36,10 @@ 0xAaBbAd7BD40602B78C0649032D2532dEFa23A4C0 - Green + Pink Company producer 0xBbAaAd7BD40602B78C0649032D2532dEFa24323 - - Green - Company producer - 0xCcCcAd7BD40602B78C0649032D2532dEFa212345 - @@ -164,4 +159,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail_with_aggregation/04_Pink_to_orange_shipment.xml b/importers/xml_examples/Retail_with_aggregation/04_Pink_to_orange_shipment.xml index d9686a51fd..6f75ff7242 100644 --- a/importers/xml_examples/Retail_with_aggregation/04_Pink_to_orange_shipment.xml +++ b/importers/xml_examples/Retail_with_aggregation/04_Pink_to_orange_shipment.xml @@ -41,9 +41,9 @@ 0xBbAaAd7BD40602B78C0649032D2532dEFa24323 - Green + Orange Company producer - 0xCcCcAd7BD40602B78C0649032D2532dEFa212345 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A @@ -164,4 +164,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail_with_aggregation/05_Pink_to_orange_receipt.xml b/importers/xml_examples/Retail_with_aggregation/05_Pink_to_orange_receipt.xml index 6bb512d254..d0b959f800 100644 --- a/importers/xml_examples/Retail_with_aggregation/05_Pink_to_orange_receipt.xml +++ b/importers/xml_examples/Retail_with_aggregation/05_Pink_to_orange_receipt.xml @@ -41,9 +41,9 @@ 0xBbAaAd7BD40602B78C0649032D2532dEFa24323 - Green + Orange Company producer - 0xCcCcAd7BD40602B78C0649032D2532dEFa212345 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A @@ -164,4 +164,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail_with_aggregation/06_Orange_unpacking.xml b/importers/xml_examples/Retail_with_aggregation/06_Orange_unpacking.xml index 2c52276ea6..1bfc68a13c 100644 --- a/importers/xml_examples/Retail_with_aggregation/06_Orange_unpacking.xml +++ b/importers/xml_examples/Retail_with_aggregation/06_Orange_unpacking.xml @@ -41,9 +41,9 @@ 0xBbAaAd7BD40602B78C0649032D2532dEFa24323 - Green + Orange Company producer - 0xCcCcAd7BD40602B78C0649032D2532dEFa212345 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A @@ -151,4 +151,4 @@ - \ No newline at end of file + diff --git a/importers/xml_examples/Retail_with_aggregation/07_Orange_unpacking_all.xml b/importers/xml_examples/Retail_with_aggregation/07_Orange_unpacking_all.xml index ec8c87761a..8463c0066d 100644 --- a/importers/xml_examples/Retail_with_aggregation/07_Orange_unpacking_all.xml +++ b/importers/xml_examples/Retail_with_aggregation/07_Orange_unpacking_all.xml @@ -41,9 +41,9 @@ 0xBbAaAd7BD40602B78C0649032D2532dEFa24323 - Green + Orange Company producer - 0xCcCcAd7BD40602B78C0649032D2532dEFa212345 + 0x90398eF02389Ef85F262737b4B3aDB8eE588B43A @@ -149,4 +149,4 @@ - \ No newline at end of file + diff --git a/migrations/20180407120531-create-data-info.js b/migrations/20180407120531-create-data-info.js index 5383f8ded0..7d05a3e138 100644 --- a/migrations/20180407120531-create-data-info.js +++ b/migrations/20180407120531-create-data-info.js @@ -23,6 +23,10 @@ module.exports = { allowNull: false, type: Sequelize.STRING, }, + import_hash: { + allowNull: false, + type: Sequelize.STRING, + }, import_timestamp: { allowNull: false, type: Sequelize.DATE, @@ -31,6 +35,10 @@ module.exports = { allowNull: false, type: Sequelize.INTEGER, }, + transaction_hash: { + allowNull: true, + type: Sequelize.STRING, + }, }), down: (queryInterface, Sequelize) => queryInterface.dropTable('data_infos'), }; diff --git a/models/data_info.js b/models/data_info.js index 1db164fa53..73c56861f6 100644 --- a/models/data_info.js +++ b/models/data_info.js @@ -5,8 +5,10 @@ module.exports = (sequelize, DataTypes) => { data_provider_wallet: DataTypes.STRING(42), total_documents: DataTypes.INTEGER, root_hash: DataTypes.STRING(40), + import_hash: DataTypes.STRING(40), import_timestamp: DataTypes.DATE, data_size: DataTypes.INTEGER, + transaction_hash: DataTypes.STRING(128), }, { tableName: 'data_info', }); diff --git a/modules/Blockchain.js b/modules/Blockchain.js index a4b73451e6..b32a8b9167 100644 --- a/modules/Blockchain.js +++ b/modules/Blockchain.js @@ -35,10 +35,11 @@ class Blockchain { * Writes data import root hash on blockchain * @param importId * @param rootHash + * @param importHash * @returns {Promise} */ - writeRootHash(importId, rootHash) { - return this.blockchain.writeRootHash(importId, rootHash); + writeRootHash(importId, rootHash, importHash) { + return this.blockchain.writeRootHash(importId, rootHash, importHash); } /** diff --git a/modules/Blockchain/Ethereum/Transactions.js b/modules/Blockchain/Ethereum/Transactions.js index 9ee1fb2cae..dd101cbcc2 100644 --- a/modules/Blockchain/Ethereum/Transactions.js +++ b/modules/Blockchain/Ethereum/Transactions.js @@ -34,10 +34,11 @@ class Transactions { break; } } catch (error) { - this.log.trace(`Nonce too low / underpriced detected. Retrying. ${error.toString()}`); if (!error.toString().includes('nonce too low') && !error.toString().includes('underpriced')) { throw new Error(error); } + + this.log.trace(`Nonce too low / underpriced detected. Retrying. ${error.toString()}`); // eslint-disable-next-line no-await-in-loop await sleep.sleep(2000); } diff --git a/modules/Blockchain/Ethereum/contracts/Escrow.sol b/modules/Blockchain/Ethereum/contracts/Escrow.sol index 4d00395c9b..cea2043988 100644 --- a/modules/Blockchain/Ethereum/contracts/Escrow.sol +++ b/modules/Blockchain/Ethereum/contracts/Escrow.sol @@ -96,6 +96,7 @@ library SafeMath { ERC20 public token; Bidding public bidding; Reading public reading; + uint256 public litigation_interval; modifier senderNotZero() { require(msg.sender != address(0), "Sender address cannot be 0"); @@ -106,6 +107,7 @@ library SafeMath { public senderNotZero{ require ( tokenAddress != address(0), "Token address cannot be 0"); token = ERC20(tokenAddress); + litigation_interval = 15 * 60; // Starting interval time = 15 minutes } function setBidding(address biddingAddress) @@ -143,6 +145,8 @@ library SafeMath { uint256 checksum; EscrowStatus escrow_status; + + uint256 litigation_interval; } mapping(bytes32 => mapping(address => EscrowDefinition)) public escrow; @@ -169,6 +173,7 @@ library SafeMath { this_escrow.end_time = 0; this_escrow.total_time_in_seconds = total_time_in_minutes.mul(60); this_escrow.escrow_status = EscrowStatus.initiated; + this_escrow.litigation_interval = litigation_interval; emit EscrowInitated(import_id, DH_wallet, token_amount, stake_amount, total_time_in_minutes); } @@ -348,7 +353,7 @@ library SafeMath { require(this_litigation.litigation_status == LitigationStatus.initiated, "Litigation status must be initiated"); - if(block.timestamp > this_litigation.litigation_start_time + 15 minutes){ + if(block.timestamp > this_litigation.litigation_start_time + this_escrow.litigation_interval){ uint256 amount_to_send; uint cancelation_time = this_litigation.litigation_start_time; @@ -394,10 +399,10 @@ library SafeMath { function cancelInactiveLitigation(bytes32 import_id) public senderNotZero{ LitigationDefinition storage this_litigation = litigation[import_id][msg.sender]; - + EscrowDefinition storage this_escrow = escrow[import_id][msg.sender]; require(this_litigation.litigation_status == LitigationStatus.answered, "Litigation status must be answered"); - require(this_litigation.answer_timestamp + 15 minutes <= block.timestamp, - "Function cannot be called within 15 minutes after answering litigation"); + require(this_litigation.answer_timestamp + this_escrow.litigation_interval <= block.timestamp, + "Function cannot be called within this_escrow.litigation_interval after answering litigation"); this_litigation.litigation_status = LitigationStatus.completed; emit LitigationCompleted(import_id, msg.sender, false); @@ -414,8 +419,8 @@ library SafeMath { || this_litigation.litigation_status == LitigationStatus.answered, "Litigation status not initiated or answered"); if (this_litigation.litigation_status == LitigationStatus.initiated){ - require(this_litigation.litigation_start_time + 15 minutes <= block.timestamp, - "Function cannot be called within 15 minutes after initiating litigation"); + require(this_litigation.litigation_start_time + this_escrow.litigation_interval <= block.timestamp, + "Function cannot be called within this_escrow.litigation_interval after initiating litigation"); uint256 amount_to_send; diff --git a/modules/Blockchain/Ethereum/contracts/OTFingerprintStore.sol b/modules/Blockchain/Ethereum/contracts/OTFingerprintStore.sol index 4fcc6f1cf4..9134ab2984 100644 --- a/modules/Blockchain/Ethereum/contracts/OTFingerprintStore.sol +++ b/modules/Blockchain/Ethereum/contracts/OTFingerprintStore.sol @@ -27,7 +27,13 @@ contract OTFingerprintStore is Ownable{ uint256 public _version; /* Data Holder Fingerprint Store */ // mapping(address => mapping (bytes32 => bytes32)) public DHFS; - mapping(address => mapping (bytes32 => bytes32)) public DHFS; + mapping(address => mapping (bytes32 => FingerprintDefinition)) public DHFS; + + struct FingerprintDefinition{ + bytes32 graph_hash; + bytes32 import_hash; + } + /* Agreement store */ struct Agreement { uint256 startTime; @@ -49,18 +55,20 @@ contract OTFingerprintStore is Ownable{ } /* Fingerprinting */ /* Store a fingerpring of a graph identified by batch_id and hash of batch_id */ - function addFingerPrint(string batch_id, bytes32 batch_id_hash, bytes32 graph_hash) public returns (bool){ + function addFingerPrint(string batch_id, bytes32 batch_id_hash, bytes32 graph_hash, bytes32 import_hash) public returns (bool){ require(msg.sender!=address(0)); require(batch_id_hash!=0x0); require(graph_hash!=0x0); - require(DHFS[msg.sender][batch_id_hash] == bytes32(0)); - DHFS[msg.sender][batch_id_hash] = graph_hash; + require(DHFS[msg.sender][batch_id_hash].graph_hash== bytes32(0)); + DHFS[msg.sender][batch_id_hash].graph_hash = graph_hash; + DHFS[msg.sender][batch_id_hash].import_hash = import_hash; + emit Fingerprint(msg.sender,batch_id,batch_id_hash,graph_hash); } - function getFingerprintByBatchHash(address dataHolder, bytes32 batch_id_hash) public constant returns (bytes32 fingerprint){ + function getFingerprintByBatchHash(address dataHolder, bytes32 batch_id_hash) public constant returns (bytes32 graph_hash, bytes32 import_hash){ require(dataHolder!=address(0)); require(batch_id_hash!=0x0); - return DHFS[dataHolder][batch_id_hash]; + return (DHFS[dataHolder][batch_id_hash].graph_hash, DHFS[dataHolder][batch_id_hash].import_hash); } /* Agreements */ function createAgreement(address dataHolder, uint256 startTime, uint256 endTime,bytes32 batch_id_hash, bytes32 data_hash) public returns (bool){ diff --git a/modules/Blockchain/Ethereum/escrow-contract/abi.json b/modules/Blockchain/Ethereum/escrow-contract/abi.json index f3bc3f855c..7227e24e99 100644 --- a/modules/Blockchain/Ethereum/escrow-contract/abi.json +++ b/modules/Blockchain/Ethereum/escrow-contract/abi.json @@ -1,639 +1,657 @@ [ - { - "constant": false, - "inputs": [ - { - "name": "DC_wallet", - "type": "address" - }, - { - "name": "DH_wallet", - "type": "address" - }, - { - "name": "import_id", - "type": "bytes32" - }, - { - "name": "token_amount", - "type": "uint256" - }, - { - "name": "stake_amount", - "type": "uint256" - }, - { - "name": "total_time_in_minutes", - "type": "uint256" - } - ], - "name": "initiateEscrow", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "import_id", - "type": "bytes32" - } - ], - "name": "payOut", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - }, - { - "name": "", - "type": "address" - } - ], - "name": "litigation", - "outputs": [ - { - "name": "requested_data_index", - "type": "uint256" - }, - { - "name": "requested_data", - "type": "bytes32" - }, - { - "name": "litigation_start_time", - "type": "uint256" - }, - { - "name": "answer_timestamp", - "type": "uint256" - }, - { - "name": "litigation_status", - "type": "uint8" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "owner", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "import_id", - "type": "bytes32" - }, - { - "name": "DH_wallet", - "type": "address" - }, - { - "name": "requested_data_index", - "type": "uint256" - }, - { - "name": "hash_array", - "type": "bytes32[]" - } - ], - "name": "initiateLitigation", - "outputs": [ - { - "name": "newLitigationInitiated", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "import_id", - "type": "bytes32" - }, - { - "name": "litigation_root_hash", - "type": "bytes32" - }, - { - "name": "distribution_root_hash", - "type": "bytes32" - }, - { - "name": "checksum", - "type": "uint256" - } - ], - "name": "addRootHashAndChecksum", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "import_id", - "type": "bytes32" - }, - { - "name": "correspondent_wallet", - "type": "address" - }, - { - "name": "sender_is_DH", - "type": "bool" - } - ], - "name": "cancelEscrow", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "import_id", - "type": "bytes32" - } - ], - "name": "cancelInactiveLitigation", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "import_id", - "type": "bytes32" - }, - { - "name": "DH_wallet", - "type": "address" - }, - { - "name": "proof_data", - "type": "bytes32" - } - ], - "name": "proveLitigaiton", - "outputs": [ - { - "name": "DH_was_penalized", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - }, - { - "name": "", - "type": "address" - } - ], - "name": "escrow", - "outputs": [ - { - "name": "DC_wallet", - "type": "address" - }, - { - "name": "token_amount", - "type": "uint256" - }, - { - "name": "tokens_sent", - "type": "uint256" - }, - { - "name": "stake_amount", - "type": "uint256" - }, - { - "name": "last_confirmation_time", - "type": "uint256" - }, - { - "name": "end_time", - "type": "uint256" - }, - { - "name": "total_time_in_seconds", - "type": "uint256" - }, - { - "name": "litigation_root_hash", - "type": "bytes32" - }, - { - "name": "distribution_root_hash", - "type": "bytes32" - }, - { - "name": "checksum", - "type": "uint256" - }, - { - "name": "escrow_status", - "type": "uint8" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "bidding", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "biddingAddress", - "type": "address" - } - ], - "name": "setBidding", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "readingAddress", - "type": "address" - } - ], - "name": "setReading", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "import_id", - "type": "bytes32" - }, - { - "name": "DH_wallet", - "type": "address" - } - ], - "name": "verifyEscrow", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "token", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "import_id", - "type": "bytes32" - }, - { - "name": "requested_data", - "type": "bytes32" - } - ], - "name": "answerLitigation", - "outputs": [ - { - "name": "answer_accepted", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "reading", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "name": "tokenAddress", - "type": "address" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "token_amount", - "type": "uint256" - }, - { - "indexed": false, - "name": "stake_amount", - "type": "uint256" - }, - { - "indexed": false, - "name": "total_time_in_minutes", - "type": "uint256" - } - ], - "name": "EscrowInitated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - } - ], - "name": "EscrowConfirmed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - } - ], - "name": "EscrowVerified", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - } - ], - "name": "EscrowCanceled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - } - ], - "name": "EscrowCompleted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "amount", - "type": "uint256" - } - ], - "name": "Payment", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "requested_data_index", - "type": "uint256" - } - ], - "name": "LitigationInitiated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - } - ], - "name": "LitigationAnswered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - } - ], - "name": "LitigationTimedOut", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "import_id", - "type": "bytes32" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "DH_was_penalized", - "type": "bool" - } - ], - "name": "LitigationCompleted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - } -] \ No newline at end of file + { + "constant": true, + "inputs": [], + "name": "litigation_interval", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + }, + { + "name": "", + "type": "address" + } + ], + "name": "litigation", + "outputs": [ + { + "name": "requested_data_index", + "type": "uint256" + }, + { + "name": "requested_data", + "type": "bytes32" + }, + { + "name": "litigation_start_time", + "type": "uint256" + }, + { + "name": "answer_timestamp", + "type": "uint256" + }, + { + "name": "litigation_status", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + }, + { + "name": "", + "type": "address" + } + ], + "name": "escrow", + "outputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "tokens_sent", + "type": "uint256" + }, + { + "name": "stake_amount", + "type": "uint256" + }, + { + "name": "last_confirmation_time", + "type": "uint256" + }, + { + "name": "end_time", + "type": "uint256" + }, + { + "name": "total_time_in_seconds", + "type": "uint256" + }, + { + "name": "litigation_root_hash", + "type": "bytes32" + }, + { + "name": "distribution_root_hash", + "type": "bytes32" + }, + { + "name": "checksum", + "type": "uint256" + }, + { + "name": "escrow_status", + "type": "uint8" + }, + { + "name": "litigation_interval", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "bidding", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "token", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "reading", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "tokenAddress", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "token_amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "stake_amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "total_time_in_minutes", + "type": "uint256" + } + ], + "name": "EscrowInitated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + } + ], + "name": "EscrowConfirmed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + } + ], + "name": "EscrowVerified", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + } + ], + "name": "EscrowCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + } + ], + "name": "EscrowCompleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Payment", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "requested_data_index", + "type": "uint256" + } + ], + "name": "LitigationInitiated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + } + ], + "name": "LitigationAnswered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + } + ], + "name": "LitigationTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "import_id", + "type": "bytes32" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "DH_was_penalized", + "type": "bool" + } + ], + "name": "LitigationCompleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "biddingAddress", + "type": "address" + } + ], + "name": "setBidding", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "readingAddress", + "type": "address" + } + ], + "name": "setReading", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "DH_wallet", + "type": "address" + }, + { + "name": "import_id", + "type": "bytes32" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "stake_amount", + "type": "uint256" + }, + { + "name": "total_time_in_minutes", + "type": "uint256" + } + ], + "name": "initiateEscrow", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "import_id", + "type": "bytes32" + }, + { + "name": "litigation_root_hash", + "type": "bytes32" + }, + { + "name": "distribution_root_hash", + "type": "bytes32" + }, + { + "name": "checksum", + "type": "uint256" + } + ], + "name": "addRootHashAndChecksum", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "import_id", + "type": "bytes32" + }, + { + "name": "DH_wallet", + "type": "address" + } + ], + "name": "verifyEscrow", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "import_id", + "type": "bytes32" + } + ], + "name": "payOut", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "import_id", + "type": "bytes32" + }, + { + "name": "correspondent_wallet", + "type": "address" + }, + { + "name": "sender_is_DH", + "type": "bool" + } + ], + "name": "cancelEscrow", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "import_id", + "type": "bytes32" + }, + { + "name": "DH_wallet", + "type": "address" + }, + { + "name": "requested_data_index", + "type": "uint256" + }, + { + "name": "hash_array", + "type": "bytes32[]" + } + ], + "name": "initiateLitigation", + "outputs": [ + { + "name": "newLitigationInitiated", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "import_id", + "type": "bytes32" + }, + { + "name": "requested_data", + "type": "bytes32" + } + ], + "name": "answerLitigation", + "outputs": [ + { + "name": "answer_accepted", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "import_id", + "type": "bytes32" + } + ], + "name": "cancelInactiveLitigation", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "import_id", + "type": "bytes32" + }, + { + "name": "DH_wallet", + "type": "address" + }, + { + "name": "proof_data", + "type": "bytes32" + } + ], + "name": "proveLitigaiton", + "outputs": [ + { + "name": "DH_was_penalized", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ] \ No newline at end of file diff --git a/modules/Blockchain/Ethereum/index.js b/modules/Blockchain/Ethereum/index.js index 8b548e7ac0..ea8bacf9b3 100644 --- a/modules/Blockchain/Ethereum/index.js +++ b/modules/Blockchain/Ethereum/index.js @@ -105,29 +105,30 @@ class Ethereum { * Writes data import root hash on Ethereum blockchain * @param importId * @param rootHash + * @param importHash * @returns {Promise} */ - writeRootHash(importId, rootHash) { + writeRootHash(importId, rootHash, importHash) { const options = { gasLimit: this.web3.utils.toHex(this.config.gas_limit), gasPrice: this.web3.utils.toHex(this.config.gas_price), to: this.otContractAddress, }; - const importIdHash = Utilities.sha3(importId); + const importIdHash = Utilities.soliditySHA3(importId); this.log.notify(`Writing root hash to blockchain for import ${importId}`); - return this.transactions.queueTransaction(this.otContractAbi, 'addFingerPrint', [importId, importIdHash, rootHash], options); + return this.transactions.queueTransaction(this.otContractAbi, 'addFingerPrint', [importId, importIdHash, rootHash, importHash], options); } /** * Gets root hash for import * @param dcWallet DC wallet - * @param dataId Import ID + * @param importId Import ID * @return {Promise} */ async getRootHash(dcWallet, importId) { - const importIdHash = Utilities.sha3(importId.toString()); + const importIdHash = Utilities.soliditySHA3(importId.toString()); this.log.trace(`Fetching root hash for dcWallet ${dcWallet} and importIdHash ${importIdHash}`); return this.otContract.methods.getFingerprintByBatchHash(dcWallet, importIdHash).call(); } diff --git a/modules/Blockchain/Ethereum/ot-contract/abi.json b/modules/Blockchain/Ethereum/ot-contract/abi.json index cfc78bc975..b229196127 100644 --- a/modules/Blockchain/Ethereum/ot-contract/abi.json +++ b/modules/Blockchain/Ethereum/ot-contract/abi.json @@ -1,357 +1,373 @@ -[ - { - "constant": false, - "inputs": [ - { - "name": "batch_id", - "type": "string" - }, - { - "name": "batch_id_hash", - "type": "bytes32" - }, - { - "name": "graph_hash", - "type": "bytes32" - } - ], - "name": "addFingerPrint", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getVersion", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "party", - "type": "address" - } - ], - "name": "getNumberOfAgreements", - "outputs": [ - { - "name": "agreementCount", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "dataHolder", - "type": "address" - }, - { - "name": "batch_id_hash", - "type": "bytes32" - } - ], - "name": "getFingerprintByBatchHash", - "outputs": [ - { - "name": "fingerprint", - "type": "bytes32" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "_version", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "uint256" - } - ], - "name": "agreements", - "outputs": [ - { - "name": "startTime", - "type": "uint256" - }, - { - "name": "endTime", - "type": "uint256" - }, - { - "name": "data_hash", - "type": "bytes32" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "uint256" - } - ], - "name": "agreementPartiesList", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "owner", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "dataHolder", - "type": "address" - }, - { - "name": "startTime", - "type": "uint256" - }, - { - "name": "endTime", - "type": "uint256" - }, - { - "name": "batch_id_hash", - "type": "bytes32" - }, - { - "name": "data_hash", - "type": "bytes32" - } - ], - "name": "createAgreement", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getAgreementPartiesCount", - "outputs": [ - { - "name": "partiesCount", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "version", - "type": "uint256" - } - ], - "name": "OTHashStore", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "bytes32" - }, - { - "name": "", - "type": "uint256" - } - ], - "name": "DHFS", - "outputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "dataHolder", - "type": "address" - }, - { - "indexed": true, - "name": "batch_id", - "type": "string" - }, - { - "indexed": true, - "name": "batch_id_hash", - "type": "bytes32" - }, - { - "indexed": false, - "name": "graph_hash", - "type": "bytes32" - } - ], - "name": "Fingerprint", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "dataCreator", - "type": "address" - }, - { - "indexed": true, - "name": "dataHolder", - "type": "address" - }, - { - "indexed": true, - "name": "batch_id_hash", - "type": "bytes32" - }, - { - "indexed": false, - "name": "graph_hash", - "type": "bytes32" - }, - { - "indexed": false, - "name": "startTime", - "type": "uint256" - }, - { - "indexed": false, - "name": "endTime", - "type": "uint256" - } - ], - "name": "Agreed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - } -] - + [ + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "bytes32" + } + ], + "name": "DHFS", + "outputs": [ + { + "name": "graph_hash", + "type": "bytes32" + }, + { + "name": "import_hash", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "_version", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "agreements", + "outputs": [ + { + "name": "startTime", + "type": "uint256" + }, + { + "name": "endTime", + "type": "uint256" + }, + { + "name": "data_hash", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "agreementPartiesList", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "dataHolder", + "type": "address" + }, + { + "indexed": true, + "name": "batch_id", + "type": "string" + }, + { + "indexed": true, + "name": "batch_id_hash", + "type": "bytes32" + }, + { + "indexed": false, + "name": "graph_hash", + "type": "bytes32" + } + ], + "name": "Fingerprint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "dataCreator", + "type": "address" + }, + { + "indexed": true, + "name": "dataHolder", + "type": "address" + }, + { + "indexed": true, + "name": "batch_id_hash", + "type": "bytes32" + }, + { + "indexed": false, + "name": "graph_hash", + "type": "bytes32" + }, + { + "indexed": false, + "name": "startTime", + "type": "uint256" + }, + { + "indexed": false, + "name": "endTime", + "type": "uint256" + } + ], + "name": "Agreed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "getVersion", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "dataHolder", + "type": "address" + }, + { + "name": "batch_id_hash", + "type": "bytes32" + } + ], + "name": "getFingerprintByBatchHash", + "outputs": [ + { + "name": "graph_hash", + "type": "bytes32" + }, + { + "name": "import_hash", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "party", + "type": "address" + } + ], + "name": "getNumberOfAgreements", + "outputs": [ + { + "name": "agreementCount", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "constructor", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "version", + "type": "uint256" + } + ], + "name": "OTHashStore", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "batch_id", + "type": "string" + }, + { + "name": "batch_id_hash", + "type": "bytes32" + }, + { + "name": "graph_hash", + "type": "bytes32" + }, + { + "name": "import_hash", + "type": "bytes32" + } + ], + "name": "addFingerPrint", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "dataHolder", + "type": "address" + }, + { + "name": "startTime", + "type": "uint256" + }, + { + "name": "endTime", + "type": "uint256" + }, + { + "name": "batch_id_hash", + "type": "bytes32" + }, + { + "name": "data_hash", + "type": "bytes32" + } + ], + "name": "createAgreement", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getAgreementPartiesCount", + "outputs": [ + { + "name": "partiesCount", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ] \ No newline at end of file diff --git a/modules/Blockchain/Ethereum/signing.js b/modules/Blockchain/Ethereum/signing.js index 11d7cbd4a2..c238079313 100644 --- a/modules/Blockchain/Ethereum/signing.js +++ b/modules/Blockchain/Ethereum/signing.js @@ -151,7 +151,7 @@ bytes32 confirmation_hash, uint8 v, bytes32 r, bytes32 s - var hash = utilities.sha3(raw_data); + var hash = utilities.soliditySHA3(raw_data); var signature = Account.sign(hash, `0x${private_key}`); var vrs = Account.decodeSignature(signature); s = { diff --git a/modules/Blockchain/Ethereum/test/bidding.test.js b/modules/Blockchain/Ethereum/test/bidding.test.js index a3d5f2775c..97e1eee2ad 100644 --- a/modules/Blockchain/Ethereum/test/bidding.test.js +++ b/modules/Blockchain/Ethereum/test/bidding.test.js @@ -617,6 +617,8 @@ contract('Bidding testing', async (accounts) => { var read_token_amount = 10e10; var read_stake_factor = 2; + const reader = 1; + const seller = 2; // eslint-disable-next-line no-undef it('Should initiate reading between acc[2] and acc[1]', async () => { @@ -624,7 +626,7 @@ contract('Bidding testing', async (accounts) => { const reading = await Reading.deployed(); var response = await reading.purchased_data.call(import_id, accounts[chosen_bids[0]]); - console.log(`${JSON.stringify(response)}`); + console.log(`\t Purchased data of profile[${seller}]: ${JSON.stringify(response)}`); var actual_DC_wallet = response[0]; var actual_distribution_root_hash = response[1]; @@ -642,15 +644,18 @@ contract('Bidding testing', async (accounts) => { 'Purchased data - checksum not matching', ); - await reading.initiatePurchase( + const tx = await reading.initiatePurchase( import_id, - accounts[chosen_bids[0]], + accounts[seller], read_token_amount, read_stake_factor, - { from: accounts[2] }, + { from: accounts[reader] }, ); - response = await reading.purchase.call(accounts[chosen_bids[0]], accounts[2], import_id); + console.log(`\t Gas Used for initiating purchase: ${tx.receipt.gasUsed}`); + + + response = await reading.purchase.call(accounts[seller], accounts[reader], import_id); var actual_token_amount = response[0]; var actual_stake_factor = response[1]; var actual_status = response[5].toNumber(); @@ -668,7 +673,126 @@ contract('Bidding testing', async (accounts) => { assert.equal( actual_status, 1, - 'Read status not initiated', + 'Read status not equal initiated', + ); + }); + + // eslint-disable-next-line no-undef + it('Should send commitment', async () => { + // Get instances of contracts used in the test + const reading = await Reading.deployed(); + const util = await TestingUtilities.deployed(); + + const commitment = await util.keccakString.call('This only a test'); + + const tx = await reading.sendCommitment( + import_id, + accounts[reader], + commitment, + { from: accounts[seller] }, + ); + + console.log(`\t Gas Used for sending commitment: ${tx.receipt.gasUsed}`); + + const response = await reading.purchase.call(accounts[seller], accounts[reader], import_id); + var actual_commitment = response[2]; + var actual_status = response[5].toNumber(); + + assert.equal( + actual_commitment, + commitment, + 'Commitment not matching', + ); + assert.equal( + actual_status, + 2, + 'Read status not equal committed', + ); + }); + + // eslint-disable-next-line no-undef + it('Should confirm purchase', async () => { + // Get instances of contracts used in the test + const reading = await Reading.deployed(); + + const tx = await reading.confirmPurchase( + import_id, + accounts[seller], + { from: accounts[reader] }, + ); + + console.log(`\t Gas Used for confirming purchase: ${tx.receipt.gasUsed}`); + + const response = await reading.purchase.call(accounts[seller], accounts[reader], import_id); + var actual_status = response[5].toNumber(); + + assert.equal( + actual_status, + 3, + 'Read status not equal confirmed', ); }); + + // eslint-disable-next-line no-undef + it('Should send encrypted block', async () => { + // Get instances of contracts used in the test + const reading = await Reading.deployed(); + + const encryptedBlock = 1235; // This is only for testing, not a valid value + + const tx = await reading.sendEncryptedBlock( + import_id, + accounts[reader], + encryptedBlock, + { from: accounts[seller] }, + ); + + console.log(`\t Gas Used for sending encrypted block: ${tx.receipt.gasUsed}`); + + const response = await reading.purchase.call(accounts[seller], accounts[reader], import_id); + var actual_encrypted_block = response[3].toNumber(); + var actual_status = response[5].toNumber(); + assert.equal( + actual_encrypted_block, + encryptedBlock, + 'Encrypted block value not valid', + ); + assert.equal( + actual_status, + 4, + 'Read status not equal sent', + ); + }); + + // THIS TEST IS NOT USED + // BECAUSE THE TIMEOUT SET ON PAYOUT WOULD EXCEED THE MAX TIME ALLOWED FOR A TEST + + // // eslint-disable-next-line no-undef + // it('Should payout seller for data purchase', async () => { + // // Get instances of contracts used in the test + // const reading = await Reading.deployed(); + + // await new Promise(resolve => setTimeout(resolve, 305000)); + + // let tx = await reading.payOut( + // import_id, + // accounts[reader], + // { from: accounts[seller] }, + // ); + + // console.log(`\t Gas Used for purchase payment: ${tx.receipt.gasUsed}`); + + + // let response = await reading.purchase.call( + // accounts[seller], + // accounts[reader], + // import_id, + // ); + // var actual_status = response[5].toNumber(); + // assert.equal( + // actual_status, + // 7, + // 'Read status not equal completed', + // ); + // }); }); diff --git a/modules/DHService.js b/modules/DHService.js index 1a3cd551b5..d34e1fe9c3 100644 --- a/modules/DHService.js +++ b/modules/DHService.js @@ -485,7 +485,7 @@ class DHService { * @param importId ID of import. * @returns {Promise<*>} */ - async getVerticesForImport(importId) { + async getImport(importId) { // Check if import came from DH replication or reading replication. const holdingData = await Models.holding_data.find({ where: { id: importId } }); @@ -527,7 +527,7 @@ class DHService { return { vertices: values[0], edges: values[1] }; } - throw Error(`Cannot find vertices for import ID ${importId}.`); + throw Error(`Cannot find import for import ID ${importId}.`); } listenToBlockchainEvents() { diff --git a/modules/EventEmitter.js b/modules/EventEmitter.js index d1e3501f63..b3f9223995 100644 --- a/modules/EventEmitter.js +++ b/modules/EventEmitter.js @@ -148,14 +148,70 @@ class EventEmitter { const { import_id: importId } = data; logger.info(`Get vertices trigered for import ID ${importId}`); try { - const result = await dhService.getVerticesForImport(importId); + const result = await dhService.getImport(importId); if (result.vertices.length === 0) { data.response.status(204); } else { data.response.status(200); } - data.response.send(result); + + const rawData = 'raw-data' in data.request.headers && data.request.headers['raw-data'] === 'true'; + + if (rawData) { + data.response.send(result); + } else { + data.response + .send(ImportUtilities.normalizeImport(result.vertices, result.edges)); + } + } catch (error) { + logger.error(`Failed to get vertices for import ID ${importId}.`); + notifyError(error); + data.response.status(500); + data.response.send({ + message: error, + }); + } + }); + + this._on('api-import-info', async (data) => { + const { importId } = data; + logger.info(`Get imported vertices triggered for import ID ${importId}`); + try { + const dataInfo = await Models.data_info.find({ where: { import_id: importId } }); + + if (!dataInfo) { + logger.info(`Import data for import ID ${importId} does not exist.`); + data.response.status(404); + data.response.send({ + message: `Import data for import ID ${importId} does not exist`, + }); + return; + } + + const result = await dhService.getImport(importId); + + const dataimport = + await Models.data_info.findOne({ where: { import_id: importId } }); + + if (result.vertices.length === 0 || dataimport == null) { + data.response.status(204); + data.response.send(result); + } else { + data.response.status(200); + data.response.send({ + import: ImportUtilities.normalizeImport( + result.vertices, + result.edges, + ), + import_hash: ImportUtilities.importHash( + result.vertices, + result.edges, + ), + root_hash: dataimport.root_hash, + transaction: dataimport.transaction_hash, + }); + } } catch (error) { logger.error(`Failed to get vertices for import ID ${importId}.`); notifyError(error); @@ -185,6 +241,28 @@ class EventEmitter { }); }); + this._on('api-imports-info', async (data) => { + logger.debug('Get import ids'); + try { + const dataimports = await Models.data_info.findAll(); + data.response.status(200); + data.response.send(dataimports.map(di => ({ + import_id: di.import_id, + total_documents: di.total_documents, + root_hash: di.root_hash, + import_hash: di.import_hash, + data_size: di.data_size, + transaction_hash: di.transaction_hash, + }))); + } catch (e) { + logger.error('Failed to get information about imports', e); + data.response.status(500); + data.response.send({ + message: 'Failed to get information about imports', + }); + } + }); + this._on('api-query', (data) => { logger.info(`Get veritces triggered with query ${JSON.stringify(data.query)}`); product.getVertices(data.query).then((res) => { @@ -223,12 +301,32 @@ class EventEmitter { } logger.info(`Get root hash triggered with dcWallet ${dcWallet} and importId ${importId}`); blockchain.getRootHash(dcWallet, importId).then((res) => { - data.response.send(res); + if (res) { + if (!Utilities.isZeroHash(res.graph_hash)) { + data.response.status(200); + data.response.send({ + root_hash: res.graph_hash, + import_hash: res.import_hash, + }); + } else { + data.response.status(404); + data.response.send({ + message: `Root hash not found for query ${JSON.stringify(data.query)}`, + }); + } + } else { + data.response.status(500); + data.response.send({ + message: `Failed to get root hash for query ${JSON.stringify(data.query)}`, + }); + } }).catch((err) => { logger.error(`Failed to get root hash for query ${JSON.stringify(data.query)}`); notifyError(err); data.response.status(500); - data.response.send(`Failed to get root hash for query ${JSON.stringify(data.query)}`); // TODO rethink about status codes + data.response.send({ + message: `Failed to get root hash for query ${JSON.stringify(data.query)}`, // TODO rethink about status codes + }); }); }); @@ -344,6 +442,7 @@ class EventEmitter { const { import_id, root_hash, + import_hash, total_documents, wallet, // TODO: Sender's wallet is ignored for now. vertices, @@ -355,10 +454,12 @@ class EventEmitter { .create({ import_id, root_hash, + import_hash, data_provider_wallet: config.node_wallet, import_timestamp: new Date(), total_documents, data_size: dataSize, + transaction_hash: null, }).catch((error) => { logger.error(error); notifyError(error); @@ -369,13 +470,17 @@ class EventEmitter { remoteControl.importFailed(error); }); - if (data.replicate) { this.emit('api-create-offer', { import_id, response: data.response }); } else { + await dcController.writeRootHash(import_id, root_hash, import_hash); + data.response.status(201); data.response.send({ + message: 'Import success', import_id, + import_hash, + wallet: config.node_wallet, }); remoteControl.importSucceeded(); } @@ -456,8 +561,8 @@ class EventEmitter { this._on('api-gs1-import-request', async (data) => { try { - logger.info(`GS1 import with ${data.filepath} triggered.`); - const responseObject = await importer.importXMLgs1(data.filepath); + logger.debug('GS1 import triggered'); + const responseObject = await importer.importXMLgs1(data.content); const { error } = responseObject; const { response } = responseObject; @@ -473,8 +578,8 @@ class EventEmitter { this._on('api-wot-import-request', async (data) => { try { - logger.info(`WOT import with ${data.filepath} triggered.`); - const responseObject = await importer.importWOT(data.filepath); + logger.debug('WOT import triggered'); + const responseObject = await importer.importWOT(data.content); const { error } = responseObject; const { response } = responseObject; @@ -998,11 +1103,11 @@ class EventEmitter { // async this._on('kad-verify-import-request', async (request) => { - logger.info('Request to verify encryption key of replicated data received'); - const { wallet: dhWallet } = request.contact[1]; const { epk, importId, encryptionKey } = request.params.message; + logger.info(`Request to verify encryption key of replicated data received from ${dhWallet}`); + const dcNodeId = request.contact[0]; await dcController.verifyKeys(importId, dcNodeId, dhWallet, epk, encryptionKey); }); diff --git a/modules/GS1Importer.js b/modules/GS1Importer.js index 2b90841571..4ef134c4e7 100644 --- a/modules/GS1Importer.js +++ b/modules/GS1Importer.js @@ -827,19 +827,23 @@ class GS1Importer { }; } - async parseGS1(gs1XmlFile) { - const gs1XmlFileBuffer = fs.readFileSync(gs1XmlFile); + /** + * Import GS1 contents + * @param contents + * @returns {Promise} + */ + async parseGS1(contents) { const xsdFileBuffer = fs.readFileSync('./importers/xsd_schemas/EPCglobal-epcis-masterdata-1_2.xsd'); const schema = xsd.parse(xsdFileBuffer.toString()); - const validationResult = schema.validate(gs1XmlFileBuffer.toString()); + const validationResult = schema.validate(contents); if (validationResult !== null) { this.helper.handleError(`Failed to validate schema. ${validationResult}`, 400); } return new Promise(resolve => parseString( - gs1XmlFileBuffer, + contents, { explicitArray: false, mergeAttrs: true }, /* eslint-disable consistent-return */ async (err, json) => { diff --git a/modules/GS1Utilities.js b/modules/GS1Utilities.js index c28f624ae4..8383a1301e 100644 --- a/modules/GS1Utilities.js +++ b/modules/GS1Utilities.js @@ -167,7 +167,7 @@ class GS1Utilities { privateData[key] = value; const sorted = Utilities.sortObject(value); - data.private[key] = Utilities.sha3(JSON.stringify(`${sorted}${salt}`)); + data.private[key] = Utilities.soliditySHA3(JSON.stringify(`${sorted}${salt}`)); } privateData._salt = salt; } @@ -184,7 +184,7 @@ class GS1Utilities { for (const key in original) { const value = original[key]; const sorted = Utilities.sortObject(value); - result[key] = Utilities.sha3(JSON.stringify(`${sorted}${salt}`)); + result[key] = Utilities.soliditySHA3(JSON.stringify(`${sorted}${salt}`)); } return Utilities.objectDistance(hashed, result); } diff --git a/modules/ImportUtilities.js b/modules/ImportUtilities.js index 4fbc972e6f..faafa36563 100644 --- a/modules/ImportUtilities.js +++ b/modules/ImportUtilities.js @@ -4,6 +4,7 @@ const Encryption = require('./Encryption'); const bytes = require('utf8-length'); const utilities = require('./Utilities'); const uuidv4 = require('uuid/v4'); +const { sha3_256 } = require('js-sha3'); /** * Import related utilities @@ -76,6 +77,53 @@ class ImportUtilities { } } + /** + * Normalizes import (use just necessary data) + * @param vertices Import vertices + * @param edges Import edges + * @returns {{edges: *, vertices: *}} + */ + static normalizeImport(vertices, edges) { + ImportUtilities.sort(edges); + ImportUtilities.sort(vertices); + + let normEdges = null; + if (edges) { + normEdges = edges.map(e => utilities.sortObject({ + _key: e._key, + identifiers: e.identifiers, + _from: e._from, + _to: e._to, + edge_type: e.edge_type, + })); + } + + let normVertices = null; + if (vertices) { + normVertices = vertices.map(v => utilities.sortObject({ + _key: v._key, + identifiers: v.identifiers, + data: v.data, + })); + } + + return { + edges: normEdges, + vertices: normVertices, + }; + } + + /** + * Calculate import hash + * @param vertices Import vertices + * @param edges Import edges + * @returns {*} + */ + static importHash(vertices, edges) { + const normalized = ImportUtilities.normalizeImport(vertices, edges); + return utilities.normalizeHex(sha3_256(utilities.stringify(normalized, 0))); + } + /** * Creates Merkle tree from import data * @param vertices Import vertices @@ -91,7 +139,7 @@ class ImportUtilities { // process vertices for (const i in vertices) { - const hash = utilities.sha3(utilities.sortObject({ + const hash = utilities.soliditySHA3(utilities.sortObject({ identifiers: vertices[i].identifiers, data: vertices[i].data, })); @@ -103,7 +151,7 @@ class ImportUtilities { } for (const edge of edges) { - const hash = utilities.sha3(utilities.sortObject({ + const hash = utilities.soliditySHA3(utilities.sortObject({ identifiers: edge.identifiers, _from: edge._from, _to: edge._to, diff --git a/modules/Network.js b/modules/Network.js index b07ae60f33..ba432f829d 100644 --- a/modules/Network.js +++ b/modules/Network.js @@ -14,6 +14,8 @@ const PeerCache = require('./kademlia/PeerCache'); const KadenceUtils = require('@kadenceproject/kadence/lib/utils.js'); const ip = require('ip'); +const { NetworkRequestIgnoredError } = require('./errors'); + /** * DHT module (Kademlia) */ @@ -87,9 +89,19 @@ class Network { parseInt(config.child_derivation_index, 10), ); + const onionEnabled = parseInt(config.onion_enabled, 10); + const natTraversalEnabled = parseInt(config.traverse_nat_enabled, 10); + + let kadServerHost = null; + if (config.local_network_only || natTraversalEnabled || onionEnabled) { + kadServerHost = '127.0.0.1'; + } else { + kadServerHost = await utilities.getExternalIp(); + } + // Initialize public contact data const contact = { - hostname: config.node_rpc_ip, + hostname: kadServerHost, protocol: 'https:', port: parseInt(config.node_port, 10), xpub: parentKey.publicExtendedKey, @@ -115,20 +127,13 @@ class Network { storage: levelup(encoding(leveldown(`${__dirname}/../data/kadence.dht`))), }); + const { validateContact } = this; + // Override node's _updateContact method to filter contacts. this.node._updateContact = (identity, contact) => { try { - if (ip.isV4Format(contact.hostname) || ip.isV6Format(contact.hostname)) { - if (config.local_network_only && ip.isPublic(contact.hostname)) { - this.log.debug(`Ignored contact ${identity} from remote address: ${contact.hostname}.`); - return; - } else if (!config.local_network_only && ip.isPrivate(contact.hostname)) { - this.log.debug(`Ignored contact ${identity} from local address: ${contact.hostname}.`); - return; - } - } - if (!contact.network_id || contact.network_id !== config.network_id) { - this.log.debug(`Ignored contact ${identity}. Invalid network ID.`); + if (!validateContact(contact)) { + this.log.debug(`Ignored contact ${identity}. Hostname ${contact.hostname}. Network ID ${contact.network_id}.`); return; } } catch (err) { @@ -141,6 +146,13 @@ class Network { ._updateContact.call(this.node, identity, contact); }; + this.node.use((request, response, next) => { + if (!validateContact(request.contact[1])) { + return next(new NetworkRequestIgnoredError('Contact not valid.', request)); + } + next(); + }); + this.log.info('Starting OT Node...'); this.node.eclipse = this.node.plugin(kadence.eclipse()); this.node.quasar = this.node.plugin(kadence.quasar()); @@ -154,11 +166,11 @@ class Network { )); this.log.info('Spartacus initialized'); - if (parseInt(config.onion_enabled, 10)) { + if (onionEnabled) { this.enableOnion(); } - if (parseInt(config.traverse_nat_enabled, 10)) { + if (natTraversalEnabled) { this.enableNatTraversal(); } @@ -627,6 +639,12 @@ class Network { }); // Define a global custom error handler rule this.node.use((err, request, response, next) => { + if (err instanceof NetworkRequestIgnoredError.constructor) { + this.log.debug(`Network request ignored. Contact ${JSON.stringify(request.contact)}`); + response.send([]); + return; + } + this.log.warn(`KADemlia error. ${err}. Request: ${request}.`); response.send({ error: err.message }); }); @@ -635,6 +653,29 @@ class Network { kademlia() { return this.node; } + + /** + * Validates contact. + * + * Checks if contact is in the network by checking network ID and if contact has IP + * check if it's in the local or remote network based on current configuration. + * @param contact Contact to check + * @returns {boolean} true if contact is in the same network. + */ + validateContact(contact) { + if (ip.isV4Format(contact.hostname) || ip.isV6Format(contact.hostname)) { + if (config.local_network_only && ip.isPublic(contact.hostname)) { + return false; + } else if (!config.local_network_only && ip.isPrivate(contact.hostname)) { + return false; + } + } + if (!contact.network_id || contact.network_id !== config.network_id) { + return false; + } + + return true; + } } module.exports = Network; diff --git a/modules/Utilities.js b/modules/Utilities.js index 5b43937828..bab532df87 100644 --- a/modules/Utilities.js +++ b/modules/Utilities.js @@ -17,6 +17,8 @@ const levenshtein = require('js-levenshtein'); const BN = require('bn.js'); const KademliaUtils = require('./kademlia/KademliaUtils'); const numberToBN = require('number-to-bn'); +const externalip = require('externalip'); +const sortedStringify = require('sorted-json-stringify'); const pjson = require('../package.json'); @@ -380,7 +382,7 @@ class Utilities { * @param data * @returns {string} */ - static sha3(data) { + static soliditySHA3(data) { return soliditySha3(data); } @@ -825,9 +827,9 @@ class Utilities { static getImportDistance(price, importId, stakeAmount) { const wallet = new BN(config.wallet); const nodeId = new BN(`0x${config.node_kademlia_id}`); - const hashWallerNodeId = new BN(Utilities.sha3(wallet + nodeId)); + const hashWallerNodeId = new BN(Utilities.soliditySHA3(wallet + nodeId)); const myBid = hashWallerNodeId.add(price); - const offer = new BN(Utilities.sha3(importId)).add(stakeAmount); + const offer = new BN(Utilities.soliditySHA3(importId)).add(stakeAmount); return Math.abs(myBid.sub(offer)); } @@ -952,6 +954,20 @@ class Utilities { return parseInt(config.is_bootstrap_node, 10); } + /** + * Enable auth token? + */ + static authTokenEnabled() { + return parseInt(config.enable_auth_token, 10); + } + + /** + * Gets Houston password (Auth token) + */ + static getHoustonPassword() { + return config.houston_password; + } + /** * Shuffles array in place * @param {Array} a items An array containing the items. @@ -963,6 +979,58 @@ class Utilities { } return a; } + + /** + * Get external IP + * @returns {Promise} + */ + static getExternalIp() { + return new Promise((resolve, reject) => { + externalip((err, ip) => { + if (err) { + reject(err); + } + resolve(ip); + }); + }); + } + + /** + * Read file contents + * @param file + * @returns {Promise} + */ + static fileContents(file) { + return new Promise((resolve, reject) => { + fs.readFile(file, 'utf8', (err, content) => { + if (err) { + reject(err); + } else { + resolve(content); + } + }); + }); + } + + /** + * Stringifies data to JSON with default parameters + * @param data Data to be stringified + * @param ident JSON identification + * @returns {*} + */ + static stringify(data, ident = 2) { + return sortedStringify(data, null, ident); + } + + /** + * Checks if hash is zero or any given hex string regardless of prefix 0x + * @param {string} hash + */ + static isZeroHash(hash) { + const num = new BN(this.denormalizeHex(hash)); + + return num.eqn(0); + } } module.exports = Utilities; diff --git a/modules/WOTImporter.js b/modules/WOTImporter.js index 77e1478756..6e544024c7 100644 --- a/modules/WOTImporter.js +++ b/modules/WOTImporter.js @@ -22,21 +22,13 @@ class WOTImporter { /** * Parse WOT model - * @param payloadFile WOT description + * @param payload WOT contents * @return {Promise} */ - async parse(payloadFile) { - let payload; - try { - payload = JSON.parse(fs.readFileSync(payloadFile, 'utf8')); - } catch (err) { - const error = new Error('Invalid JSON file'); - error.status = 400; - throw error; - } - + async parse(payload) { + const parsed = JSON.parse(payload); const importId = Utilities.createImportId(); - const { things, sender } = payload.data; + const { things, sender } = parsed.data; const edges = []; const vertices = []; diff --git a/modules/command/command-executor.js b/modules/command/command-executor.js index 9b62b549d5..b067993cda 100644 --- a/modules/command/command-executor.js +++ b/modules/command/command-executor.js @@ -19,7 +19,7 @@ const STATUS = { * How many commands will run in parallel * @type {number} */ -const QUEUE_PARALLELISM = 4; +const QUEUE_PARALLELISM = 1; /** * Queues and processes commands @@ -126,7 +126,6 @@ class CommandExecutor { } } catch (e) { this.logger.error(`Failed to process command ${command.name} and ID ${command.id}. ${e}.\n${e.stack}`); - this.notifyError(e); try { const result = await this._handleError(command, handler, e); if (result && result.commands) { @@ -134,7 +133,7 @@ class CommandExecutor { } } catch (e) { this.logger.warn(`Failed to handle error callback for command ${command.name} and ID ${command.id}`); - this.notifyError(e); + this.notifyError(e, { data: command.data }); } } } diff --git a/modules/command/dc/dc-offer-key-verification-command.js b/modules/command/dc/dc-offer-key-verification-command.js index 920414fdb0..94160c56c4 100644 --- a/modules/command/dc/dc-offer-key-verification-command.js +++ b/modules/command/dc/dc-offer-key-verification-command.js @@ -17,6 +17,7 @@ class DCOfferKeyVerificationCommand extends Command { this.network = ctx.network; this.blockchain = ctx.blockchain; this.graphStorage = ctx.graphStorage; + this.notifyEvent = ctx.notifyEvent; } /** @@ -62,11 +63,38 @@ class DCOfferKeyVerificationCommand extends Command { if (escrow.distribution_root_hash !== Utilities.normalizeHex(distributionHash)) { this.logger.warn(`Distribution hash for import ${importId} and DH ${dhWallet} is incorrect`); failed = true; + + this.notifyEvent( + 'Distribution hash is incorrect', + { + dhNodeId, + importId, + dhWallet, + encryptionKey, + distributionHash, + litigationRootHash, + vertices, + edges, + }, + ); } if (escrow.litigation_root_hash !== Utilities.normalizeHex(litigationRootHash)) { this.logger.warn(`Litigation hash for import ${importId} and DH ${dhWallet} is incorrect`); failed = true; + this.notifyEvent( + 'Litigation hash is incorrect', + { + dhNodeId, + importId, + dhWallet, + encryptionKey, + distributionHash, + litigationRootHash, + vertices, + edges, + }, + ); } if (!escrow.checksum === epkChecksum) { @@ -79,6 +107,19 @@ class DCOfferKeyVerificationCommand extends Command { if (!ImportUtilities.compareDocuments(decryptedVertices, originalVertices)) { this.logger.warn(`Decryption key for import ${importId} and DH ${dhWallet} is incorrect`); failed = true; + this.notifyEvent( + 'Decryption key is incorrect', + { + dhNodeId, + importId, + dhWallet, + encryptionKey, + distributionHash, + litigationRootHash, + vertices, + edges, + }, + ); } if (failed) { diff --git a/modules/command/dc/dc-offer-root-hash-command.js b/modules/command/dc/dc-offer-root-hash-command.js index 1f5b322fb0..6f9684c9e7 100644 --- a/modules/command/dc/dc-offer-root-hash-command.js +++ b/modules/command/dc/dc-offer-root-hash-command.js @@ -19,30 +19,52 @@ class DCOfferRootHashCommand extends Command { offerId, importId, rootHash, + importHash, } = command.data; - const offer = await Models.offers.findOne({ where: { id: offerId } }); - - const blockchainRootHash = await this.blockchain.getRootHash( + const result = await this.blockchain.getRootHash( this.config.node_wallet, importId, ); + const blockchainRootHash = result.graph_hash; + const { data } = command; if (blockchainRootHash.toString() === '0x0000000000000000000000000000000000000000000000000000000000000000') { this.remoteControl.writingRootHash(importId); try { - await this.blockchain.writeRootHash(importId, rootHash); + const result = await this.blockchain.writeRootHash(importId, rootHash, importHash); + const dataInfo = await Models.data_info.findOne({ + where: { import_id: data.importId }, + }); + dataInfo.transaction_hash = result.transactionHash; + await dataInfo.save({ fields: ['transaction_hash'] }); this.logger.info('Fingerprint written on blockchain'); } catch (err) { - offer.status = 'FAILED'; - await offer.save({ fields: ['status'] }); - this.notifyError(err); + await this._notify(err, offerId); throw Error(`Failed to write fingerprint on blockchain. ${err}`); } } else if (blockchainRootHash !== rootHash) { throw Error(`Calculated root hash (${rootHash}) differs from one on blockchain (${blockchainRootHash}).`); } - return this.continueSequence(command.data, command.sequence); + return this.continueSequence(data, command.sequence); + } + + /** + * Notify about the error + * @param offerId + * @param err + * @returns {Promise} + * @private + */ + async _notify(err, offerId) { + if (offerId) { + const offer = await Models.offers.findOne({ where: { id: offerId } }); + if (offer) { + offer.status = 'FAILED'; + await offer.save({ fields: ['status'] }); + } + } + this.notifyError(err); } /** diff --git a/modules/command/dh/dh-offer-bid-add-command.js b/modules/command/dh/dh-offer-bid-add-command.js index 8fbfa031cc..a304d1ea90 100644 --- a/modules/command/dh/dh-offer-bid-add-command.js +++ b/modules/command/dh/dh-offer-bid-add-command.js @@ -62,8 +62,26 @@ class DHOfferBidAddCommand extends Command { * @param command * @param err */ - recover(command, err) { - this.logger.info('Bid not added, your bid was probably too late and the offer has been closed'); + async recover(command, err) { + this.logger.warn('Trying to recover from dhOfferBidAddCommand.'); + + if (err.toString().includes('Transaction has been reverted by the EVM')) { + const { + importId, + } = command.data; + + // Check if we're too late for bid. + const offer = await this.blockchain.getOffer(importId); + + if (offer[0] !== '0x0000000000000000000000000000000000000000') { + if (!offer.active || offer.finalized) { + this.logger.warn(`Offer for ${importId} was already finalized or not active. Failed to add bid.`); + return; + } + } + } + + throw err; } /** diff --git a/modules/command/dh/dh-offer-handle-import-command.js b/modules/command/dh/dh-offer-handle-import-command.js index 6530d088df..40ab311a84 100644 --- a/modules/command/dh/dh-offer-handle-import-command.js +++ b/modules/command/dh/dh-offer-handle-import-command.js @@ -55,6 +55,7 @@ class DHOfferHandleImportCommand extends Command { import_id: importResult.import_id, total_documents: importResult.vertices.length, root_hash: importResult.root_hash, + import_hash: importResult.import_hash, data_provider_wallet: importResult.wallet, import_timestamp: new Date(), data_size: dataSize, diff --git a/modules/controller/dc-controller.js b/modules/controller/dc-controller.js index 1d5d0e32f0..76cb2881a5 100644 --- a/modules/controller/dc-controller.js +++ b/modules/controller/dc-controller.js @@ -9,6 +9,23 @@ class DCController { this.commandExecutor = ctx.commandExecutor; } + /** + * Creates offer + * @returns {Promise<*>} + */ + async writeRootHash(importId, rootHash, importHash) { + await this.commandExecutor.add({ + name: 'dcOfferRootHashCommand', + delay: 0, + data: { + importId, + rootHash, + importHash, + }, + transactional: false, + }); + } + /** * Creates offer * @param importId - Import ID diff --git a/modules/errors/index.js b/modules/errors/index.js new file mode 100644 index 0000000000..404bd9203d --- /dev/null +++ b/modules/errors/index.js @@ -0,0 +1,2 @@ + +module.exports.NetworkRequestIgnoredError = require('./network-request-ignored-error'); diff --git a/modules/errors/network-request-ignored-error.js b/modules/errors/network-request-ignored-error.js new file mode 100644 index 0000000000..2a681ad4fd --- /dev/null +++ b/modules/errors/network-request-ignored-error.js @@ -0,0 +1,16 @@ +/** + * Represent one ignored network request. + */ +class NetworkRequestIgnoredError extends Error { + constructor(message, request) { + super(message); + + // Ensure the name of this error is the same as the class name + this.name = this.constructor.name; + + this.request = request; + + // This clips the constructor invocation from the stack trace. + Error.captureStackTrace(this, this.constructor); + } +} diff --git a/modules/importer.js b/modules/importer.js index 7e9ed25c0c..54e61e2533 100644 --- a/modules/importer.js +++ b/modules/importer.js @@ -144,14 +144,18 @@ class Importer { edges = Graph.sortVertices(edges); vertices = Graph.sortVertices(vertices); + const importHash = ImportUtilities.importHash(vertices, edges); + const merkle = await ImportUtilities.merkleStructure(vertices.filter(vertex => vertex.vertex_type !== 'CLASS'), edges); this.log.info(`Import id: ${import_id}`); - this.log.info(`Import hash: ${merkle.tree.getRoot()}`); + this.log.info(`Root hash: ${merkle.tree.getRoot()}`); + this.log.info(`Import hash: ${importHash}`); return { import_id, root_hash: merkle.tree.getRoot(), + import_hash: importHash, total_documents: merkle.hashPairs.length, vertices, edges, diff --git a/ot-node.js b/ot-node.js index 4cc7c96fc3..10d5d7c5b7 100644 --- a/ot-node.js +++ b/ot-node.js @@ -37,6 +37,8 @@ const Web3 = require('web3'); global.__basedir = __dirname; +let context; + process.on('unhandledRejection', (reason, p) => { if (reason.message.startsWith('Invalid JSON RPC response')) { return; @@ -58,6 +60,7 @@ process.on('unhandledRejection', (reason, p) => { identity: config.node_kademlia_id, config: cleanConfig, }, + severity: 'error', }, ); } @@ -84,6 +87,7 @@ process.on('uncaughtException', (err) => { identity: config.node_kademlia_id, config: cleanConfig, }, + severity: 'error', }, ); }); @@ -102,7 +106,7 @@ process.on('exit', (code) => { } }); -function notifyBugsnag(error, subsystem) { +function notifyBugsnag(error, metadata, subsystem) { if (process.env.NODE_ENV !== 'development') { const cleanConfig = Object.assign({}, config); delete cleanConfig.node_private_key; @@ -124,10 +128,45 @@ function notifyBugsnag(error, subsystem) { }; } + if (metadata) { + Object.assign(options, metadata); + } + bugsnag.notify(error, options); } } +function notifyEvent(message, metadata, subsystem) { + if (process.env.NODE_ENV !== 'development') { + const cleanConfig = Object.assign({}, config); + delete cleanConfig.node_private_key; + delete cleanConfig.houston_password; + delete cleanConfig.database; + delete cleanConfig.blockchain; + + const options = { + user: { + id: config.node_wallet, + identity: config.node_kademlia_id, + config: cleanConfig, + }, + severity: 'info', + }; + + if (subsystem) { + options.subsystem = { + name: subsystem, + }; + } + + if (metadata) { + Object.assign(options, metadata); + } + + bugsnag.notify(message, options); + } +} + /** * Main node object */ @@ -189,6 +228,7 @@ class OTNode { warn: log.warn, error: log.error, }, + logLevel: 'error', }, ); } @@ -302,6 +342,8 @@ class OTNode { injectionMode: awilix.InjectionMode.PROXY, }); + context = container.cradle; + container.loadModules(['modules/command/**/*.js', 'modules/controller/**/*.js'], { formatName: 'camelCase', resolverOptions: { @@ -332,6 +374,7 @@ class OTNode { logger: awilix.asValue(log), networkUtilities: awilix.asClass(NetworkUtilities).singleton(), notifyError: awilix.asFunction(() => notifyBugsnag).transient(), + notifyEvent: awilix.asFunction(() => notifyEvent).transient(), }); const emitter = container.resolve('emitter'); const dhService = container.resolve('dhService'); @@ -497,11 +540,12 @@ class OTNode { * Start RPC server */ startRPC(emitter) { - const server = restify.createServer({ + const options = { name: 'RPC server', version: pjson.version, formatters: { 'application/json': (req, res, body) => { + res.set('content-type', 'application/json; charset=utf-8'); if (!body) { if (res.getHeader('Content-Length') === undefined && res.contentLength === undefined) { res.setHeader('Content-Length', 0); @@ -525,14 +569,31 @@ class OTNode { body = body.toString('base64'); } - const data = JSON.stringify(body, null, 2); + let ident = 2; + if ('prettify-json' in req.headers) { + if (req.headers['prettify-json'] === 'false') { + ident = 0; + } + } + const data = Utilities.stringify(body, ident); + if (res.getHeader('Content-Length') === undefined && res.contentLength === undefined) { res.setHeader('Content-Length', Buffer.byteLength(data)); } return data; }, }, - }); + }; + + if (config.node_rpc_use_ssl !== '0') { + Object.assign(options, { + key: fs.readFileSync(config.node_rpc_ssl_key_path), + certificate: fs.readFileSync(config.node_rpc_ssl_cert_path), + rejectUnauthorized: true, + }); + } + + const server = restify.createServer(options); server.use(restify.plugins.acceptParser(server.acceptable)); server.use(restify.plugins.queryParser()); @@ -540,12 +601,37 @@ class OTNode { const cors = corsMiddleware({ preflightMaxAge: 5, // Optional origins: ['*'], - allowHeaders: ['API-Token'], + allowHeaders: ['API-Token', 'prettify-json', 'raw-data'], exposeHeaders: ['API-Token-Expiry'], }); server.pre(cors.preflight); server.use(cors.actual); + server.use((request, response, next) => { + if (Utilities.authTokenEnabled()) { + const token = request.query.auth_token; + + const deny = (message) => { + log.trace(message); + response.status(401); + response.send({ + message, + }); + }; + + if (!token) { + const msg = 'Failed to authorize. Auth token is missing'; + deny(msg); + return; + } + if (token !== Utilities.getHoustonPassword()) { + const msg = `Failed to authorize. Auth token ${token} is invalid`; + deny(msg); + return; + } + } + return next(); + }); // TODO: Temp solution to listen all adapters in local net. let serverListenAddress = config.node_rpc_ip; @@ -576,7 +662,7 @@ class OTNode { return true; } - if (!remote_access.includes(request_ip)) { + if (remote_access.length > 0 && !remote_access.includes(request_ip)) { res.status(403); res.send({ message: 'Unauthorized request', @@ -593,7 +679,7 @@ class OTNode { * @param importfile - file or text data * @param importtype - (GS1/WOT) */ - server.post('/api/import', (req, res) => { + server.post('/api/import', async (req, res) => { log.api('POST: Import of data request received.'); if (!authorize(req, res)) { @@ -625,33 +711,30 @@ class OTNode { // Check if file is provided if (req.files !== undefined && req.files.importfile !== undefined) { const inputFile = req.files.importfile.path; - const queryObject = { - filepath: inputFile, - contact: req.contact, - replicate: req.body.replicate, - response: res, - }; - - emitter.emit(`api-${importtype}-import-request`, queryObject); - } else if (req.body.importfile !== undefined) { - // Check if import data is provided in request body - const fileData = req.body.importfile; - fs.writeFile('tmp/import.xml', fileData, (err) => { - if (err) { - return console.log(err); - } - console.log('The file was saved!'); - - const inputFile = '/tmp/import.tmp'; + try { + const content = await Utilities.fileContents(inputFile); const queryObject = { - filepath: inputFile, + content, contact: req.contact, replicate: req.body.replicate, response: res, }; - emitter.emit(`api-${importtype}-import-request`, queryObject); - }); + } catch (e) { + res.status(400); + res.send({ + message: 'No import data provided', + }); + } + } else if (req.body.importfile !== undefined) { + // Check if import data is provided in request body + const queryObject = { + content: req.body.importfile, + contact: req.contact, + replicate: req.body.replicate, + response: res, + }; + emitter.emit(`api-${importtype}-import-request`, queryObject); } else { // No import data provided res.status(400); @@ -691,6 +774,23 @@ class OTNode { } }); + server.get('/api/dump/rt', (req, res) => { + log.api('Dumping routing table'); + const message = {}; + context.network.kademlia().router.forEach((value, key, map) => { + if (value.length > 0) { + value.forEach((bValue, bKey, bMap) => { + message[bKey] = bValue; + }); + } + }); + + res.status(200); + res.send({ + message, + }); + }); + server.get('/api/replication/:replication_id', (req, res) => { log.api('GET: Replication status request received'); @@ -827,6 +927,7 @@ class OTNode { emitter.emit('api-query-local-import', { import_id: req.params.import_id, + request: req, response: res, }); }); @@ -900,6 +1001,29 @@ class OTNode { res.send({ message: 'Bad request' }); } }); + + server.get('/api/import_info', (req, res) => { + log.api('GET: import_info.'); + const queryObject = req.query; + + if (queryObject.import_id === undefined) { + res.send({ status: 400, message: 'Missing parameter!', data: [] }); + return; + } + + emitter.emit('api-import-info', { + importId: queryObject.import_id, + response: res, + }); + }); + + server.get('/api/imports_info', (req, res) => { + log.api('GET: List imports request received.'); + + emitter.emit('api-imports-info', { + response: res, + }); + }); } } diff --git a/package-lock.json b/package-lock.json index 280524d108..6737892940 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "origintrail-node", - "version": "1.3.10", + "version": "1.3.24", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -172,9 +172,9 @@ "integrity": "sha512-0OdKaIq5rsQaO/U/24h0G2w+btpXxf8HUwTRO8xlCtpoL8E5LL+ViRV1pGgFnB0XTnADr/E6/boi1YbqicjnAA==" }, "@kadenceproject/kadence": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@kadenceproject/kadence/-/kadence-4.1.0.tgz", - "integrity": "sha512-HEy7b00XXj1BUSjhPD0iqzuFEpvU7A5A2sjOqNhuBcnvR/R3VJ/5zkWwyy1s7DRPYAFadlPPWmG/4skQfW+PiA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@kadenceproject/kadence/-/kadence-4.1.3.tgz", + "integrity": "sha512-OuYMKEMdGQ8m9NEf75SiomtWd6JHibnY8EB5grPrqgP86hF102dy/qGqVZUK8ZhBnZy5QeU+7YKHRrWwYnTkRQ==", "requires": { "async": "2.6.0", "atbf": "1.1.0", @@ -197,7 +197,7 @@ "levelup": "2.0.1", "lru-cache": "4.1.1", "merge": "1.2.0", - "metapipe": "2.0.1", + "metapipe": "2.0.2", "mkdirp": "0.5.1", "ms": "2.1.1", "nat-pmp": "git+https://gitlab.com/kadence/node-nat-pmp.git#ffeda3dee8fd7103f368b4d2448ed0a861f662a5", @@ -1938,6 +1938,13 @@ "integrity": "sha1-P/NKMAbvFcD7NWflQbkaI0ASPRE=", "requires": { "js-sha3": "0.3.1" + }, + "dependencies": { + "js-sha3": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.3.1.tgz", + "integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM=" + } } }, "browserify-sign": { @@ -3920,6 +3927,13 @@ "utf8": "2.1.2", "xhr2": "0.1.4", "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" + } } } } @@ -4194,6 +4208,11 @@ "secp256k1": "3.5.0" } }, + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" + }, "uuid": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", @@ -5546,7 +5565,7 @@ "solc": "0.4.24", "temp": "0.8.3", "tmp": "0.0.31", - "web3": "1.0.0-beta.34", + "web3": "1.0.0-beta.35", "web3-provider-engine": "14.0.6", "websocket": "1.0.26", "yargs": "7.1.0" @@ -5996,6 +6015,11 @@ "requires": { "debug": "2.6.9" } + }, + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" } } }, @@ -10592,15 +10616,15 @@ "resolved": "https://registry.npmjs.org/hsv3/-/hsv3-1.1.4.tgz", "integrity": "sha512-OL+3yfn+SAwYuWEy5vzy8GL7As10/4qGU4Q5JIEryU5QBl1jvtcRHB1Hap5P0logNfzY4E6VjIYGmmTt2s/EUw==", "requires": { - "commander": "2.16.0", + "commander": "2.17.1", "granax": "3.1.3", "mkdirp": "0.5.1" }, "dependencies": { "commander": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", - "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==" + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" } } }, @@ -11201,9 +11225,9 @@ } }, "js-sha3": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.3.1.tgz", - "integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM=" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" }, "js-tokens": { "version": "3.0.2", @@ -11482,13 +11506,13 @@ "async": "2.6.1", "cheerio": "1.0.0-rc.2", "follow-redirects": "1.5.0", - "semver": "5.5.0" + "semver": "5.5.1" }, "dependencies": { "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" } } }, @@ -12203,9 +12227,9 @@ } }, "metapipe": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/metapipe/-/metapipe-2.0.1.tgz", - "integrity": "sha1-0F2GodGJIuSL6/eoxHZkMR4ZiuA=" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/metapipe/-/metapipe-2.0.2.tgz", + "integrity": "sha512-BLQ+3J2OTMXWFLyoav/sl1sPIpDt3EaJSDpov1gitKoYl8uWfkXPOUplYJip/DWIaKd45LdsOuOR0k1jjDaacg==" }, "methods": { "version": "1.0.1", @@ -12425,9 +12449,9 @@ } }, "mock-fs": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.5.0.tgz", - "integrity": "sha512-qqudNfOX7ZmX9vm1WIAU+gWlmxVNAnwY6UG3RkFutNywmRCUGP83tujP6IxX2DS1TmcaEZBOhYwDuYEmJYE+3w==" + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.6.0.tgz", + "integrity": "sha512-aYutNIwFaMsVgtMoc5vMsobA/yRJR2FTUFoTZgnjdb3gID0g8WMmeafWmHPgzKgZ7zwQ5kggYUgeq5sN9k9uDw==" }, "moment": { "version": "2.22.2", @@ -20453,10 +20477,22 @@ "crypto-js": "3.1.8", "utf8": "2.1.2", "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" + } } } } }, + "sorted-json-stringify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/sorted-json-stringify/-/sorted-json-stringify-0.1.1.tgz", + "integrity": "sha512-RBjgNf6RFfJDHuvp0J/GBlxVkyRmXMpQgWKq1VNx5uMSoeceI+YwSoQaFyZucWKGzVqKeK8RWFY7D7gDjyxopQ==" + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -21016,7 +21052,7 @@ "integrity": "sha512-G8gi5fcXP/2upwiuOShJ258sIufBVztekgobr3cVgYXObZwJ5AXLqZn52AI+/ffft29pJexF9WNdUxjlkVehoQ==", "requires": { "bluebird": "3.5.1", - "buffer": "5.1.0", + "buffer": "5.2.0", "decompress": "4.2.0", "eth-lib": "0.1.27", "fs-extra": "2.1.2", @@ -21024,7 +21060,7 @@ "got": "7.1.0", "mime-types": "2.1.18", "mkdirp-promise": "5.0.1", - "mock-fs": "4.5.0", + "mock-fs": "4.6.0", "setimmediate": "1.0.5", "tar.gz": "1.0.7", "xhr-request-promise": "0.1.2" @@ -21036,9 +21072,9 @@ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" }, "buffer": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz", - "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.0.tgz", + "integrity": "sha512-nUJyfChH7PMJy75eRDCCKtszSEFokUNXC1hNVSe+o+VdcgvDPLs20k3v8UXI8ruRYAJiYtyRea8mYyqPxoHWDw==", "requires": { "base64-js": "1.3.0", "ieee754": "1.1.12" @@ -21513,6 +21549,13 @@ "utf8": "2.1.2", "xhr2": "0.1.4", "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" + } } } } @@ -21572,7 +21615,6 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, "requires": { "is-typedarray": "1.0.0" } @@ -21805,9 +21847,9 @@ "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=" }, "utf8": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", - "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" }, "utf8-length": { "version": "0.0.1", @@ -21903,23 +21945,23 @@ } }, "web3": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.0.0-beta.34.tgz", - "integrity": "sha1-NH5WG3hAmMtVYzFfSQR5odkfKrE=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.0.0-beta.35.tgz", + "integrity": "sha512-xwDmUhvTcHQvvNnOPcPZZgCxKUsI2e+GbHy7JkTK3/Rmnutazy8x7fsAXT9myw7V1qpi3GgLoZ3fkglSUbg1Mg==", "requires": { - "web3-bzz": "1.0.0-beta.34", - "web3-core": "1.0.0-beta.34", - "web3-eth": "1.0.0-beta.34", - "web3-eth-personal": "1.0.0-beta.34", - "web3-net": "1.0.0-beta.34", - "web3-shh": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-bzz": "1.0.0-beta.35", + "web3-core": "1.0.0-beta.35", + "web3-eth": "1.0.0-beta.35", + "web3-eth-personal": "1.0.0-beta.35", + "web3-net": "1.0.0-beta.35", + "web3-shh": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" } }, "web3-bzz": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.0.0-beta.34.tgz", - "integrity": "sha1-Bo03d3q2Xlxg+OyLmlDP5FJ3kpw=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.0.0-beta.35.tgz", + "integrity": "sha512-BhAU0qhlr8zltm4gs/+P1gki2VkxHJaM2Rrh4DGesDW0lzwufRoNvWFlwx1bKHoFPWNbSmm9PRkHOYOINL/Tgw==", "requires": { "got": "7.1.0", "swarm-js": "0.1.37", @@ -21934,24 +21976,24 @@ } }, "web3-core": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.0.0-beta.34.tgz", - "integrity": "sha1-EhvoVV6fsA0sXQXd0zgdDJ5GmH4=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.0.0-beta.35.tgz", + "integrity": "sha512-ayGavbgVk4KL9Y88Uv411fBJ0SVgVfKhKEBweKYzmP0zOqneMzWt6YsyD1n6kRvjAbqA0AfUPEOKyMNjcx2tjw==", "requires": { - "web3-core-helpers": "1.0.0-beta.34", - "web3-core-method": "1.0.0-beta.34", - "web3-core-requestmanager": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-core-helpers": "1.0.0-beta.35", + "web3-core-method": "1.0.0-beta.35", + "web3-core-requestmanager": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" } }, "web3-core-helpers": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.34.tgz", - "integrity": "sha1-sWjaANPhnhVrwVriAyA91N/uLQM=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.35.tgz", + "integrity": "sha512-APOu3sEsamyqWt//8o4yq9KF25/uqGm+pQShson/sC4gKzmfJB07fLo2ond0X30E8fIqAPeVCotPXQxGciGUmA==", "requires": { "underscore": "1.8.3", - "web3-eth-iban": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-eth-iban": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" }, "dependencies": { "underscore": { @@ -21962,15 +22004,15 @@ } }, "web3-core-method": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.0.0-beta.34.tgz", - "integrity": "sha1-7BY8iixJD6AqfsFVWfpzB/x8xt0=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.0.0-beta.35.tgz", + "integrity": "sha512-jidImCide8q0GpfsO4L73qoHrbkeWgwU3uOH5DKtJtv0ccmG086knNMRgryb/o9ZgetDWLmDEsJnHjBSoIwcbA==", "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.34", - "web3-core-promievent": "1.0.0-beta.34", - "web3-core-subscriptions": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-core-helpers": "1.0.0-beta.35", + "web3-core-promievent": "1.0.0-beta.35", + "web3-core-subscriptions": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" }, "dependencies": { "underscore": { @@ -21981,24 +22023,24 @@ } }, "web3-core-promievent": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.34.tgz", - "integrity": "sha1-pPT6Z4S7KT6CxglgrltWqUzQPtw=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.35.tgz", + "integrity": "sha512-GvqXqKq07OmHuVi5uNRg6k79a1/CI0ViCC+EtNv4CORHtDRmYEt5Bvdv6z6FJEiaaQkD0lKbFwNhLxutx7HItw==", "requires": { "any-promise": "1.3.0", "eventemitter3": "1.1.1" } }, "web3-core-requestmanager": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.34.tgz", - "integrity": "sha1-Afj2zyrmtvC3DDi64e90G1urIVw=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.35.tgz", + "integrity": "sha512-S+zW2h17ZZQU9oe3yaCJE0E7aJS4C3Kf4kGPDv+nXjW0gKhQQhgVhw1Doq/aYQGqNSWJp7f1VHkz5gQWwg6RRg==", "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.34", - "web3-providers-http": "1.0.0-beta.34", - "web3-providers-ipc": "1.0.0-beta.34", - "web3-providers-ws": "1.0.0-beta.34" + "web3-core-helpers": "1.0.0-beta.35", + "web3-providers-http": "1.0.0-beta.35", + "web3-providers-ipc": "1.0.0-beta.35", + "web3-providers-ws": "1.0.0-beta.35" }, "dependencies": { "underscore": { @@ -22009,13 +22051,13 @@ } }, "web3-core-subscriptions": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.34.tgz", - "integrity": "sha1-n+0UQDPyIcPPIQYDAv/a9e8t4t4=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.35.tgz", + "integrity": "sha512-gXzLrWvcGkGiWq1y33Z4Y80XI8XMrwowiQJkrPSjQ81K5PBKquOGwcMffLaKcwdmEy/NpsOXDeFo3eLE1Ghvvw==", "requires": { "eventemitter3": "1.1.1", "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.34" + "web3-core-helpers": "1.0.0-beta.35" }, "dependencies": { "underscore": { @@ -22026,22 +22068,22 @@ } }, "web3-eth": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.0.0-beta.34.tgz", - "integrity": "sha1-dAhgAIUMb+b1Ne9Jg31tS7YRMmg=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.0.0-beta.35.tgz", + "integrity": "sha512-04mcb2nGPXThawuuYICPOxv0xOHofvQKsjZeIq+89nyOC8DQMGTAErDkGyMHQYtjpth5XDhic0wuEsA80AmFZA==", "requires": { "underscore": "1.8.3", - "web3-core": "1.0.0-beta.34", - "web3-core-helpers": "1.0.0-beta.34", - "web3-core-method": "1.0.0-beta.34", - "web3-core-subscriptions": "1.0.0-beta.34", - "web3-eth-abi": "1.0.0-beta.34", - "web3-eth-accounts": "1.0.0-beta.34", - "web3-eth-contract": "1.0.0-beta.34", - "web3-eth-iban": "1.0.0-beta.34", - "web3-eth-personal": "1.0.0-beta.34", - "web3-net": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-core": "1.0.0-beta.35", + "web3-core-helpers": "1.0.0-beta.35", + "web3-core-method": "1.0.0-beta.35", + "web3-core-subscriptions": "1.0.0-beta.35", + "web3-eth-abi": "1.0.0-beta.35", + "web3-eth-accounts": "1.0.0-beta.35", + "web3-eth-contract": "1.0.0-beta.35", + "web3-eth-iban": "1.0.0-beta.35", + "web3-eth-personal": "1.0.0-beta.35", + "web3-net": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" }, "dependencies": { "underscore": { @@ -22052,14 +22094,14 @@ } }, "web3-eth-abi": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.34.tgz", - "integrity": "sha1-A0Uz46ovfln/MXk+rqaFwO1a9no=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.35.tgz", + "integrity": "sha512-KUDC+EtFFYG8z01ZleKrASdjj327/rtWHzEt6RWsEj7bBa0bGp9nEh+nqdZx/Sdgz1O8tnfFzJlrRcXpfr1vGg==", "requires": { "bn.js": "4.11.6", "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-core-helpers": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" }, "dependencies": { "bn.js": { @@ -22075,9 +22117,9 @@ } }, "web3-eth-accounts": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.34.tgz", - "integrity": "sha1-4JFC7uzHl6w0WbdemyOUbTaV8zM=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.35.tgz", + "integrity": "sha512-duIgRsfht/0kAW/eQ0X9lKtVIykbETrnM2H7EnvplCzPHtQLodpib4o9JXfh9n6ZDgdDC7cuJoiVB9QJg089ew==", "requires": { "any-promise": "1.3.0", "crypto-browserify": "3.12.0", @@ -22085,10 +22127,10 @@ "scrypt.js": "0.2.0", "underscore": "1.8.3", "uuid": "2.0.1", - "web3-core": "1.0.0-beta.34", - "web3-core-helpers": "1.0.0-beta.34", - "web3-core-method": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-core": "1.0.0-beta.35", + "web3-core-helpers": "1.0.0-beta.35", + "web3-core-method": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" }, "dependencies": { "eth-lib": { @@ -22114,18 +22156,18 @@ } }, "web3-eth-contract": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.34.tgz", - "integrity": "sha1-nbs4+udkOoCEJ6IBgEcOx0FckeY=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.35.tgz", + "integrity": "sha512-foPohOg5O1UCGKGZOIs+kQK5IZdV2QQ7pAWwNxH8WHplUA+fre1MurXNpoxknUmH6mYplFhXjqgYq2MsrBpHrA==", "requires": { "underscore": "1.8.3", - "web3-core": "1.0.0-beta.34", - "web3-core-helpers": "1.0.0-beta.34", - "web3-core-method": "1.0.0-beta.34", - "web3-core-promievent": "1.0.0-beta.34", - "web3-core-subscriptions": "1.0.0-beta.34", - "web3-eth-abi": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-core": "1.0.0-beta.35", + "web3-core-helpers": "1.0.0-beta.35", + "web3-core-method": "1.0.0-beta.35", + "web3-core-promievent": "1.0.0-beta.35", + "web3-core-subscriptions": "1.0.0-beta.35", + "web3-eth-abi": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" }, "dependencies": { "underscore": { @@ -22136,12 +22178,12 @@ } }, "web3-eth-iban": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.34.tgz", - "integrity": "sha1-mvRYYFhnzPdOqXmq8yazi6alugw=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.35.tgz", + "integrity": "sha512-H5wkcNcAIc+h/WoDIKv7ZYmrM2Xqu3O7jBQl1IWo73EDVQji+AoB2i3J8tuwI1yZRInRwrfpI3Zuwuf54hXHmQ==", "requires": { "bn.js": "4.11.6", - "web3-utils": "1.0.0-beta.34" + "web3-utils": "1.0.0-beta.35" }, "dependencies": { "bn.js": { @@ -22152,25 +22194,25 @@ } }, "web3-eth-personal": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.34.tgz", - "integrity": "sha1-mvuhZzQuveVCC81YlcP2w0OI8gU=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.35.tgz", + "integrity": "sha512-AcM9nnlxu7ZRRxPvkrFB9eLxMM4A2cPfj2aCg21Wb2EpMnhR+b/O1cT33k7ApRowoMpM+T9M8vx2oPNwXfaCOQ==", "requires": { - "web3-core": "1.0.0-beta.34", - "web3-core-helpers": "1.0.0-beta.34", - "web3-core-method": "1.0.0-beta.34", - "web3-net": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-core": "1.0.0-beta.35", + "web3-core-helpers": "1.0.0-beta.35", + "web3-core-method": "1.0.0-beta.35", + "web3-net": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" } }, "web3-net": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.0.0-beta.34.tgz", - "integrity": "sha1-QnzqL0MYgUScjjjVIykPFz+f9j0=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.0.0-beta.35.tgz", + "integrity": "sha512-bbwaQ/KohGjIJ6HAKbZ6KrklCAaG6/B7hIbAbVLSFLxF+Yz9lmAgQYaDInpidpC/NLb3WOmcbRF+P77J4qMVIA==", "requires": { - "web3-core": "1.0.0-beta.34", - "web3-core-method": "1.0.0-beta.34", - "web3-utils": "1.0.0-beta.34" + "web3-core": "1.0.0-beta.35", + "web3-core-method": "1.0.0-beta.35", + "web3-utils": "1.0.0-beta.35" } }, "web3-provider-engine": { @@ -22212,22 +22254,22 @@ } }, "web3-providers-http": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.0.0-beta.34.tgz", - "integrity": "sha1-5WG1K7tDdmKCAH1AKFv+NVDCfno=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.0.0-beta.35.tgz", + "integrity": "sha512-DcIMFq52Fb08UpWyZ3ZlES6NsNqJnco4hBS/Ej6eOcASfuUayPI+GLkYVZsnF3cBYqlH+DOKuArcKSuIxK7jIA==", "requires": { - "web3-core-helpers": "1.0.0-beta.34", - "xhr2": "0.1.4" + "web3-core-helpers": "1.0.0-beta.35", + "xhr2-cookies": "1.1.0" } }, "web3-providers-ipc": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.34.tgz", - "integrity": "sha1-obd/GjBtc2SanAOQUuQMtxMo0Ao=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.35.tgz", + "integrity": "sha512-iB0FG0HcpUnayfa8pn4guqEQ4Y1nrroi/jffdtQgFkrNt0sD3fMSwwC0AbmECqj3tDLl0e1slBR0RENll+ZF0g==", "requires": { "oboe": "2.1.3", "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.34" + "web3-core-helpers": "1.0.0-beta.35" }, "dependencies": { "underscore": { @@ -22238,12 +22280,12 @@ } }, "web3-providers-ws": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.34.tgz", - "integrity": "sha1-fecPG4Py3jZHZ3IVa+z+9uNRbrM=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.35.tgz", + "integrity": "sha512-Cx64NgDStynKaUGDIIOfaCd0fZusL8h5avKTkdTjUu2aHhFJhZoVBGVLhoDtUaqZGWIZGcBJOoVf2JkGUOjDRQ==", "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.34", + "web3-core-helpers": "1.0.0-beta.35", "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" }, "dependencies": { @@ -22259,40 +22301,25 @@ "nan": "2.10.0", "typedarray-to-buffer": "3.1.5", "yaeti": "0.0.6" - }, - "dependencies": { - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" - } } } } }, "web3-shh": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.0.0-beta.34.tgz", - "integrity": "sha1-l1Bh1x6uxCzO5Xb3vY9w8DhEr+A=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.0.0-beta.35.tgz", + "integrity": "sha512-8qSonk/x0xabERS9Sr6AIADN/Ty+5KwARkkGIfSYHKqFpdMDz+76F7cUCxtoCZoS8K04xgZlDKYe0TJXLYA0Fw==", "requires": { - "web3-core": "1.0.0-beta.34", - "web3-core-method": "1.0.0-beta.34", - "web3-core-subscriptions": "1.0.0-beta.34", - "web3-net": "1.0.0-beta.34" + "web3-core": "1.0.0-beta.35", + "web3-core-method": "1.0.0-beta.35", + "web3-core-subscriptions": "1.0.0-beta.35", + "web3-net": "1.0.0-beta.35" } }, "web3-utils": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.0.0-beta.34.tgz", - "integrity": "sha1-lBH8OarvOcpOBhafdiKX2f8CCXA=", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.0.0-beta.35.tgz", + "integrity": "sha512-Dq6f0SOKj3BDFRgOPnE6ALbzBDCKVIW8mKWVf7tGVhTDHf+wQaWwQSC3aArFSqdExB75BPBPyDpuMTNszhljpA==", "requires": { "bn.js": "4.11.6", "eth-lib": "0.1.27", @@ -22511,6 +22538,21 @@ "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz", "integrity": "sha1-f4dliEdxbbUCYyOBL4GMras4el8=" }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "2.1.2" + }, + "dependencies": { + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + } + } + }, "xml2js": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", @@ -22548,8 +22590,7 @@ "yaeti": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=", - "dev": true + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" }, "yallist": { "version": "2.1.2", diff --git a/package.json b/package.json index 3b041608a8..c01f9f2a5c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "origintrail-node", - "version": "1.3.10", + "version": "1.3.24", "description": "OriginTrail node", "main": ".eslintrc.js", "config": { @@ -51,7 +51,7 @@ "snyk": true, "dependencies": { "@garbados/merkle-tree": "^1.0.3-alpha", - "@kadenceproject/kadence": "^4.1.0", + "@kadenceproject/kadence": "^4.1.3", "ajv": "^5.5.2", "arangojs": "^5.8.0", "async": "^2.6.0", @@ -81,6 +81,7 @@ "ip": "^1.1.5", "ipaddr.js": "^1.8.0", "js-levenshtein": "^1.1.3", + "js-sha3": "^0.8.0", "json-stable-stringify": "^1.0.1", "knex": "^0.14.5", "leveldown": "^3.0.0", @@ -112,16 +113,18 @@ "socket.io-client": "^2.1.1", "socks": "^2.1.6", "solidity-sha3": "^0.4.1", + "sorted-json-stringify": "^0.1.1", "sqldown": "^2.1.0", "sqlite3": "^4.0.2", "superagent": "^3.8.3", "truffle-hdwallet-provider": "0.0.5", "umzug": "^2.1.0", "underscore": "^1.9.0", + "utf8": "^3.0.0", "utf8-length": "latest", "uuid": "^3.3.2", "validator": "^9.4.1", - "web3": "1.0.0-beta.34", + "web3": "^1.0.0-beta.35", "winston": "^2.4.3", "winston-loggly-bulk": "^2.0.3", "xml2js": "^0.4.19" diff --git a/seeders/20180407124949-node-config.js b/seeders/20180407124949-node-config.js index 1f229d5a9d..36becd1587 100644 --- a/seeders/20180407124949-node-config.js +++ b/seeders/20180407124949-node-config.js @@ -129,6 +129,18 @@ module.exports = { key: 'node_rpc_port', value: process.env.NODE_RPC_PORT ? process.env.NODE_RPC_PORT : '8900', }, + { + key: 'node_rpc_use_ssl', + value: process.env.NODE_RPC_USE_SSL ? process.env.NODE_RPC_USE_SSL : '0', + }, + { + key: 'node_rpc_ssl_key_path', + value: process.env.NODE_RPC_SSL_KEY_PATH ? process.env.NODE_RPC_SSL_KEY_PATH : '', + }, + { + key: 'node_rpc_ssl_cert_path', + value: process.env.NODE_RPC_SSL_CERT_PATH ? process.env.NODE_RPC_SSL_CERT_PATH : '', + }, { key: 'send_logs_to_origintrail', value: process.env.SEND_LOGS ? process.env.SEND_LOGS : '1', @@ -141,6 +153,10 @@ module.exports = { key: 'is_bootstrap_node', value: process.env.IS_BOOTSTRAP_NODE ? process.env.IS_BOOTSTRAP_NODE : '0', }, + { + key: 'enable_auth_token', + value: process.env.ENABLE_AUTH_TOKEN ? process.env.ENABLE_AUTH_TOKEN : '0', + }, { key: 'houston_password', value: uuidv4(), diff --git a/seeders/20180407223548-blockchain_data.js b/seeders/20180407223548-blockchain_data.js index 8573ecee0c..53866a8e6d 100644 --- a/seeders/20180407223548-blockchain_data.js +++ b/seeders/20180407223548-blockchain_data.js @@ -12,7 +12,7 @@ module.exports = { network_id: 'rinkeby', gas_limit: '800000', gas_price: '5000000000', - ot_contract_address: '0x826b0e0b03f22c5e58557456bd8b8ede318c2e0a', + ot_contract_address: '0xc47ab060e064e9291d723e14ddf4122bc121624b', token_contract_address: '0x98d9a611ad1b5761bdc1daac42c48e4d54cf5882', escrow_contract_address: '0x34248a6e9db421a6f03757efc2a8069df9747161', bidding_contract_address: '0x20d7ca2f13c2703a594962956312ae1f56219213', diff --git a/test/api/zkGetTrail.test.js b/test/api/zkGetTrail.test.js index 9a8ce02240..7248f75878 100644 --- a/test/api/zkGetTrail.test.js +++ b/test/api/zkGetTrail.test.js @@ -81,7 +81,7 @@ describe('Check ZK by quering /api/trail for EVENT vertices', () => { let queryObject; let myTrail; it(`zero knowledge status check for EVENT in ${path.basename(xmlFile.args[0])} file`, async () => { - await gs1.parseGS1(xmlFile.args[0]); + await gs1.parseGS1(await Utilities.fileContents(xmlFile.args[0])); switch (path.basename(xmlFile.args[0])) { case 'Transformation.xml': queryObject = { uid: 'CARENGINES_PROVIDER_ID:2015-03-15T00:00:00.000-04:00Z-04:00' }; diff --git a/test/modules/gs1-importer.test.js b/test/modules/gs1-importer.test.js index 320a73ffc3..f36efc82ad 100644 --- a/test/modules/gs1-importer.test.js +++ b/test/modules/gs1-importer.test.js @@ -1,7 +1,7 @@ /* eslint-disable max-len */ require('dotenv').config(); const { - describe, beforeEach, afterEach, it, + describe, before, beforeEach, afterEach, it, } = require('mocha'); const { assert, expect } = require('chai'); const path = require('path'); @@ -12,12 +12,14 @@ const GS1Utilities = require('../../modules/GS1Utilities'); const WOTImporter = require('../../modules/WOTImporter'); const Importer = require('../../modules/importer'); const Utilities = require('../../modules/Utilities'); -const RemoteControl = require('../../modules/RemoteControl'); const Network = require('../../modules/Network'); const NetworkUtilities = require('../../modules/NetworkUtilities'); const EventEmitter = require('../../modules/EventEmitter'); const Product = require('../../modules/Product'); +const Storage = require('../../modules/Storage'); +const models = require('../../models'); const Web3 = require('web3'); +const fs = require('fs'); const awilix = require('awilix'); function buildSelectedDatabaseParam(databaseName) { @@ -47,6 +49,10 @@ describe('GS1 Importer tests', () => { { args: [path.join(__dirname, 'test_xml/ZKExample.xml')] }, ]; + before('Setup models', async () => { + Storage.models = (await models.sequelize.sync()).models; + }); + beforeEach('Setup DB', async function setupDb() { this.timeout(5000); @@ -104,7 +110,7 @@ describe('GS1 Importer tests', () => { it( `should correctly parse and import ${path.basename(test.args[0])} file ${i}th time`, // eslint-disable-next-line no-loop-func - async () => gs1.parseGS1(test.args[0]), + async () => gs1.parseGS1(await Utilities.fileContents(test.args[0])), ); } }); @@ -116,7 +122,7 @@ describe('GS1 Importer tests', () => { `should correctly pack keys for ${path.basename(test.args[0])}`, // eslint-disable-next-line no-loop-func async () => { - const result = await gs1.parseGS1(test.args[0]); + const result = await gs1.parseGS1(await Utilities.fileContents(test.args[0])); const { response } = await importer.importJSON(result, true); const { vertices, edges } = response; @@ -164,7 +170,7 @@ describe('GS1 Importer tests', () => { it('check keys immutability on GraphExample_3.xml', async () => { const myGraphExample3 = path.join(__dirname, 'test_xml/GraphExample_3.xml'); - await gs1.parseGS1(myGraphExample3); + await gs1.parseGS1(await Utilities.fileContents(myGraphExample3)); const firstImportVerticesCount = await graphStorage.getDocumentsCount('ot_vertices'); assert.equal(firstImportVerticesCount, 14, 'There should be 14 vertices'); @@ -172,7 +178,7 @@ describe('GS1 Importer tests', () => { assert.equal(firstImportVerticesKeys.length, firstImportVerticesCount); // re-import into same db instance - await gs1.parseGS1(myGraphExample3); + await gs1.parseGS1(await Utilities.fileContents(myGraphExample3)); const secondImportVerticesCount = await graphStorage.getDocumentsCount('ot_vertices'); assert.equal(secondImportVerticesCount, 14, 'There should be 14 vertices'); @@ -189,7 +195,7 @@ describe('GS1 Importer tests', () => { it('check total graph nodes count in scenario of GraphExample_3.xml', async () => { const myGraphExample3 = path.join(__dirname, 'test_xml/GraphExample_3.xml'); - await gs1.parseGS1(myGraphExample3); + await gs1.parseGS1(await Utilities.fileContents(myGraphExample3)); const verticesCount1 = await graphStorage.getDocumentsCount('ot_vertices'); assert.isNumber(verticesCount1); assert.isTrue(verticesCount1 >= 0, 'we expect positive number of vertices'); @@ -197,7 +203,7 @@ describe('GS1 Importer tests', () => { assert.isNumber(edgesCount1); assert.isTrue(edgesCount1 >= 0, 'we expect positive number of edges'); - await gs1.parseGS1(myGraphExample3); + await gs1.parseGS1(await Utilities.fileContents(myGraphExample3)); const verticesCount2 = await graphStorage.getDocumentsCount('ot_vertices'); assert.isTrue(verticesCount2 >= 0, 'we expect positive number of vertices'); assert.isNumber(verticesCount2); @@ -213,10 +219,6 @@ describe('GS1 Importer tests', () => { describe('Graph validation', async () => { function checkImportResults(import1Result, import2Result) { - expect(import1Result.root_hash).to.be - .equal(import2Result.root_hash); - expect(import1Result.total_documents).to.be - .equal(import2Result.total_documents); expect(import1Result.vertices.length).to.be .equal(import2Result.vertices.length); @@ -303,14 +305,16 @@ describe('GS1 Importer tests', () => { function checkProcessedResults(processedResult1, processedResult2) { expect(processedResult1.root_hash).to.be.equal(processedResult2.root_hash); + expect(processedResult1.import_hash).to.be.equal(processedResult2.import_hash); + expect(processedResult1.total_documents).to.be.equal(processedResult1.total_documents); } inputXmlFiles.forEach((test) => { it( `should generate the same graph for subsequent ${path.basename(test.args[0])} imports`, async () => { - const import1Result = await gs1.parseGS1(test.args[0]); - const import2Result = await gs1.parseGS1(test.args[0]); + const import1Result = await gs1.parseGS1(await Utilities.fileContents(test.args[0])); + const import2Result = await gs1.parseGS1(await Utilities.fileContents(test.args[0])); checkImportResults(import1Result, import2Result); const processedResult1 = await importer.afterImport(import1Result); @@ -331,7 +335,7 @@ describe('GS1 Importer tests', () => { for (let i = 0; i < imports.length; i += 1) { // eslint-disable-next-line no-await-in-loop - const result = await gs1.parseGS1(imports[i].args[0]); + const result = await gs1.parseGS1(await Utilities.fileContents(imports[i].args[0])); importResults.push(result); } @@ -485,7 +489,7 @@ describe('GS1 Importer tests', () => { inputXmlFiles.forEach((test) => { it(`content/traversal check for ${path.basename(test.args[0])}`, async () => { - await gs1.parseGS1(test.args[0]); + await gs1.parseGS1(await Utilities.fileContents(test.args[0])); await checkSpecificVerticeContent(`${test.args[0]}`); }); }); diff --git a/test/modules/utilities.test.js b/test/modules/utilities.test.js index 5eeca9a1e5..08e5547481 100644 --- a/test/modules/utilities.test.js +++ b/test/modules/utilities.test.js @@ -32,7 +32,7 @@ describe('Utilities module', () => { 'read_stake_factor', 'dh_max_time_mins', 'dh_price', 'dh_stake_factor', 'send_logs_to_origintrail', 'dh_min_reputation', 'dh_min_stake_amount', 'max_token_amount_per_dh', 'total_escrow_time_in_milliseconds', 'is_bootstrap_node', 'houston_password', 'enable_debug_logs_level', 'reverse_tunnel_address', 'reverse_tunnel_port', - 'network_id'], + 'network_id', 'node_rpc_use_ssl', 'node_rpc_ssl_key_path', 'node_rpc_ssl_cert_path', 'enable_auth_token'], 'Some config items are missing in node_config', ); }); diff --git a/test/modules/wot-importer.test.js b/test/modules/wot-importer.test.js index 618496d837..fdbef76aad 100644 --- a/test/modules/wot-importer.test.js +++ b/test/modules/wot-importer.test.js @@ -69,7 +69,7 @@ describe('WOT Importer tests', () => { it( `should correctly parse and import ${path.basename(test.args[0])} file ${i}th time`, // eslint-disable-next-line no-loop-func - async () => wot.parse(test.args[0]), + async () => wot.parse(await Utilities.fileContents(test.args[0])), ); } }); diff --git a/test/protocol/protocol.test.js b/test/protocol/protocol.test.js index 209828b66a..b52c8f46e0 100644 --- a/test/protocol/protocol.test.js +++ b/test/protocol/protocol.test.js @@ -12,7 +12,7 @@ const fs = require('fs'); const Umzug = require('umzug'); const BN = require('bn.js'); const sleep = require('sleep-async')().Promise; -const uuidv4 = require('uuid/v4'); +const bytes = require('utf8-length'); const Utilities = require('../../modules/Utilities'); const ImportUtilities = require('../../modules/ImportUtilities'); @@ -457,7 +457,7 @@ describe('Protocol tests', () => { biddingApprovalIncreaseCommand: awilix.asClass(BiddingApprovalIncreaseCommand) .singleton(), dcController: awilix.asClass(DCController).singleton(), - notifyError: awilix.asFunction(() => {}), + notifyError: awilix.asFunction(() => (error) => { throw error; }), }); testNode.blockchain = container.resolve('blockchain'); @@ -594,6 +594,25 @@ describe('Protocol tests', () => { mockGraphStorage.imports[importId] = { vertices, edges }; const merkle = await ImportUtilities.merkleStructure(vertices, edges); rootHash = merkle.tree.getRoot(); + const normalized = ImportUtilities.normalizeImport( + vertices, + edges, + ); + const importHash = ImportUtilities.importHash( + normalized.vertices, + normalized.edges, + ); + + Models.data_info.create({ + import_id: importId, + root_hash: rootHash, + import_hash: importHash, + data_provider_wallet: testNode1.wallet, + import_timestamp: new Date(), + total_documents: vertices.length, + data_size: bytes(JSON.stringify(vertices)), + transaction_hash: null, + }); }); diff --git a/testnet/register-node.js b/testnet/register-node.js index 83828bacd8..b31d1c5229 100644 --- a/testnet/register-node.js +++ b/testnet/register-node.js @@ -3,7 +3,7 @@ require('dotenv').config(); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; const axios = require('axios'); const envfile = require('envfile'); -const externalip = require('externalip'); +const ip = require('ip'); const fs = require('fs'); const socket = require('socket.io-client')('wss://station.origintrail.io:3010'); @@ -107,20 +107,26 @@ class RegisterNode { counter += 1; console.log(`Counting ${counter}`); if (counter > 20) { - process.kill(3); + process.exit(3); } } }); }, 20000); }).catch((e) => { console.log(e); - process.kill(3); + process.exit(3); }); } setConfig() { return new Promise(async (resolve, reject) => { const env = envfile.parseFileSync('.env'); + + if ('NODE_WALLET' in process.env) { + env.NODE_WALLET = process.env.NODE_WALLET; + env.NODE_PRIVATE_KEY = process.env.NODE_PRIVATE_KEY; + } + if (!env.NODE_WALLET) { const { wallet, pk } = await this.generateWallet(); env.NODE_WALLET = wallet; @@ -128,14 +134,18 @@ class RegisterNode { } if (process.env.INSTALLATION === 'local') { - env.NODE_IP = '127.0.0.1'; + env.NODE_IP = '127.0.0.1'; // TODO remove } else { - env.NODE_IP = await this.getExternalIp(); + env.NODE_IP = ip.address(); } env.DB_PASSWORD = 'root'; env.BOOTSTRAP_NODE = 'https://46.101.233.127:5278/#a69e413b7916a22658e1435b498761ff3d922b56,https://82.196.6.215:5278/#d3167d777720c15e024b7e7ab41055bcdf1bf03e'; + if ('IMPORT_WHITELIST' in process.env) { + env.IMPORT_WHITELIST = process.env.IMPORT_WHITELIST; + } + for (const prop in env) { if (Object.prototype.hasOwnProperty.call(env, prop)) { process.env[prop] = env[prop]; @@ -189,17 +199,6 @@ class RegisterNode { // eslint-disable-next-line require('../ot-node'); } - - getExternalIp() { - return new Promise((resolve, reject) => { - externalip((err, ip) => { - if (err) { - console.log(err); - } - resolve(ip); - }); - }); - } } // eslint-disable-next-line no-new (new RegisterNode());