diff --git a/migrations/20180407114338-create-blockchain-data.js b/migrations/20180407114338-create-blockchain-data.js index b0f956f467..550f1a7c0d 100644 --- a/migrations/20180407114338-create-blockchain-data.js +++ b/migrations/20180407114338-create-blockchain-data.js @@ -28,6 +28,9 @@ module.exports = { escrow_contract_address: { type: Sequelize.STRING, }, + bidding_contract_address: { + type: Sequelize.STRING, + }, rpc_node_host: { type: Sequelize.STRING, }, diff --git a/migrations/20180420094832-create-offers.js b/migrations/20180420094832-create-offers.js new file mode 100644 index 0000000000..e3b7eaaac1 --- /dev/null +++ b/migrations/20180420094832-create-offers.js @@ -0,0 +1,39 @@ + +module.exports = { + up: (queryInterface, Sequelize) => queryInterface.createTable('offers', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + data_lifespan: { + type: Sequelize.INTEGER, + }, + start_tender_time: { + type: Sequelize.INTEGER, + }, + tender_duration: { + type: Sequelize.INTEGER, + }, + min_number_applicants: { + type: Sequelize.INTEGER, + }, + price_tokens: { + type: Sequelize.INTEGER, + }, + data_size_bytes: { + type: Sequelize.INTEGER, + }, + replication_number: { + type: Sequelize.INTEGER, + }, + root_hash: { + type: Sequelize.STRING, + }, + max_token_amount: { + type: Sequelize.INTEGER, + }, + }), + down: (queryInterface, Sequelize) => queryInterface.dropTable('offers'), +}; diff --git a/migrations/20180420095258-create-bids.js b/migrations/20180420095258-create-bids.js new file mode 100644 index 0000000000..e5b17e88bb --- /dev/null +++ b/migrations/20180420095258-create-bids.js @@ -0,0 +1,39 @@ + +module.exports = { + up: (queryInterface, Sequelize) => queryInterface.createTable('bids', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + bid_index: { + type: Sequelize.INTEGER, + }, + price: { + type: Sequelize.INTEGER, + }, + data_id: { + type: Sequelize.INTEGER, + }, + dc_wallet: { + type: Sequelize.STRING, + }, + hash: { + type: Sequelize.STRING, + }, + dc_id: { + type: Sequelize.STRING, + }, + total_escrow_time: { + type: Sequelize.INTEGER, + }, + stake: { + type: Sequelize.INTEGER, + }, + data_size_bytes: { + type: Sequelize.INTEGER, + }, + }), + down: (queryInterface, Sequelize) => queryInterface.dropTable('bids'), +}; diff --git a/models/bids.js b/models/bids.js new file mode 100644 index 0000000000..bcc52c4f4b --- /dev/null +++ b/models/bids.js @@ -0,0 +1,18 @@ + +module.exports = (sequelize, DataTypes) => { + const bids = sequelize.define('bids', { + bid_index: DataTypes.INTEGER, + price: DataTypes.INTEGER, + hash: DataTypes.STRING(128), + data_id: DataTypes.INTEGER, + dc_wallet: DataTypes.STRING, + dc_id: DataTypes.STRING, + total_escrow_time: DataTypes.INTEGER, + stake: DataTypes.INTEGER, + data_size_bytes: DataTypes.INTEGER, + }, {}); + bids.associate = function (models) { + // associations can be defined here + }; + return bids; +}; diff --git a/models/blockchain_data.js b/models/blockchain_data.js index 71888058a4..61a4d33703 100644 --- a/models/blockchain_data.js +++ b/models/blockchain_data.js @@ -8,6 +8,7 @@ module.exports = (sequelize, DataTypes) => { ot_contract_address: DataTypes.STRING(50), token_contract_address: DataTypes.STRING(50), escrow_contract_address: DataTypes.STRING(50), + bidding_contract_address: DataTypes.STRING(50), rpc_node_host: DataTypes.STRING(256), rpc_node_port: DataTypes.INTEGER, wallet_address: DataTypes.STRING(50), diff --git a/models/offers.js b/models/offers.js new file mode 100644 index 0000000000..5190896ca8 --- /dev/null +++ b/models/offers.js @@ -0,0 +1,18 @@ + +module.exports = (sequelize, DataTypes) => { + var offers = sequelize.define('offers', { + data_lifespan: DataTypes.INTEGER, + start_tender_time: DataTypes.INTEGER, + tender_duration: DataTypes.INTEGER, + min_number_applicants: DataTypes.INTEGER, + price_tokens: DataTypes.INTEGER, + data_size_bytes: DataTypes.INTEGER, + replication_number: DataTypes.INTEGER, + root_hash: DataTypes.STRING, + max_token_amount: DataTypes.INTEGER, + }, {}); + offers.associate = function (models) { + // associations can be defined here + }; + return offers; +}; diff --git a/modules/Blockchain.js b/modules/Blockchain.js index 2770c54346..b1783e89be 100644 --- a/modules/Blockchain.js +++ b/modules/Blockchain.js @@ -35,15 +35,12 @@ class Blockchain { } /** - * Initiating escrow for data holding - * @param {string} - dhWallet - * @param {number} - dataId - * @param {number} - tokenAmount - * @param {number} - totalTime + * Increase token approval for bidding contract + * @param {number} tokenAmountIncrease * @returns {Promise} */ - initiateEscrow(dhWallet, dataId, tokenAmount, totalTime) { - return this.blockchain.initiateEscrow(dhWallet, dataId, tokenAmount, totalTime); + increaseBiddingApproval(tokenAmountIncrease) { + return this.blockchain.increaseBiddingApproval(tokenAmountIncrease); } /** @@ -51,11 +48,12 @@ class Blockchain { * @param {string} - dcWallet * @param {number} - dataId * @param {number} - tokenAmount + * @param {number} - stakeAmount * @param {number} - totalTime * @returns {Promise} */ - verifyEscrow(dcWallet, dataId, tokenAmount, totalTime) { - return this.blockchain.verifyEscrow(dcWallet, dataId, tokenAmount, totalTime); + verifyEscrow(dcWallet, dataId, tokenAmount, stakeAmount, totalTime) { + return this.blockchain.verifyEscrow(dcWallet, dataId, tokenAmount, stakeAmount, totalTime); } /** @@ -77,6 +75,122 @@ class Blockchain { payOut(dcWallet, dataId) { return this.blockchain.payOut(dcWallet, dataId); } + + /** + * Creates offer for the data storing on the Ethereum blockchain. + * @param dataId Data ID of the offer. + * @param nodeId KADemlia node ID of offer creator + * @param totalEscrowTime Total time of the escrow in milliseconds + * @param maxTokenAmount Maximum price per DH + * @param MinStakeAmount Minimum stake in tokens + * @param biddingTime Total time of the bid in milliseconds + * @param minNumberOfBids Number of bid required for offer to be successful + * @param dataSize Size of the data for storing in bytes + * @param ReplicationFactor Number of replications + * @returns {Promise} Return choose start-time. + */ + createOffer( + dataId, nodeId, + totalEscrowTime, + maxTokenAmount, + MinStakeAmount, + biddingTime, + minNumberOfBids, + dataSize, ReplicationFactor, + ) { + return this.blockchain.createOffer( + dataId, nodeId, + totalEscrowTime, + maxTokenAmount, + MinStakeAmount, + biddingTime, + minNumberOfBids, + dataSize, ReplicationFactor, + ); + } + + /** + * Cancel offer for data storing on Ethereum blockchain. + * @param dataId Data if of the offer. + */ + cancelOffer(dataId) { + return this.blockchain.cancelOffer(dataId); + } + + /** + * Subscribe to a particular event + * @param contractName Ethereum contract instance + * @param event Event name + * @param eventOpts Event options (filter, range, etc.) + * @param callback Callback to be executed on success/error (callback returns stop flag) + * @param periodMills Repeating period for checking past events + * @param untilMills Subscription termination + */ + subscribeToEvent(contractName, event, eventOpts, callback, periodMills, untilMills) { + return this.blockchain + .subscribeToEvent(contractName, event, eventOpts, callback, periodMills, untilMills); + } + + /** + * Adds bid to the offer on Ethereum blockchain + * @param dcWallet Wallet of the bidder + * @param dataId ID of the data of the bid + * @param nodeId KADemlia ID of this node + * @param bidHash Hashed bid that will be revealed once + * revealBid() is called. @note token amount cannot be greater then max token amount + * @returns {Promise} Index of the bid. + */ + addBid(dcWallet, dataId, nodeId, bidHash) { + return this.blockchain.addBid(dcWallet, dataId, nodeId, bidHash); + } + + /** + * Cancel the bid on Ethereum blockchain + * @param dcWallet Wallet of the bidder + * @param dataId ID of the data of the bid + * @param bidIndex Index of the bid + * @returns {Promise} + */ + cancelBid(dcWallet, dataId, bidIndex) { + return this.blockchain.cancelBid(dcWallet, dataId, bidIndex); + } + + /** + * Reveals the bid of the offer + * @param dcWallet Wallet of the DC who's offer is + * @param dataId Id of the data in the offer + * @param nodeId KADemlia ID of bidder + * @param tokenAmount Amount of the token + * @param stakeAmount Amount of the stake + * @param bidIndex Index of the bid + * @returns {Promise} + */ + revealBid(dcWallet, dataId, nodeId, tokenAmount, stakeAmount, bidIndex) { + return this.blockchain.revealBid( + dcWallet, dataId, nodeId, + tokenAmount, stakeAmount, bidIndex, + ); + } + + /** + * Starts choosing bids from contract escrow on Ethereum blockchain + * @param dataId ID of data of the bid + * @returns {Promise} Array of bid indices of chosen ones. + */ + chooseBids(dataId) { + return this.blockchain.chooseBids(dataId); + } + + /** + * + * @param dcWallet + * @param dataId + * @param bidIndex + * @returns {Promise} + */ + getBid(dcWallet, dataId, bidIndex) { + return this.blockchain.getBid(dcWallet, dataId, bidIndex); + } } module.exports = Blockchain; diff --git a/modules/Blockchain/Ethereum/Transactions.js b/modules/Blockchain/Ethereum/Transactions.js index a691a8d56f..30f8ba3590 100644 --- a/modules/Blockchain/Ethereum/Transactions.js +++ b/modules/Blockchain/Ethereum/Transactions.js @@ -37,7 +37,6 @@ class Transactions { newTransaction.args, newTransaction.options, ); - const transaction = new Tx(rawTx); transaction.sign(this.privateKey); diff --git a/modules/Blockchain/Ethereum/bidding-contract/abi.json b/modules/Blockchain/Ethereum/bidding-contract/abi.json new file mode 100644 index 0000000000..81a9c9310a --- /dev/null +++ b/modules/Blockchain/Ethereum/bidding-contract/abi.json @@ -0,0 +1,580 @@ +[ + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "node_id", + "type": "uint256" + }, + { + "name": "bid_hash", + "type": "bytes32" + } + ], + "name": "addBid", + "outputs": [ + { + "name": "bidIndex", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "bidIndex", + "type": "uint256" + } + ], + "name": "cancelBid", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "data_id", + "type": "uint256" + } + ], + "name": "cancelOffer", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "data_id", + "type": "uint256" + } + ], + "name": "chooseBids", + "outputs": [ + { + "name": "chosen_data_holders", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "DC_node_id", + "type": "uint256" + }, + { + "name": "total_escrow_time", + "type": "uint256" + }, + { + "name": "max_token_amount", + "type": "uint256" + }, + { + "name": "min_stake_amount", + "type": "uint256" + }, + { + "name": "bidding_phase_time", + "type": "uint256" + }, + { + "name": "min_number_of_bids", + "type": "uint256" + }, + { + "name": "data_size", + "type": "uint256" + }, + { + "name": "replication_factor", + "type": "uint256" + } + ], + "name": "createOffer", + "outputs": [ + { + "name": "choose_start_time", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + } + ], + "name": "BidTaken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + }, + { + "indexed": false, + "name": "bidIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "node_id", + "type": "uint256" + }, + { + "indexed": false, + "name": "bid_hash", + "type": "bytes32" + } + ], + "name": "AddedBid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + } + ], + "name": "OfferFinalized", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "node_id", + "type": "uint256" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "stake_amount", + "type": "uint256" + }, + { + "name": "bidIndex", + "type": "uint256" + } + ], + "name": "revealBid", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + } + ], + "name": "OfferCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "node_id", + "type": "uint256" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + }, + { + "indexed": false, + "name": "token_amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "stake_amount", + "type": "uint256" + } + ], + "name": "RevealedBid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "DC_node_id", + "type": "uint256" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + }, + { + "indexed": false, + "name": "total_escrow_time", + "type": "uint256" + }, + { + "indexed": false, + "name": "max_token_amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "min_stake_amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "data_size", + "type": "uint256" + } + ], + "name": "OfferCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "x", + "type": "uint256" + } + ], + "name": "XwasSet", + "type": "event" + }, + { + "inputs": [ + { + "name": "tokenAddress", + "type": "address" + }, + { + "name": "escrowAddress", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "bid", + "outputs": [ + { + "name": "bid_hash", + "type": "bytes32" + }, + { + "name": "DH_wallet", + "type": "address" + }, + { + "name": "node_id", + "type": "uint256" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "stake_amount", + "type": "uint256" + }, + { + "name": "chance", + "type": "uint256" + }, + { + "name": "active", + "type": "bool" + }, + { + "name": "chosen", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "escrow", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + } + ], + "name": "getOfferStatus", + "outputs": [ + { + "name": "isOfferFinal", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "bidIndex", + "type": "uint256" + } + ], + "name": "isBidChosen", + "outputs": [ + { + "name": "_isBidChosen", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "offer", + "outputs": [ + { + "name": "total_escrow_time", + "type": "uint256" + }, + { + "name": "max_token_amount", + "type": "uint256" + }, + { + "name": "min_stake_amount", + "type": "uint256" + }, + { + "name": "reveal_start_time", + "type": "uint256" + }, + { + "name": "choose_start_time", + "type": "uint256" + }, + { + "name": "min_number_of_bids", + "type": "uint256" + }, + { + "name": "data_size", + "type": "uint256" + }, + { + "name": "replication_factor", + "type": "uint256" + }, + { + "name": "number_of_bids", + "type": "uint256" + }, + { + "name": "number_of_bids_revealed", + "type": "uint256" + }, + { + "name": "total_bid_chance", + "type": "uint256" + }, + { + "name": "random_number_seed", + "type": "uint256" + }, + { + "name": "active", + "type": "bool" + }, + { + "name": "finalized", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "token", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/modules/Blockchain/Ethereum/bidding-contract/bytecode.txt b/modules/Blockchain/Ethereum/bidding-contract/bytecode.txt new file mode 100644 index 0000000000..5e2c8993b0 --- /dev/null +++ b/modules/Blockchain/Ethereum/bidding-contract/bytecode.txt @@ -0,0 +1 @@ +6080604052631dcd650060025534801561001857600080fd5b506040516040806129168339810180604052810190808051906020019092919080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156100af5750600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15156100ba57600080fd5b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050506127ca8061014c6000396000f3006080604052600436106100ba576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303b31c15146100bf5780630a094dd0146101345780630f41ba4b146101b65780633290463b1461028e57806352cb44fc146102e55780636b2129601461034a5780638f573d9c1461040e578063c15bd4cb1461047d578063c9325129146104f6578063e2fdcc1714610587578063ef706adf146105de578063fc0c546a1461060b575b600080fd5b3480156100cb57600080fd5b50610132600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190505050610662565b005b34801561014057600080fd5b5061015f60048036038101908080359060200190929190505050610d15565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156101a2578082015181840152602081019050610187565b505050509050019250505060405180910390f35b3480156101c257600080fd5b5061020b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190505050611757565b6040518089600019166000191681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200187815260200186815260200185815260200184815260200183151515158152602001821515151581526020019850505050505050505060405180910390f35b34801561029a57600080fd5b506102e3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291905050506117f3565b005b3480156102f157600080fd5b50610330600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611bf9565b604051808215151515815260200191505060405180910390f35b34801561035657600080fd5b50610395600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611c64565b604051808f81526020018e81526020018d81526020018c81526020018b81526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200183151515158152602001821515151581526020019e50505050505050505050505050505060405180910390f35b34801561041a57600080fd5b50610463600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190505050611cf7565b604051808215151515815260200191505060405180910390f35b34801561048957600080fd5b506104e0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035600019169060200190929190505050611d74565b6040518082815260200191505060405180910390f35b34801561050257600080fd5b5061057160048036038101908080359060200190929190803590602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919050505061208e565b6040518082815260200191505060405180910390f35b34801561059357600080fd5b5061059c612642565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156105ea57600080fd5b5061060960048036038101908080359060200190929190505050612668565b005b34801561061757600080fd5b50610620612742565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000600360008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000878152602001908152602001600020600c0160009054906101000a900460ff1615156106d057600080fd5b42600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000888152602001908152602001600020600301541115151561073257600080fd5b42600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008881526020019081526020016000206004015411151561079357600080fd5b83600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600088815260200190815260200160002060010154101515156107f557600080fd5b33858585604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401848152602001838152602001828152602001945050505050604051809103902060001916600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000888152602001908152602001600020600084815260200190815260200160002060000154600019161415156108d757600080fd5b33600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000888152602001908152602001600020600084815260200190815260200160002060010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555084600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600088815260200190815260200160002060008481526020019081526020016000206002018190555083600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600088815260200190815260200160002060008481526020019081526020016000206003018190555082600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600088815260200190815260200160002060008481526020019081526020016000206004018190555083600254811515610ac257fe5b04600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008881526020019081526020016000206000848152602001908152602001600020600501819055506001600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000888152602001908152602001600020600084815260200190815260200160002060060160006101000a81548160ff021916908315150217905550600360008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008781526020019081526020016000209050610c1e84600254811515610c0a57fe5b0482600a015461276790919063ffffffff16565b81600a0181905550610c3e6001826009015461276790919063ffffffff16565b81600901819055504381600b01540181600b01819055507fefd438b1966b5984f9c065e1473677494dc718928f53405fcaa8d223dc4e90f1873387898888604051808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001838152602001828152602001965050505050505060405180910390a150505050505050565b60606000806000806000806000806000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c815260200190815260200160002098508860090154896005015411151515610d8e57600080fd5b42896004015411151515610da157600080fd5b8860070154975087604051908082528060200260200182016040528015610dd75781602001602082028038833980820191505090505b5099506000965088600b015495505b8787108015610df9575088600901548811155b156116725788600a0154428a60080154880201811515610e1557fe5b06945060009350600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c815260200190815260200160002060008581526020019081526020016000206005015492505b84831015610f12578380600101945050610f0b600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008d81526020019081526020016000206000868152602001908152602001600020600501548461276790919063ffffffff16565b9250610e84565b600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c81526020019081526020016000206000858152602001908152602001600020915081600401546000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8460010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16306040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b15801561108e57600080fd5b505af11580156110a2573d6000803e3d6000fd5b505050506040513d60208110156110b857600080fd5b8101908080519060200190929190505050101580156111f5575081600401546000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a082318460010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156111b757600080fd5b505af11580156111cb573d6000803e3d6000fd5b505050506040513d60208110156111e157600080fd5b810190808051906020019092919050505010155b156115f8578160040154905060008260040181905550600082600501819055506000811115611399576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8360010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561135c57600080fd5b505af1158015611370573d6000803e3d6000fd5b505050506040513d602081101561138657600080fd5b8101908080519060200190929190505050505b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166395b9df2b338460010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168e8660030154868f600001546040518763ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018481526020018381526020018281526020019650505050505050600060405180830381600087803b1580156114d657600080fd5b505af11580156114ea573d6000803e3d6000fd5b5050505060018260060160016101000a81548160ff021916908315150217905550838a8881518110151561151a57fe5b906020019060200201818152505086806001019750507f317718fddb55bc6c03b3519e1be57b8f4dc97663268ddbce56748913919390c9338360010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a1611640565b61161060018a6009015461278590919063ffffffff16565b89600901819055506000826005018190555060008260060160006101000a81548160ff0219169083151502179055505b6000826005018190555061166582600501548a600a015461278590919063ffffffff16565b89600a0181905550610de6565b6001600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008d8152602001908152602001600020600c0160016101000a81548160ff0219169083151502179055507f064d50203237a65dcd9810ba5ec04a2028896bd1480ae79852d640ca58e4f6d0338c604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1505050505050505050919050565b600460205282600052604060002060205281600052604060002060205280600052604060002060009250925050508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030154908060040154908060050154908060060160009054906101000a900460ff16908060060160019054906101000a900460ff16905088565b3373ffffffffffffffffffffffffffffffffffffffff16600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020600083815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156118b157600080fd5b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000838152602001908152602001600020600082815260200190815260200160002060060160009054906101000a900460ff16151561192e57600080fd5b6119f8600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020600083815260200190815260200160002060050154600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020600a015461278590919063ffffffff16565b600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020600a0181905550611ab66001600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008581526020019081526020016000206009015461278590919063ffffffff16565b600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020600901819055506000600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000206000838152602001908152602001600020600501819055506000600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020600083815260200190815260200160002060060160006101000a81548160ff021916908315150217905550505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000838152602001908152602001600020600c0160019054906101000a900460ff16905092915050565b60036020528160005260406000206020528060005260406000206000915091505080600001549080600101549080600201549080600301549080600401549080600501549080600601549080600701549080600801549080600901549080600a01549080600b01549080600c0160009054906101000a900460ff169080600c0160019054906101000a900460ff1690508e565b6000600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020600083815260200190815260200160002060060160019054906101000a900460ff1690509392505050565b6000600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020600c0160009054906101000a900460ff161515611de257600080fd5b42600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002060030154111515611e4357600080fd5b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020600801549050611f006001600360008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008781526020019081526020016000206008015461276790919063ffffffff16565b600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008681526020019081526020016000206008018190555081600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000868152602001908152602001600020600083815260200190815260200160002060000181600019169055507ff5376361bc5b311271bd72143b9d96f479075f09b9afe0b442f6af8239ba2212858583338787604051808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018381526020018260001916600019168152602001965050505050505060405180910390a1809050949350505050565b6000808711801561209f5750600088115b80156120ab5750600084115b80156120b75750600085115b80156120c35750600082115b15156120ce57600080fd5b8382111515156120dd57600080fd5b60001515600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c8152602001908152602001600020600c0160009054906101000a900460ff16151514151561215057600080fd5b87600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c81526020019081526020016000206000018190555086600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c81526020019081526020016000206001018190555085600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c815260200190815260200160002060020181905550844201600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c815260200190815260200160002060030181905550846002024201600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c8152602001908152602001600020600401819055905083600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c81526020019081526020016000206005018190555082600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c81526020019081526020016000206006018190555081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c8152602001908152602001600020600701819055506000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c8152602001908152602001600020600801819055506000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c8152602001908152602001600020600901819055506001600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c8152602001908152602001600020600c0160006101000a81548160ff0219169083151502179055506000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c8152602001908152602001600020600c0160016101000a81548160ff0219169083151502179055507f623b4c671f8767711f2158cec69be01f8212cd521cff76563ca2c0fec199ccbd338a8c8b8b8b89604051808873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200187815260200186815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390a19998505050505050505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000838152602001908152602001600020600c0160006101000a81548160ff0219169083151502179055507f871dc347e88ef58454c9f69d734469ed3f59dd31fd0d6b7960d092da71f4454d3382604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a150565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080828401905083811015151561277b57fe5b8091505092915050565b600082821115151561279357fe5b8183039050929150505600a165627a7a723058207826592a98093e60392d833bb15834d22c53054b9a79bf01ca116feeb74f73b30029 \ No newline at end of file diff --git a/modules/Blockchain/Ethereum/contracts/Bidding.sol b/modules/Blockchain/Ethereum/contracts/Bidding.sol new file mode 100644 index 0000000000..9e5c835453 --- /dev/null +++ b/modules/Blockchain/Ethereum/contracts/Bidding.sol @@ -0,0 +1,281 @@ +pragma solidity ^0.4.18; + +library SafeMath { + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function div(uint256 a, uint256 b) internal pure returns (uint256) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + assert(b <= a); + return a - b; + } + + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + assert(c >= a); + return c; + } +} + +contract ERC20Basic { + uint256 public totalSupply; + function balanceOf(address who) public constant returns (uint256); + function transfer(address to, uint256 value) public returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value); +} + +contract ERC20 is ERC20Basic { + function allowance(address owner, address spender) public constant returns (uint256); + function transferFrom(address from, address to, uint256 value) public returns (bool); + function approve(address spender, uint256 value) public returns (bool); + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +contract EscrowHolder { + function initiateEscrow(address DC_wallet, address DH_wallet, uint data_id, uint token_amount,uint stake_amount, uint total_time) public; +} + +contract Bidding { + using SafeMath for uint256; + + ERC20 public token; + EscrowHolder public escrow; + uint TOTAL_NUM_TOKENS = 500000000; + + function Bidding(address tokenAddress, address escrowAddress) + public{ + require ( tokenAddress != address(0) && escrowAddress != address(0)); + token = ERC20(tokenAddress); + escrow = EscrowHolder(escrowAddress); + } + + + /* ----------------------------- BIDDING ----------------------------- */ + + + struct OfferDefinition{ + //Parameters of one escrow + uint total_escrow_time; + uint max_token_amount; + uint min_stake_amount; + + //Parameters for the bidding + uint reveal_start_time; + uint choose_start_time; + uint min_number_of_bids; + + //Parameters of the data + uint data_size; + uint replication_factor; //Number of DH's required + + + //Parameters for use during the bidding mechanism + uint256 number_of_bids; + uint256 number_of_bids_revealed; + uint total_bid_chance; + uint random_number_seed; + bool active; + bool finalized; + } + + struct BidDefinition{ + bytes32 bid_hash; + address DH_wallet; + uint node_id; + uint token_amount; + uint stake_amount; + uint chance; + bool active; + bool chosen; + } + + mapping(address => mapping(uint => OfferDefinition)) public offer; + mapping(address => mapping(uint => mapping(uint => BidDefinition))) public bid; + + uint256 x; + + event OfferCreated(address DC_wallet,uint DC_node_id, uint data_id, uint total_escrow_time, uint max_token_amount, uint min_stake_amount, uint data_size); + event OfferCanceled(address DC_wallet, uint data_id); + // event RevealPhaseStarted(address DC_wallet, uint data_id); + // event ChoosingPhaseStarted(address DC_wallet, uint data_id); + event AddedBid(address DC_wallet,uint data_id, uint bidIndex, address DH_wallet, uint node_id, bytes32 bid_hash); + event BidTaken(address DC_wallet, address DH_wallet, uint data_id); + event RevealedBid(address DC_wallet, address DH_wallet, uint node_id,uint data_id, uint token_amount, uint stake_amount); + event OfferFinalized(address DC_wallet,uint data_id); + event XwasSet(uint x); + + function createOffer( + uint data_id, + uint DC_node_id, + uint total_escrow_time, + uint max_token_amount, + uint min_stake_amount, + uint bidding_phase_time, + uint min_number_of_bids, + uint data_size, + uint replication_factor) + public returns (uint choose_start_time){ + + require(max_token_amount > 0 && total_escrow_time > 0 && min_number_of_bids > 0 && bidding_phase_time > 0 && replication_factor > 0); + require(replication_factor <= min_number_of_bids); + require(offer[msg.sender][data_id].active == false); + + // require(token.allowance(msg.sender,this) >= SafeMath.mul(tokens_per_DH,replication_factor)); + // token.transferFrom(msg.sender,this,SafeMath.mul(tokens_per_DH,replication_factor)); + + offer[msg.sender][data_id].total_escrow_time = total_escrow_time; + offer[msg.sender][data_id].max_token_amount = max_token_amount; + offer[msg.sender][data_id].min_stake_amount = min_stake_amount; + + offer[msg.sender][data_id].reveal_start_time = block.timestamp + bidding_phase_time; + choose_start_time = offer[msg.sender][data_id].choose_start_time = block.timestamp + 2 * bidding_phase_time; + offer[msg.sender][data_id].min_number_of_bids = min_number_of_bids; + + offer[msg.sender][data_id].data_size = data_size; + offer[msg.sender][data_id].replication_factor = replication_factor; + + offer[msg.sender][data_id].number_of_bids = 0; + offer[msg.sender][data_id].number_of_bids_revealed = 0; + offer[msg.sender][data_id].active = true; + offer[msg.sender][data_id].finalized = false; + OfferCreated(msg.sender, DC_node_id, data_id, total_escrow_time,max_token_amount, min_stake_amount, data_size); + } + + + //Da li vraca pare? Kada sme da uradi cancel? + function cancelOffer(uint data_id) + public{ + offer[msg.sender][data_id].active = false; + + OfferCanceled(msg.sender, data_id); + } + + function isBidChosen(address DC_wallet, uint data_id, uint bidIndex) public constant returns (bool _isBidChosen){ + return bid[DC_wallet][data_id][bidIndex].chosen; + } + function getOfferStatus(address DC_wallet, uint data_id) public constant returns (bool isOfferFinal){ + return offer[DC_wallet][data_id].finalized; + } + + function addBid(address DC_wallet, uint data_id, uint node_id, bytes32 bid_hash) + public returns (uint bidIndex){ + require(offer[DC_wallet][data_id].active); + require(offer[DC_wallet][data_id].reveal_start_time > block.timestamp); + + bidIndex = offer[DC_wallet][data_id].number_of_bids; + offer[DC_wallet][data_id].number_of_bids = offer[DC_wallet][data_id].number_of_bids.add(1); + + // fix + bid[DC_wallet][data_id][bidIndex].bid_hash = bid_hash; + + // bid[DC_wallet][data_id][bidIndex].bid_hash = keccak256(msg.sender, node_id, token_amount, stake_amount); + AddedBid(DC_wallet,data_id, bidIndex, msg.sender, node_id, bid_hash ); + return bidIndex; + } + + function revealBid(address DC_wallet, uint data_id, uint node_id, uint token_amount, uint stake_amount, uint bidIndex) + public { + + require(offer[DC_wallet][data_id].active); + require(offer[DC_wallet][data_id].reveal_start_time <= block.timestamp); + require(offer[DC_wallet][data_id].choose_start_time > block.timestamp); + require(offer[DC_wallet][data_id].max_token_amount >= token_amount); + + require(bid[DC_wallet][data_id][bidIndex].bid_hash == keccak256(msg.sender, node_id, token_amount, stake_amount)); + + bid[DC_wallet][data_id][bidIndex].DH_wallet = msg.sender; + bid[DC_wallet][data_id][bidIndex].node_id = node_id; + bid[DC_wallet][data_id][bidIndex].token_amount = token_amount; + bid[DC_wallet][data_id][bidIndex].stake_amount = stake_amount; + bid[DC_wallet][data_id][bidIndex].chance = TOTAL_NUM_TOKENS / token_amount; + bid[DC_wallet][data_id][bidIndex].active = true; + + OfferDefinition storage this_offer = offer[DC_wallet][data_id]; + + this_offer.total_bid_chance = this_offer.total_bid_chance.add(TOTAL_NUM_TOKENS / token_amount); + this_offer.number_of_bids_revealed = this_offer.number_of_bids_revealed.add(1); + this_offer.random_number_seed = this_offer.random_number_seed + block.number;//FIX + + RevealedBid(DC_wallet,msg.sender, node_id,data_id, token_amount, stake_amount); + + } + + function cancelBid(address DC_wallet, uint data_id, uint bidIndex) + public{ + require(bid[DC_wallet][data_id][bidIndex].DH_wallet == msg.sender); + require(bid[DC_wallet][data_id][bidIndex].active); + + offer[DC_wallet][data_id].total_bid_chance = offer[DC_wallet][data_id].total_bid_chance.sub(bid[DC_wallet][data_id][bidIndex].chance); + offer[DC_wallet][data_id].number_of_bids_revealed = offer[DC_wallet][data_id].number_of_bids_revealed.sub(1); + + bid[DC_wallet][data_id][bidIndex].chance = 0; + bid[DC_wallet][data_id][bidIndex].active = false; + } + + function chooseBids(uint data_id) public returns (uint256[] chosen_data_holders){ + + OfferDefinition storage this_offer = offer[msg.sender][data_id]; + + require(this_offer.min_number_of_bids <= this_offer.number_of_bids_revealed); + require(this_offer.choose_start_time <= block.timestamp); + + uint N = this_offer.replication_factor; + chosen_data_holders = new uint256[](N); + + uint256 i = 0; + uint256 seed = this_offer.random_number_seed; + + while(i < N && N <= this_offer.number_of_bids_revealed){ //FIX: Should be hash(block.hash) + + uint nextIndex = (seed * this_offer.number_of_bids + block.timestamp) % this_offer.total_bid_chance; + uint256 j = 0; + uint256 sum = bid[msg.sender][data_id][j].chance; + while(sum < nextIndex){ + j++; + sum = sum.add(bid[msg.sender][data_id][j].chance); + } + BidDefinition storage chosenBid = bid[msg.sender][data_id][j]; + if(token.allowance(chosenBid.DH_wallet,this) >= chosenBid.stake_amount + && token.balanceOf(chosenBid.DH_wallet) >= chosenBid.stake_amount){ + + uint stake_to_transfer = chosenBid.stake_amount; + chosenBid.stake_amount = 0; + chosenBid.chance = 0; + // // transfering stake + // if(stake_to_transfer > 0) token.transferFrom(chosenBid.DH_wallet,escrow,stake_to_transfer); + + //Initiating new escrow + escrow.initiateEscrow(msg.sender, chosenBid.DH_wallet, data_id, chosenBid.token_amount, stake_to_transfer, this_offer.total_escrow_time); + //TODO Ako DC odmah salje pare ovde racunati koliko treba da mu se vrati + chosenBid.chosen = true; + chosen_data_holders[i] = j; + i++; + BidTaken(msg.sender, chosenBid.DH_wallet, data_id); + } + else{ + this_offer.number_of_bids_revealed = this_offer.number_of_bids_revealed.sub(1); + chosenBid.chance = 0; + chosenBid.active = false; + + } + chosenBid.chance = 0; + this_offer.total_bid_chance = this_offer.total_bid_chance.sub(chosenBid.chance); + } + + + + offer[msg.sender][data_id].finalized = true; + OfferFinalized(msg.sender,data_id); + + } + +} \ No newline at end of file diff --git a/modules/Blockchain/Ethereum/contracts/Escrow.sol b/modules/Blockchain/Ethereum/contracts/Escrow.sol index d378b7f35b..16aef57508 100644 --- a/modules/Blockchain/Ethereum/contracts/Escrow.sol +++ b/modules/Blockchain/Ethereum/contracts/Escrow.sol @@ -25,7 +25,45 @@ library SafeMath { return c; } } +/** + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ + contract Ownable { + address public owner; + + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + function Ownable() public { + owner = msg.sender; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function transferOwnership(address newOwner) public onlyOwner { + require(newOwner != address(0)); + emit OwnershipTransferred(owner, newOwner); + owner = newOwner; + } +} contract ERC20Basic { uint256 public totalSupply; function balanceOf(address who) public constant returns (uint256); @@ -40,18 +78,28 @@ contract ERC20 is ERC20Basic { event Approval(address indexed owner, address indexed spender, uint256 value); } -contract EscrowHolder { +contract EscrowHolder is Ownable{ using SafeMath for uint256; ERC20 public token; + function EscrowHolder(address tokenAddress) + public{ + require ( tokenAddress != address(0) ); + token = ERC20(tokenAddress); + } + + /* ----------------------------- ESCROW ----------------------------- */ + enum EscrowStatus {initiated, active, canceled, completed} struct EscrowDefinition{ uint token_amount; uint tokens_sent; + + uint stake_amount; uint last_confirmation_time; uint end_time; @@ -62,61 +110,63 @@ contract EscrowHolder { mapping(address => mapping(address => mapping(uint => EscrowDefinition))) public escrow; - event EscrowInitated(address DC_wallet, address DH_wallet, uint data_id); - event EscrowVerified(address DC_wallet, address DH_wallet, uint data_id); + event EscrowInitated(address DC_wallet, address DH_wallet, uint data_id, uint token_amount, uint stake_amount, uint total_time); + event EscrowVerified(address DC_wallet, address DH_wallet, uint data_id, bool verification_successful); event EscrowCanceled(address DC_wallet, address DH_wallet, uint data_id); event EscrowCompleted(address DC_wallet, address DH_wallet, uint data_id); - function EscrowHolder(address tokenAddress) - public{ - require ( tokenAddress != address(0) ); - token = ERC20(tokenAddress); - } - - function initiateEscrow(address DH_wallet, uint data_id, uint token_amount, uint total_time) - public { - require(escrow[msg.sender][DH_wallet][data_id].escrow_status != EscrowStatus.active - && escrow[msg.sender][DH_wallet][data_id].escrow_status != EscrowStatus.canceled); + function initiateEscrow(address DC_wallet, address DH_wallet, uint data_id, uint token_amount, uint stake_amount, uint total_time) + public onlyOwner{ + require(escrow[DC_wallet][DH_wallet][data_id].escrow_status != EscrowStatus.active + && escrow[DC_wallet][DH_wallet][data_id].escrow_status != EscrowStatus.canceled); require(token_amount > 0 && total_time > 0); - require(token.allowance(msg.sender,this) >= token_amount); - token.transferFrom(msg.sender,this,token_amount); + require(token.allowance(DC_wallet,this) >= token_amount); + token.transferFrom(DC_wallet, this, token_amount); - escrow[msg.sender][DH_wallet][data_id] = EscrowDefinition(token_amount, 0, 0, 0, total_time, EscrowStatus.initiated); + escrow[DC_wallet][DH_wallet][data_id] = EscrowDefinition(token_amount, 0, stake_amount, 0, 0, total_time, EscrowStatus.initiated); - EscrowInitated(msg.sender, DH_wallet, data_id); + EscrowInitated(DC_wallet, DH_wallet, data_id, token_amount, stake_amount, total_time); } - function verifyEscrow(address DC_wallet, uint data_id, uint token_amount, uint total_time) + function verifyEscrow(address DC_wallet, uint data_id, uint token_amount, uint stake_amount, uint total_time) public returns (bool isVerified){ isVerified = false; EscrowDefinition storage escrow_def = escrow[DC_wallet][msg.sender][data_id]; - + require(escrow_def.token_amount == token_amount && - escrow_def.escrow_status == EscrowStatus.initiated && - escrow_def.total_time == total_time); + escrow_def.stake_amount == stake_amount && + escrow_def.escrow_status == EscrowStatus.initiated && + escrow_def.total_time == total_time); - escrow_def.last_confirmation_time = block.number; - escrow_def.end_time = SafeMath.add(block.number, total_time); + //Transfer the stake_amount to the escrow + require(token.allowance(msg.sender,this) >= stake_amount); + token.transferFrom(msg.sender, this, stake_amount); + + escrow_def.last_confirmation_time = block.timestamp; + escrow_def.end_time = SafeMath.add(block.timestamp, total_time); escrow_def.escrow_status = EscrowStatus.active; isVerified = true; - EscrowVerified(DC_wallet, msg.sender, data_id); + EscrowVerified(DC_wallet, msg.sender, data_id, isVerified); } function payOut(address DC_wallet, uint data_id) public{ EscrowDefinition storage this_escrow = escrow[DC_wallet][msg.sender][data_id]; - require(this_escrow.escrow_status != EscrowStatus.initiated && - this_escrow.escrow_status != EscrowStatus.completed); + require(this_escrow.escrow_status == EscrowStatus.active); uint256 amount_to_send; if(this_escrow.escrow_status == EscrowStatus.active){ - uint end_time = block.number; + uint end_time = block.timestamp; if(end_time > this_escrow.end_time){ + uint stake_to_send = this_escrow.stake_amount; + this_escrow.stake_amount = 0; + if(stake_to_send > 0) token.transfer(msg.sender, stake_to_send); + amount_to_send = SafeMath.sub(this_escrow.token_amount, this_escrow.tokens_sent); this_escrow.escrow_status = EscrowStatus.completed; EscrowCompleted(DC_wallet, msg.sender, data_id); @@ -138,18 +188,19 @@ contract EscrowHolder { } } - function cancelEscrow(address DH_wallet, uint256 data_id) public { EscrowDefinition storage this_escrow = escrow[msg.sender][DH_wallet][data_id]; require(this_escrow.escrow_status != EscrowStatus.completed && - this_escrow.escrow_status != EscrowStatus.canceled); + this_escrow.escrow_status != EscrowStatus.canceled); uint256 amount_to_send; if(this_escrow.escrow_status == EscrowStatus.active){ - uint cancelation_time = block.number; - if(this_escrow.end_time < block.number) cancelation_time = this_escrow.end_time; + + uint cancelation_time = block.timestamp; + if(this_escrow.end_time < block.timestamp) cancelation_time = this_escrow.end_time; + amount_to_send = SafeMath.mul(this_escrow.token_amount, SafeMath.sub(this_escrow.end_time,cancelation_time)) / this_escrow.total_time; this_escrow.escrow_status = EscrowStatus.canceled; } @@ -158,18 +209,25 @@ contract EscrowHolder { this_escrow.escrow_status = EscrowStatus.completed; } - if(amount_to_send > 0) this_escrow.tokens_sent.add(amount_to_send); - - if(this_escrow.tokens_sent == this_escrow.token_amount){ - this_escrow.escrow_status = EscrowStatus.completed; + //Transfer the amount_to_send to DC + if(amount_to_send > 0) { + this_escrow.tokens_sent.add(amount_to_send); + token.transfer(msg.sender, amount_to_send); } - else { - this_escrow.escrow_status = EscrowStatus.canceled; + + //Calculate the amount to send back to DH and transfer the money back + amount_to_send = SafeMath.sub(this_escrow.token_amount, this_escrow.tokens_sent); + if(amount_to_send > 0) { + this_escrow.tokens_sent.add(amount_to_send); + token.transfer(msg.sender,amount_to_send); } - if(amount_to_send > 0) token.transfer(msg.sender, amount_to_send); + uint stake_to_send = this_escrow.stake_amount; + this_escrow.stake_amount = 0; + if(stake_to_send > 0) token.transfer(DH_wallet, stake_to_send); + + this_escrow.escrow_status = EscrowStatus.completed; EscrowCanceled(msg.sender, DH_wallet, data_id); } -} - +} \ No newline at end of file diff --git a/modules/Blockchain/Ethereum/escrow-contract/abi.json b/modules/Blockchain/Ethereum/escrow-contract/abi.json index 2128146004..e3867c6849 100644 --- a/modules/Blockchain/Ethereum/escrow-contract/abi.json +++ b/modules/Blockchain/Ethereum/escrow-contract/abi.json @@ -1,255 +1,336 @@ [ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "DC_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "data_id", - "type": "uint256" - } - ], - "name": "EscrowCompleted", - "type": "event" - }, - { - "constant": false, - "inputs": [ - { - "name": "DH_wallet", - "type": "address" - }, - { - "name": "data_id", - "type": "uint256" - } - ], - "name": "cancelEscrow", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "DH_wallet", - "type": "address" - }, - { - "name": "data_id", - "type": "uint256" - }, - { - "name": "token_amount", - "type": "uint256" - }, - { - "name": "total_time", - "type": "uint256" - } - ], - "name": "initiateEscrow", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "DC_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "data_id", - "type": "uint256" - } - ], - "name": "EscrowVerified", - "type": "event" - }, - { - "constant": false, - "inputs": [ - { - "name": "DC_wallet", - "type": "address" - }, - { - "name": "data_id", - "type": "uint256" - } - ], - "name": "payOut", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "DC_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "data_id", - "type": "uint256" - } - ], - "name": "EscrowCanceled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "DC_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "DH_wallet", - "type": "address" - }, - { - "indexed": false, - "name": "data_id", - "type": "uint256" - } - ], - "name": "EscrowInitated", - "type": "event" - }, - { - "constant": false, - "inputs": [ - { - "name": "DC_wallet", - "type": "address" - }, - { - "name": "data_id", - "type": "uint256" - }, - { - "name": "token_amount", - "type": "uint256" - }, - { - "name": "total_time", - "type": "uint256" - } - ], - "name": "verifyEscrow", - "outputs": [ - { - "name": "isVerified", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "name": "tokenAddress", - "type": "address" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "uint256" - } - ], - "name": "escrow", - "outputs": [ - { - "name": "token_amount", - "type": "uint256" - }, - { - "name": "tokens_sent", - "type": "uint256" - }, - { - "name": "last_confirmation_time", - "type": "uint256" - }, - { - "name": "end_time", - "type": "uint256" - }, - { - "name": "total_time", - "type": "uint256" - }, - { - "name": "escrow_status", - "type": "uint8" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "token", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - } + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "DH_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + } + ], + "name": "cancelEscrow", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + } + ], + "name": "EscrowCompleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + } + ], + "name": "EscrowCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + }, + { + "indexed": false, + "name": "token_amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "stake_amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "total_time", + "type": "uint256" + } + ], + "name": "EscrowInitated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + }, + { + "indexed": false, + "name": "verification_successful", + "type": "bool" + } + ], + "name": "EscrowVerified", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "DH_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "stake_amount", + "type": "uint256" + }, + { + "name": "total_time", + "type": "uint256" + } + ], + "name": "initiateEscrow", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + } + ], + "name": "payOut", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "name": "tokenAddress", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "stake_amount", + "type": "uint256" + }, + { + "name": "total_time", + "type": "uint256" + } + ], + "name": "verifyEscrow", + "outputs": [ + { + "name": "isVerified", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "escrow", + "outputs": [ + { + "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", + "type": "uint256" + }, + { + "name": "escrow_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": "token", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } ] \ No newline at end of file diff --git a/modules/Blockchain/Ethereum/escrow-contract/bytecode.txt b/modules/Blockchain/Ethereum/escrow-contract/bytecode.txt index 7fe96df927..e652f46853 100644 --- a/modules/Blockchain/Ethereum/escrow-contract/bytecode.txt +++ b/modules/Blockchain/Ethereum/escrow-contract/bytecode.txt @@ -1 +1 @@ -6060604052341561000f57600080fd5b60405160208061140383398101604052808051906020019091905050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561006757600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061134c806100b76000396000f300606060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630221038a1461007d578063048b1bd4146100bf57806382b9be1a146101015780639b5c84ab146101a7578063b1d13b0814610213578063fc0c546a14610267575b600080fd5b341561008857600080fd5b6100bd600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506102bc565b005b34156100ca57600080fd5b6100ff600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506106f0565b005b341561010c57600080fd5b610160600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610ac9565b6040518087815260200186815260200185815260200184815260200183815260200182600381111561018e57fe5b60ff168152602001965050505050505060405180910390f35b34156101b257600080fd5b6101f9600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091908035906020019091908035906020019091905050610b2c565b604051808215151515815260200191505060405180910390f35b341561021e57600080fd5b610265600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091908035906020019091908035906020019091905050610d03565b005b341561027257600080fd5b61027a611291565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000806000600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085815260200190815260200160002092506000600381111561035d57fe5b8360050160009054906101000a900460ff16600381111561037a57fe5b141580156103af575060038081111561038f57fe5b8360050160009054906101000a900460ff1660038111156103ac57fe5b14155b15156103ba57600080fd5b600160038111156103c757fe5b8360050160009054906101000a900460ff1660038111156103e457fe5b14156105125743905082600301548111156104d75761040b836000015484600101546112b6565b915060038360050160006101000a81548160ff0219169083600381111561042e57fe5b02179055507f7c536285ed58c4a6427ffae76ff5e2f308320390e247d10710b96944a531ae7f853386604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a161050d565b82600401546104f784600001546104f28487600201546112b6565b6112cf565b81151561050057fe5b0491508083600201819055505b6105ec565b610524836000015484600101546112b6565b915060038360050160006101000a81548160ff0219169083600381111561054757fe5b02179055507f7c536285ed58c4a6427ffae76ff5e2f308320390e247d10710b96944a531ae7f853386604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a15b60008211156106e95761060c82846001015461130290919063ffffffff16565b506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15156106d057600080fd5b5af115156106dd57600080fd5b50505060405180519050505b5050505050565b6000806000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020925060038081111561079057fe5b8360050160009054906101000a900460ff1660038111156107ad57fe5b141580156107e35750600260038111156107c357fe5b8360050160009054906101000a900460ff1660038111156107e057fe5b14155b15156107ee57600080fd5b600160038111156107fb57fe5b8360050160009054906101000a900460ff16600381111561081857fe5b141561088c57439050438360030154101561083557826003015490505b826004015461085584600001546108508660030154856112b6565b6112cf565b81151561085e57fe5b04915060028360050160006101000a81548160ff0219169083600381111561088257fe5b02179055506108ba565b8260000154915060038360050160006101000a81548160ff021916908360038111156108b457fe5b02179055505b60008211156108dc576108da82846001015461130290919063ffffffff16565b505b8260000154836001015414156109175760038360050160006101000a81548160ff0219169083600381111561090d57fe5b021790555061093e565b60028360050160006101000a81548160ff0219169083600381111561093857fe5b02179055505b6000821115610a23576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1515610a0a57600080fd5b5af11515610a1757600080fd5b50505060405180519050505b7fe346e1f49ea333b13c3167ec512b5461ece2524e753dc7886347aaffb5029f81338686604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a15050505050565b600160205282600052604060002060205281600052604060002060205280600052604060002060009250925050508060000154908060010154908060020154908060030154908060040154908060050160009054906101000a900460ff16905086565b60008060009150600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008681526020019081526020016000209050838160000154148015610bfc575060006003811115610bdd57fe5b8160050160009054906101000a900460ff166003811115610bfa57fe5b145b8015610c0b5750828160040154145b1515610c1657600080fd5b438160020181905550610c294384611302565b816003018190555060018160050160006101000a81548160ff02191690836003811115610c5257fe5b0217905550600191507f1eeee46bb4ebc18666dea316260f32d9af22456b54006ce107dd74e6296fb799863387604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a150949350505050565b60016003811115610d1057fe5b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085815260200190815260200160002060050160009054906101000a900460ff166003811115610db957fe5b14158015610e7b575060026003811115610dcf57fe5b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085815260200190815260200160002060050160009054906101000a900460ff166003811115610e7857fe5b14155b1515610e8657600080fd5b600082118015610e965750600081115b1515610ea157600080fd5b816000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b1515610f9157600080fd5b5af11515610f9e57600080fd5b5050506040518051905010151515610fb557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15156110ac57600080fd5b5af115156110b957600080fd5b505050604051805190505060c060405190810160405280838152602001600081526020016000815260200160008152602001828152602001600060038111156110fe57fe5b815250600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a08201518160050160006101000a81548160ff021916908360038111156111e457fe5b02179055509050507f89535c64e82723ed669f075ab5336470f637d6abf0121a65a7146b69b5903ea7338585604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a150505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008282111515156112c457fe5b818303905092915050565b600080828402905060008414806112f057508284828115156112ed57fe5b04145b15156112f857fe5b8091505092915050565b600080828401905083811015151561131657fe5b80915050929150505600a165627a7a7230582036ad1886fa9c26537f60bfb12f57536cd867365ca7efeb15c863d83a6ea43dc80029 \ No newline at end of file +608060405234801561001057600080fd5b50604051602080611a5f83398101806040528101908080519060200190929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156100af57600080fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061195f806101006000396000f30060806040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630221038a14610093578063048b1bd4146100e057806382b9be1a1461012d5780638da5cb5b146101e657806395b9df2b1461023d578063cf724ed7146102c8578063f2fde38b1461034b578063fc0c546a1461038e575b600080fd5b34801561009f57600080fd5b506100de600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506103e5565b005b3480156100ec57600080fd5b5061012b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061095d565b005b34801561013957600080fd5b50610198600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e7a565b604051808881526020018781526020018681526020018581526020018481526020018381526020018260038111156101cc57fe5b60ff16815260200197505050505050505060405180910390f35b3480156101f257600080fd5b506101fb610ee3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561024957600080fd5b506102c6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190505050610f08565b005b3480156102d457600080fd5b50610331600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190505050611567565b604051808215151515815260200191505060405180910390f35b34801561035757600080fd5b5061038c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061174e565b005b34801561039a57600080fd5b506103a36118a3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600080600080600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002093506000600381111561048757fe5b8460060160009054906101000a900460ff1660038111156104a457fe5b141580156104d957506003808111156104b957fe5b8460060160009054906101000a900460ff1660038111156104d657fe5b14155b15156104e457600080fd5b600160038111156104f157fe5b8460060160009054906101000a900460ff16600381111561050e57fe5b141561075857429150836004015482111561071d578360020154905060008460020181905550600081111561063f57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561060257600080fd5b505af1158015610616573d6000803e3d6000fd5b505050506040513d602081101561062c57600080fd5b8101908080519060200190929190505050505b610651846000015485600101546118c9565b925060038460060160006101000a81548160ff0219169083600381111561067457fe5b02179055507f7c536285ed58c4a6427ffae76ff5e2f308320390e247d10710b96944a531ae7f863387604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a1610753565b836005015461073d85600001546107388588600301546118c9565b6118e2565b81151561074657fe5b0492508184600301819055505b610832565b61076a846000015485600101546118c9565b925060038460060160006101000a81548160ff0219169083600381111561078d57fe5b02179055507f7c536285ed58c4a6427ffae76ff5e2f308320390e247d10710b96944a531ae7f863387604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a15b60008311156109555761085283856001015461191590919063ffffffff16565b50600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33856040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561091857600080fd5b505af115801561092c573d6000803e3d6000fd5b505050506040513d602081101561094257600080fd5b8101908080519060200190929190505050505b505050505050565b600080600080600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002093506003808111156109fe57fe5b8460060160009054906101000a900460ff166003811115610a1b57fe5b14158015610a51575060026003811115610a3157fe5b8460060160009054906101000a900460ff166003811115610a4e57fe5b14155b1515610a5c57600080fd5b60016003811115610a6957fe5b8460060160009054906101000a900460ff166003811115610a8657fe5b1415610afa574291504284600401541015610aa357836004015491505b8360050154610ac38560000154610abe8760040154866118c9565b6118e2565b811515610acc57fe5b04925060028460060160006101000a81548160ff02191690836003811115610af057fe5b0217905550610b28565b8360000154925060038460060160006101000a81548160ff02191690836003811115610b2257fe5b02179055505b6000831115610b4a57610b4883856001015461191590919063ffffffff16565b505b836000015484600101541415610b855760038460060160006101000a81548160ff02191690836003811115610b7b57fe5b0217905550610bac565b60028460060160006101000a81548160ff02191690836003811115610ba657fe5b02179055505b83600201549050600084600201819055506000811115610cc857600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb87836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015610c8b57600080fd5b505af1158015610c9f573d6000803e3d6000fd5b505050506040513d6020811015610cb557600080fd5b8101908080519060200190929190505050505b6000831115610dd357600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33856040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015610d9657600080fd5b505af1158015610daa573d6000803e3d6000fd5b505050506040513d6020811015610dc057600080fd5b8101908080519060200190929190505050505b7fe346e1f49ea333b13c3167ec512b5461ece2524e753dc7886347aaffb5029f81338787604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a1505050505050565b600260205282600052604060002060205281600052604060002060205280600052604060002060009250925050508060000154908060010154908060020154908060030154908060040154908060050154908060060160009054906101000a900460ff16905087565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610f6357600080fd5b60016003811115610f7057fe5b600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002060060160009054906101000a900460ff16600381111561101957fe5b141580156110db57506002600381111561102f57fe5b600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002060060160009054906101000a900460ff1660038111156110d857fe5b14155b15156110e657600080fd5b6000831180156110f65750600081115b151561110157600080fd5b82600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e88306040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b1580156111f357600080fd5b505af1158015611207573d6000803e3d6000fd5b505050506040513d602081101561121d57600080fd5b81019080805190602001909291905050501015151561123b57600080fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8730866040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561133457600080fd5b505af1158015611348573d6000803e3d6000fd5b505050506040513d602081101561135e57600080fd5b81019080805190602001909291905050505060e060405190810160405280848152602001600081526020018381526020016000815260200160008152602001828152602001600060038111156113b057fe5b815250600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000868152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c08201518160060160006101000a81548160ff021916908360038111156114a057fe5b02179055509050507f23f818acf4b173d25f3d95286be10f439ed828a237bdfaaf9f71e58af806be67868686868686604051808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001838152602001828152602001965050505050505060405180910390a1505050505050565b60008060009150600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600087815260200190815260200160002090508481600001541480156116135750838160020154145b801561164657506000600381111561162757fe5b8160060160009054906101000a900460ff16600381111561164457fe5b145b80156116555750828160050154145b151561166057600080fd5b4281600301819055506116734284611915565b816004018190555060018160060160006101000a81548160ff0219169083600381111561169c57fe5b0217905550600191507f1eeee46bb4ebc18666dea316260f32d9af22456b54006ce107dd74e6296fb799873388604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a15095945050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156117a957600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156117e557600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008282111515156118d757fe5b818303905092915050565b60008082840290506000841480611903575082848281151561190057fe5b04145b151561190b57fe5b8091505092915050565b600080828401905083811015151561192957fe5b80915050929150505600a165627a7a72305820e43f7abfc96418488ea990784e2a345732a34547ebbf6817da3a33468ea476970029 \ No newline at end of file diff --git a/modules/Blockchain/Ethereum/index.js b/modules/Blockchain/Ethereum/index.js index 63699fe010..a10be82674 100644 --- a/modules/Blockchain/Ethereum/index.js +++ b/modules/Blockchain/Ethereum/index.js @@ -2,6 +2,9 @@ const Web3 = require('web3'); const fs = require('fs'); const Transactions = require('./Transactions'); const Utilities = require('../../Utilities'); +const globalEvents = require('../../GlobalEvents'); + +const { globalEmitter } = globalEvents; const log = Utilities.getLogger(); @@ -23,7 +26,7 @@ class Ethereum { this.otContractAddress = blockchainConfig.ot_contract_address; this.tokenContractAddress = blockchainConfig.token_contract_address; this.escrowContractAddress = blockchainConfig.escrow_contract_address; - + this.biddingContractAddress = blockchainConfig.bidding_contract_address; // OT contract data const contractAbiFile = fs.readFileSync('./modules/Blockchain/Ethereum/ot-contract/abi.json'); @@ -46,9 +49,42 @@ class Ethereum { this.escrowContractAddress, ); + const biddingAbiFile = fs.readFileSync('./modules/Blockchain/Ethereum/bidding-contract/abi.json'); + this.biddingContractAbi = JSON.parse(biddingAbiFile); + this.biddingContract = new this.web3.eth.Contract( + this.biddingContractAbi, + this.biddingContractAddress, + ); + + this.contractsByName = { + BIDDING_CONTRACT: this.biddingContract, + }; + // Storing config data this.config = blockchainConfig; + this.biddingContract.events.OfferCreated() + .on('data', (event) => { + console.log(event); // same results as the optional callback above + globalEmitter.emit('eth-offer-created', event); + }) + .on('error', log.warn); + + this.biddingContract.events.OfferCanceled() + .on('data', (event) => { + console.log(event); // same results as the optional callback above + globalEmitter.emit('eth-offer-canceled', event); + }) + .on('error', log.warn); + + this.biddingContract.events.BidTaken() + .on('data', (event) => { + console.log(event); // same results as the optional callback above + globalEmitter.emit('eth-bid-taken', event); + }) + .on('error', log.warn); + + log.info('Selected blockchain: Ethereum'); } @@ -87,22 +123,18 @@ class Ethereum { } /** - * Initiating escrow for data holding on Ethereum blockchain - * @param {string} - dhWallet - * @param {number} - dataId - * @param {number} - tokenAmount - * @param {number} - totalTime + * Increase token approval for Bidding contract on Ethereum blockchain + * @param {number} tokenAmountIncrease * @returns {Promise} */ - initiateEscrow(dhWallet, dataId, tokenAmount, totalTime) { + increaseBiddingApproval(tokenAmountIncrease) { const options = { gasLimit: this.web3.utils.toHex(this.config.gas_limit), gasPrice: this.web3.utils.toHex(this.config.gas_price), - to: this.escrowContractAddress, + to: this.tokenContractAddress, }; - - log.warn('Initiating escrow'); - return this.transactions.queueTransaction(this.escrowContractAbi, 'initiateEscrow', [dhWallet, dataId, tokenAmount, totalTime], options); + log.warn('Increasing bidding approval'); + return this.transactions.queueTransaction(this.tokenContractAbi, 'increaseApproval', [this.biddingContractAddress, tokenAmountIncrease], options); } /** @@ -110,10 +142,11 @@ class Ethereum { * @param {string} - dcWallet * @param {number} - dataId * @param {number} - tokenAmount + * @param {number} - stakeAmount * @param {number} - totalTime * @returns {Promise} */ - verifyEscrow(dcWallet, dataId, tokenAmount, totalTime) { + verifyEscrow(dcWallet, dataId, tokenAmount, stakeAmount, totalTime) { const options = { gasLimit: this.web3.utils.toHex(this.config.gas_limit), gasPrice: this.web3.utils.toHex(this.config.gas_price), @@ -121,7 +154,7 @@ class Ethereum { }; log.warn('Initiating escrow'); - return this.transactions.queueTransaction(this.escrowContractAbi, 'verifyEscrow', [dcWallet, dataId, tokenAmount, totalTime], options); + return this.transactions.queueTransaction(this.escrowContractAbi, 'verifyEscrow', [dcWallet, dataId, tokenAmount, stakeAmount, Math.round(totalTime / 1000)], options); } /** @@ -154,9 +187,218 @@ class Ethereum { to: this.escrowContractAddress, }; - log.warn('Initiating escrow'); + log.warn('Initiating escrow - payOut'); return this.transactions.queueTransaction(this.escrowContractAbi, 'payOut', [dcWallet, dataId], options); } + + /** + * Creates offer for the data storing on the Ethereum blockchain. + * @param dataId Data ID of the bid + * @param nodeId KADemlia node ID of offer creator + * @param totalEscrowTime Total time of the escrow in milliseconds + * @param maxTokenAmount Maximum price per DH + * @param MinStakeAmount Minimum stake in tokens + * @param biddingTime Total time of the bid in milliseconds + * @param minNumberOfBids Number of bid required for offer to be successful + * @param dataSize Size of the data for storing in bytes + * @param ReplicationFactor Number of replications + * @returns {Promise} Return choose start-time. + */ + createOffer( + dataId, nodeId, + totalEscrowTime, + maxTokenAmount, + MinStakeAmount, + biddingTime, + minNumberOfBids, + dataSize, ReplicationFactor, + ) { + const options = { + gasLimit: this.web3.utils.toHex(this.config.gas_limit), + gasPrice: this.web3.utils.toHex(this.config.gas_price), + to: this.biddingContractAddress, + }; + + log.warn('Initiating escrow - createOffer'); + return this.transactions.queueTransaction( + this.biddingContractAbi, 'createOffer', + [dataId, this._normalizeNodeId(nodeId), + Math.round(totalEscrowTime / 1000), + maxTokenAmount, + MinStakeAmount, + Math.round(biddingTime / 1000), + minNumberOfBids, + dataSize, ReplicationFactor], options, + ); + } + + /** + * Cancel offer for data storing on Ethereum blockchain. + * @param dataId Data if of the offer. + */ + cancelOffer(dataId) { + const options = { + gasLimit: this.web3.utils.toHex(this.config.gas_limit), + gasPrice: this.web3.utils.toHex(this.config.gas_price), + to: this.biddingContractAddress, + }; + + log.warn('Initiating escrow - cancelOffer'); + return this.transactions.queueTransaction( + this.biddingContractAbi, 'cancelOffer', + [dataId], options, + ); + } + + /** + * Subscribe to a particular event + * @param contractName Ethereum contract instance + * @param event Event name + * @param eventOpts Event options (filter, range, etc.) + * @param callback Callback to be executed on success/error (callback returns stop flag) + * @param periodMills Repeating period for checking past events + * @param untilMills Subscription termination + */ + subscribeToEvent(contractName, event, eventOpts, callback, periodMills, untilMills) { + const looper = setInterval(() => { + if (untilMills < Date.now()) { + log.trace('Looper for event is going to be unsubscribed'); + clearTimeout(looper); + return; + } + this.contractsByName[contractName].getPastEvents(event, eventOpts).then((events) => { + const stop = callback(events); + if (stop) { + clearTimeout(looper); + } + }).catch((err) => { + log.error(`Failed to get past events for ${event}`); + const stop = callback(null, err); + if (stop) { + clearTimeout(looper); + } + }); + }, periodMills); + } + + /** + * Adds bid to the offer on Ethereum blockchain + * @param dcWallet Wallet of the bidder + * @param dataId ID of the data of the bid + * @param nodeId KADemlia ID of this node + * @param bidHash Hashed bid that will be revealed once revealBid() is called + * @returns {Promise} Index of the bid. + */ + addBid(dcWallet, dataId, nodeId, bidHash) { + const options = { + gasLimit: this.web3.utils.toHex(this.config.gas_limit), + gasPrice: this.web3.utils.toHex(this.config.gas_price), + to: this.biddingContractAddress, + }; + + log.warn('Initiating escrow - addBid'); + return this.transactions.queueTransaction( + this.biddingContractAbi, 'addBid', + [dcWallet, dataId, this._normalizeNodeId(nodeId), bidHash], options, + ); + } + + /** + * Cancel the bid on Ethereum blockchain + * @param dcWallet Wallet of the bidder + * @param dataId ID of the data of the bid + * @param bidIndex Index of the bid + * @returns {Promise} + */ + cancelBid(dcWallet, dataId, bidIndex) { + const options = { + gasLimit: this.web3.utils.toHex(this.config.gas_limit), + gasPrice: this.web3.utils.toHex(this.config.gas_price), + to: this.escrowContractAddress, + }; + + log.warn('Initiating escrow - cancelBid'); + return this.transactions.queueTransaction( + this.biddingContractAbi, 'cancelBid', + [dcWallet, dataId, bidIndex], options, + ); + } + + /** + * Reveals the bid of the offer + * @param dcWallet Wallet of the DC who's offer is + * @param dataId Id of the data in the offer + * @param nodeId KADemlia ID of bidder + * @param tokenAmount Amount of the token + * @param stakeAmount Amount of the stake + * @param bidIndex Index of the bid + * @returns {Promise} + */ + revealBid(dcWallet, dataId, nodeId, tokenAmount, stakeAmount, bidIndex) { + const options = { + gasLimit: this.web3.utils.toHex(this.config.gas_limit), + gasPrice: this.web3.utils.toHex(this.config.gas_price), + to: this.biddingContractAddress, + }; + + log.warn('Initiating escrow - revealBid'); + return this.transactions.queueTransaction( + this.biddingContractAbi, 'revealBid', + [dcWallet, + dataId, + this._normalizeNodeId(nodeId), tokenAmount, stakeAmount, bidIndex], options, + ); + } + + /** + * Starts choosing bids from contract escrow on Ethereum blockchain + * @param dataId ID of data of the bid + * @returns {Promise} + */ + chooseBids(dataId) { + const options = { + gasLimit: this.web3.utils.toHex(this.config.gas_limit), + gasPrice: this.web3.utils.toHex(this.config.gas_price), + to: this.biddingContractAddress, + }; + + log.warn('Initiating escrow - chooseBid'); + return this.transactions.queueTransaction( + this.biddingContractAbi, 'chooseBids', + [dataId], options, + ); + } + + /** + * + * @param dcWallet + * @param dataId + * @param bidIndex + * @returns {Promise} + */ + getBid(dcWallet, dataId, bidIndex) { + const options = { + gasLimit: this.web3.utils.toHex(this.config.gas_limit), + gasPrice: this.web3.utils.toHex(this.config.gas_price), + to: this.biddingContractAddress, + }; + + log.warn('Initiating escrow - getBid'); + return this.transactions.queueTransaction( + this.biddingContractAbi, 'getBid', + [dcWallet, dataId, bidIndex], options, + ); + } + + /** + * Normalizes Kademlia node ID + * @param nodeId Kademlia node ID + * @returns {string} Normalized node ID + * @private + */ + _normalizeNodeId(nodeId) { + return `0x${nodeId}`; + } } module.exports = Ethereum; diff --git a/modules/Challenger.js b/modules/Challenger.js index f935cf5d74..dd44cd4d43 100644 --- a/modules/Challenger.js +++ b/modules/Challenger.js @@ -18,7 +18,7 @@ function sendChallenge(challenge) { }, }; - node.ot.challengeRequest(payload, challenge.dh_id, (error, response) => { + node.ot.challengeRequest(payload, challenge.dh, (error, response) => { if (error) { log.warn(`challenge-request: failed to get answer. Error: ${error}.`); return; @@ -52,7 +52,7 @@ function intervalFunc() { if (challenges.length > 0) { challenges.forEach(challenge => sendChallenge(challenge)); } else { - log.trace('No challenges found.'); + // log.trace('No challenges found.'); } }).catch((err) => { log.error(`Failed to get unanswered challenges. Error: ${err}.`); diff --git a/modules/DCService.js b/modules/DCService.js new file mode 100644 index 0000000000..c18cf369d0 --- /dev/null +++ b/modules/DCService.js @@ -0,0 +1,167 @@ +const node = require('./Node'); +const config = require('./Config'); +const Blockchain = require('./BlockChainInstance'); + +const Utilities = require('./Utilities'); +const Models = require('../models'); + +// TODO remove below after SC intro +const SmartContractInstance = require('./temp/MockSmartContractInstance'); + +const log = Utilities.getLogger(); + +// TODO +const totalEscrowTime = 6 * 60 * 1000; +const replicationFactor = 1; +const biddingTime = 2 * 60 * 1000; +const minNumberOfBids = 1; +const minStakeAmount = 5; +const maxTokenAmount = 1000; +/** + * DC operations (handling new offers, etc.) + */ +class DCService { + static createOffer(dataId, rootHash, totalDocuments) { + Blockchain.bc.writeRootHash(dataId, rootHash).then((res) => { + log.info('Fingerprint written on blockchain'); + }).catch((e) => { + console.log('Error: ', e); + }); + + // TODO set real offer params + const offerParams = { + price: Utilities.getRandomIntRange(1, 10), + dataSizeBytes: 900, + name: `Crazy data for ${totalDocuments} documents`, + }; + + // TODO call real SC + const scId = SmartContractInstance.sc.createOffer(dataId, offerParams); + log.info(`Created offer ${scId}`); + + Models.offers.create({ + id: dataId, + data_lifespan: totalEscrowTime, + start_tender_time: Date.now(), // TODO: Problem. Actual start time is returned by SC. + tender_duration: biddingTime, + min_number_applicants: minNumberOfBids, + price_tokens: offerParams.price, + data_size_bytes: offerParams.dataSizeBytes, + replication_number: replicationFactor, + root_hash: rootHash, + max_token_amount: maxTokenAmount, + }).then((offer) => { + Blockchain.bc.createOffer( + dataId, config.identity, + totalEscrowTime, + maxTokenAmount, + minStakeAmount, + biddingTime, + minNumberOfBids, + totalDocuments, replicationFactor, + ).then((startTime) => { + log.info('Offer written to blockchain. Broadcast event.'); + node.ot.quasar.quasarPublish('bidding-broadcast-channel', { + dataId, + dcId: config.identity, + dcWallet: config.node_wallet, + totalEscrowTime, + maxTokenAmount, + minStakeAmount, + biddingTime, + minNumberOfBids, + totalDocuments, + replicationFactor, + }); + DCService.scheduleChooseBids(dataId, totalEscrowTime); + }).catch((err) => { + log.warn(`Failed to create offer. ${JSON.stringify(err)}`); + }); + }).catch((error) => { + log.error(`Failed to write offer to DB. ${error}`); + }); + } + + /** + * Schedule chose DHs + * @param dataId Data ID + * @param totalEscrowTime Total escrow time + */ + static scheduleChooseBids(dataId, totalEscrowTime) { + Models.offers.findOne({ where: { id: dataId } }).then((offerModel) => { + const offer = offerModel.get({ plain: true }); + + function chooseBids(dataId) { + log.info(`Choose bids for data ${dataId}`); + + Blockchain.bc.increaseApproval(offer.max_token_amount * offer.replication_number) + .then(() => { + Blockchain.bc.chooseBids(dataId) + .then(() => { + log.info(`Bids choose called for data ${dataId}`); + + Blockchain.bc.subscribeToEvent('BIDDING_CONTRACT', 'OfferFinalized', { + fromBlock: 0, + toBlock: 'latest', + }, (data, err) => { + if (err) { + log.error(err); + return true; + } + // filter events manually since Web3 filtering is not working + for (const event of data) { + const eventDataId = event.returnValues.data_id; + const eventDcWallet = event.returnValues.DC_wallet; + + if (Number(eventDataId) === dataId + && eventDcWallet === config.node_wallet) { + log.info(`Offer for data ${dataId} successfully finalized`); + DCService.handleFinalizedOffer(dataId); + return true; + } + } + return false; + }, 5000, Date.now() + totalEscrowTime); + }).catch((err) => { + log.warn(`Failed call choose bids for data ${dataId}. ${err}`); + }); + }).catch((err) => { + log.warn(`Failed to increase allowance. ${JSON.stringify(err)}`); + }); + } + // change time period in order to test choose bids + setTimeout(chooseBids, 2 * offer.tender_duration, dataId); + }).catch((error) => { + log.error(`Failed to get offer (data ID ${dataId}). ${error}.`); + }); + } + + /** + * Process finalized offer + * @param dataId Data ID + */ + static handleFinalizedOffer(dataId) { + Blockchain.bc.subscribeToEvent('BIDDING_CONTRACT', 'BidTaken', { + fromBlock: 0, + toBlock: 'latest', + }, (data, err) => { + if (err) { + log.error(err); + return true; + } + // filter events manually since Web3 filtering is not working + for (const event of data) { + const eventDataId = event.returnValues.data_id; + const eventDhWallet = event.returnValues.DH_wallet; + const eventDcWallet = event.returnValues.DC_wallet; + + if (Number(eventDataId) === dataId && eventDcWallet === config.node_wallet) { + log.info(`The bid is chosen for DH ${eventDhWallet} and data ${dataId}`); + } + } + return true; + }, 5000, Date.now() + 20000); + } +} + +module.exports = DCService; diff --git a/modules/DHService.js b/modules/DHService.js new file mode 100644 index 0000000000..1d9cc5e68b --- /dev/null +++ b/modules/DHService.js @@ -0,0 +1,270 @@ +const node = require('./Node'); +const config = require('./Config'); +const BN = require('bn.js'); +const abi = require('ethereumjs-abi'); +const Blockchain = require('./BlockChainInstance'); +const importer = require('./importer')(); + +const Utilities = require('./Utilities'); +const Models = require('../models'); + +const log = Utilities.getLogger(); + +/** + * DH operations (handling new offers, etc.) + */ +class DHService { + /** + * Handles new offer + * + */ + static handleOffer( + dcWallet, + dcNodeId, + dataId, + totalEscrowTime, + minStakeAmount, + dataSizeBytes, + ) { + const minPrice = parseInt(config.dh_min_price, 10); + const maxPrice = parseInt(config.dh_max_price, 10); + const maxStakeAmount = parseInt(config.dh_max_stake, 10); + const maxDataSizeBytes = parseInt(config.dh_max_data_size_bytes, 10); + + const chosenPrice = Math.round(Utilities.getRandomIntRange(minPrice, maxPrice)); + + if (minStakeAmount > maxStakeAmount) { + log.trace(`Skipping offer because of the minStakeAmount. MinStakeAmount is ${minStakeAmount}.`); + return; + } + const stake = Math.round(Utilities.getRandomIntRange(minStakeAmount, maxStakeAmount)); + + if (maxDataSizeBytes < dataSizeBytes) { + log.trace(`Skipping offer because of data size. Offer data size in bytes is ${dataSizeBytes}.`); + return; + } + + const bidHash = abi.soliditySHA3( + ['address', 'uint256', 'uint256', 'uint256'], + [config.node_wallet, new BN(config.identity, 16), new BN(`${chosenPrice}`), new BN(`${stake}`)], + ).toString('hex'); + + log.trace(`Adding a bid for DC wallet ${dcWallet} and data ID ${dataId}`); + Blockchain.bc.addBid(dcWallet, dataId, config.identity, `0x${bidHash}`) + .then((tx) => { + // Sign escrow. + Blockchain.bc.increaseBiddingApproval(stake).catch(error => log.error(`Failed to increase approval. ${error}.`)); + + Blockchain.bc.subscribeToEvent('BIDDING_CONTRACT', 'AddedBid', { + fromBlock: 0, + toBlock: 'latest', + }, (data, err) => { + if (err) { + log.error(err); + return true; + } + // filter events manually since Web3 filtering is not working + for (const event of data) { + const eventDataId = event.returnValues.data_id; + const eventDhWallet = event.returnValues.DH_wallet; + + if (Number(eventDataId) === dataId + && eventDhWallet === config.node_wallet) { + const { bidIndex } = event.returnValues; + Models.bids.create({ + bid_index: bidIndex, + price: chosenPrice, + data_id: dataId, + dc_wallet: dcWallet, + dc_id: dcNodeId, + hash: bidHash, + total_escrow_time: totalEscrowTime, + stake, + data_size_bytes: dataSizeBytes, + }).then((bid) => { + log.info(`Created new bid for import ${dataId}. Schedule reveal... `); + + DHService.scheduleRevealBid( + dcWallet, dataId, chosenPrice, + stake, bidIndex, totalEscrowTime, + ); + }).catch((err) => { + log.error(`Failed to insert new bid. ${err}`); + }); + return true; + } + } + return false; + }, 5000, Date.now() + 20000); + }).catch((err) => { + log.error(err); + }); + } + + static handleImport(data) { + Models.bids.findOne({ where: { data_id: data.data_id } }).then((bidModel) => { + // TODO: Check data before signing escrow. + const bid = bidModel.get({ plain: true }); + importer.importJSON(data) + .then(() => { + log.trace('[DH] Replication finished'); + Blockchain.bc.increaseApproval(bid.stake).then(() => { + Blockchain.bc.verifyEscrow( + bid.dc_wallet, + data.data_id, + bid.price, + bid.stake, + bid.total_escrow_time, + ).then(() => { + // TODO No need to notify DC. DC should catch event from verifyEscrow(). + node.ot.replicationFinished({ status: 'success' }, bid.dc_id); + }).catch((error) => { + log.error(`Failed to verify escrow. ${error}`); + }); + }).catch((e) => { + log.error(`Failed to verify escrow. ${e}`); + }); + }).catch((error) => { + log.error(`Failed to import data. ${error}`); + }); + }).catch((error) => { + log.error(`Couldn't find bid with data ID ${data.data_id}. ${error}.`); + }); + } + + /** + * Schedule reveal before todtalEscrowTime + * @param dcWallet DC wallet + * @param dataId Data ID + * @param price Price + * @param stake Stake + * @param bidIndex Bid indez + * @param totalEscrowTime Total escrow time + * @private + */ + static scheduleRevealBid(dcWallet, dataId, price, stake, bidIndex, totalEscrowTime) { + function revealBid(dcWallet, dataId, price, stake, bidIndex) { + Blockchain.bc.revealBid(dcWallet, dataId, config.identity, price, stake, bidIndex) + .then(() => { + log.info(`Bid revealed for import ${dataId} and DC ${dcWallet}`); + DHService.checkIfRevealed(dcWallet, dataId); + }).catch((err) => { + log.warn(`Failed to reveal bid for import ${dataId} and DC ${dcWallet}. ${JSON.stringify(err)}`); + }); + } + setTimeout( + // change time period in order to test reveal + revealBid, 2 * 60 * 1000, + dcWallet, dataId, price, stake, bidIndex, + ); + } + + /** + * Check whether bid has successfully been revealed + * @param dcWallet DH wallet + * @param dataId Data ID + */ + static checkIfRevealed(dcWallet, dataId) { + Blockchain.bc.subscribeToEvent('BIDDING_CONTRACT', 'RevealedBid', { + fromBlock: 0, + toBlock: 'latest', + }, (data, err) => { + if (err) { + log.error(err); + return true; + } + // filter events manually since Web3 filtering is not working + for (const event of data) { + const eventDataId = event.returnValues.data_id; + const eventDcWallet = event.returnValues.DC_wallet; + + if (Number(eventDataId) === dataId + && eventDcWallet === dcWallet) { + log.info(`Successfully revealed bid for data ${dataId}.`); + DHService.scheduleOfferFinalizedCheck(dataId, dcWallet); + return true; + } + } + return false; + }, 5000, Date.now() + (15 * 60 * 1000)); + } + + /** + * Schedule check whether the offer is finalized or not + * @param dataId Data ID + * @param dcWallet DC wallet + */ + static scheduleOfferFinalizedCheck(dataId, dcWallet) { + Blockchain.bc.subscribeToEvent('BIDDING_CONTRACT', 'OfferFinalized', { + fromBlock: 0, + toBlock: 'latest', + }, (data, err) => { + if (err) { + log.error(err); + return true; + } + // filter events manually since Web3 filtering is not working + for (const event of data) { + const eventDataId = event.returnValues.data_id; + const eventDcWallet = event.returnValues.DC_wallet; + + if (Number(eventDataId) === dataId + && eventDcWallet === dcWallet) { + log.info(`Offer for data ${dataId} successfully finalized. Check if the bid is chosen.`); + DHService.scheduleBidChosenCheck(dataId, dcWallet); + return true; + } + } + return false; + }, 5000, Date.now() + (15 * 60 * 1000)); + } + + /** + * Schedule check for whether the bid is chosed for the particular import + * @param dataId Data ID + * @param dcWallet DC wallet + */ + static scheduleBidChosenCheck(dataId, dcWallet) { + Blockchain.bc.subscribeToEvent('BIDDING_CONTRACT', 'BidTaken', { + fromBlock: 0, + toBlock: 'latest', + }, (data, err) => { + if (err) { + log.error(err); + return true; + } + // filter events manually since Web3 filtering is not working + for (const event of data) { + const eventDataId = event.returnValues.data_id; + const eventDhWallet = event.returnValues.DH_wallet; + const eventDcWallet = event.returnValues.DC_wallet; + + if (Number(eventDataId) === dataId + && eventDhWallet === config.node_wallet && eventDcWallet === dcWallet) { + log.info(`The bid is chosen for DC ${dcWallet} and data ${dataId}`); + + Models.bids.findOne({ where: { data_id: dataId } }).then((bidModel) => { + const bid = bidModel.get({ plain: true }); + node.ot.replicationRequest( + { + dataId, + wallet: config.node_wallet, + }, + bid.dc_id, (err) => { + if (err) { + log.warn(`Failed to send replication request ${err}`); + // TODO Cancel bid here. + } + }, + ); + }); + + return true; + } + } + return false; + }, 5000, Date.now() + (15 * 60 * 1000)); + } +} + +module.exports = DHService; diff --git a/modules/Database/Arangojs.js b/modules/Database/Arangojs.js index 9585129388..b071cebebe 100644 --- a/modules/Database/Arangojs.js +++ b/modules/Database/Arangojs.js @@ -201,6 +201,24 @@ class ArangoJS { }); }); } + + getEdgesByImportId(data_id) { + return new Promise((resolve, reject) => { + const queryString = 'FOR v IN ot_edges FILTER POSITION(v.imports, @importId, false) != false SORT v._key RETURN v'; + + if (typeof data_id !== 'number') { + data_id = parseInt(data_id, 10); + } + + const params = { importId: data_id }; + + this.runQuery(queryString, params).then((response) => { + resolve(response); + }).catch((err) => { + reject(err); + }); + }); + } } module.exports = ArangoJS; diff --git a/modules/Database/GraphStorage.js b/modules/Database/GraphStorage.js index 66029d00f4..cb90b6d7b3 100644 --- a/modules/Database/GraphStorage.js +++ b/modules/Database/GraphStorage.js @@ -188,6 +188,25 @@ class GraphStorage { } }); } + + /** + * Gets edges by import ID from the underlying database + * @param data_id Import ID + * @returns {Promise} + */ + getEdgesByImportId(data_id) { + return new Promise((resolve, reject) => { + if (!this.db) { + reject(Error('Not connected to graph database')); + } else { + this.db.getEdgesByImportId(data_id).then((result) => { + resolve(result); + }).catch((err) => { + reject(err); + }); + } + }); + } } module.exports = GraphStorage; diff --git a/modules/EventHandlers.js b/modules/EventHandlers.js index d54b93b14b..d7c9d5d91a 100644 --- a/modules/EventHandlers.js +++ b/modules/EventHandlers.js @@ -1,7 +1,6 @@ const globalEvents = require('./GlobalEvents'); const importer = require('./importer')(); const Storage = require('./Database/SystemStorage'); -const Blockchain = require('./BlockChainInstance'); const Graph = require('./Graph'); const GraphStorage = require('./GraphStorageInstance'); const replication = require('./DataReplication'); @@ -9,10 +8,17 @@ const deasync = require('deasync-promise'); const config = require('./Config'); const ProductInstance = require('./ProductInstance'); const Challenge = require('./Challenge'); +const challenger = require('./Challenger'); const node = require('./Node'); +const Utilities = require('./Utilities'); +const DHService = require('./DHService'); +const DCService = require('./DCService'); + +// TODO remove below after SC intro +const SmartContractInstance = require('./temp/MockSmartContractInstance'); const { globalEmitter } = globalEvents; -const log = require('./Utilities').getLogger(); +const log = Utilities.getLogger(); globalEmitter.on('import-request', (data) => { importer.importXML(data.filepath, (response) => { @@ -33,71 +39,82 @@ globalEmitter.on('gs1-import-request', (data) => { data_id, root_hash, total_documents, - vertices, - edges, } = response; deasync(Storage.connect()); Storage.runSystemQuery('INSERT INTO data_info (data_id, root_hash, import_timestamp, total_documents) values(?, ? , ? , ?)', [data_id, root_hash, total_documents]) .then((data_info) => { - Blockchain.bc.writeRootHash(data_id, root_hash).then((res) => { - log.info('Fingerprint written on blockchain'); - }).catch((e) => { - // console.log('Error: ', e); - }); - - const [contactId, contact] = node.ot.getNearestNeighbour(); - Graph.encryptVertices( - contact.wallet, - contactId, - vertices, - Storage, - ).then((encryptedVertices) => { - log.info('[DC] Preparing to enter sendPayload'); - const data = {}; - data.vertices = vertices; - data.edges = edges; - data.data_id = data_id; - data.encryptedVertices = encryptedVertices; - replication.sendPayload(data).then(() => { - log.info('[DC] Payload sent'); - }); - }).catch((e) => { - console.log(e); - }); + DCService.createOffer(data_id, root_hash, total_documents); }); }).catch((e) => { console.log(e); }); }); -globalEmitter.on('replication-request', (data, response) => { +globalEmitter.on('replication-request', (request, response) => { + log.trace('replication-request received'); -}); + let price; + let importId; + const { dataId } = request.params.message; + const { wallet } = request.contact[1]; + // const bid = SmartContractInstance.sc.getBid(dataId, request.contact[0]); -globalEmitter.on('payload-request', (request, response) => { - importer.importJSON(request.params.message.payload) - .then(() => { - log.warn('[DH] Replication finished'); - response.send({ - message: 'replication-finished', - status: 'success', - }, (err) => { - if (err) { - log.error('payload-request: failed to send reply', err); - } + if (dataId) { + // TODO: decouple import ID from data id or load it from database. + importId = dataId; + // ({ price } = bid); + } + + if (!importId || !wallet) { + const errorMessage = 'Asked replication without providing offer ID or wallet not found.'; + log.warn(errorMessage); + response.send({ status: 'fail', error: errorMessage }); + return; + } + + const verticesPromise = GraphStorage.db.getVerticesByImportId(importId); + const edgesPromise = GraphStorage.db.getEdgesByImportId(importId); + + Promise.all([verticesPromise, edgesPromise]).then((values) => { + const vertices = values[0]; + const edges = values[1]; + + Graph.encryptVertices( + wallet, + request.contact[0], + vertices, + Storage, + ).then((encryptedVertices) => { + log.info('[DC] Preparing to enter sendPayload'); + const data = {}; + /* eslint-disable-next-line */ + data.contact = request.contact[0]; + data.vertices = vertices; + data.edges = edges; + data.data_id = dataId; + data.encryptedVertices = encryptedVertices; + replication.sendPayload(data).then(() => { + log.info('[DC] Payload sent'); }); + }).catch((e) => { + console.log(e); }); + }); + + response.send({ status: 'succes' }); +}); + +globalEmitter.on('payload-request', (request) => { + log.trace(`payload-request arrived from ${request.contact[0]}`); + DHService.handleImport(request.params.message.payload); // TODO doktor: send fail in case of fail. }); -globalEmitter.on('replication-finished', (status, response) => { +globalEmitter.on('replication-finished', (status) => { log.warn('Notified of finished replication, preparing to start challenges'); - - if (status === 'success') { - // TODO doktor: start challenging - } + challenger.startChallenging(); }); globalEmitter.on('kad-challenge-request', (request, response) => { @@ -124,3 +141,107 @@ globalEmitter.on('kad-challenge-request', (request, response) => { }); }); +/** + * Handles bidding-broadcast on the DH side + */ +globalEmitter.on('bidding-broadcast', (message) => { + log.info('bidding-broadcast received'); + + const { + dataId, + dcId, + dcWallet, + totalEscrowTime, + minStakeAmount, + totalDocuments, + } = message; + + DHService.handleOffer( + dcWallet, + dcId, + dataId, + totalEscrowTime, + minStakeAmount, + totalDocuments, // TODO think about it + ); +}); + +globalEmitter.on('offer-ended', (message) => { + const { scId } = message; + + log.info(`Offer ${scId} has ended.`); + + // TODO: Trigger escrow to end bidding and notify chosen. + const bids = SmartContractInstance.sc.choose(scId); + + bids.forEach((bid) => { + console.log(bid); + node.ot.biddingWon( + { dataId: scId }, + bid.dhId, (error) => { + if (error) { + log.warn(error); + } + }, + ); + }); +}); + + +globalEmitter.on('kad-bidding-won', (message) => { + log.info('Wow I won bidding. Let\'s get into it.'); + + const { dataId } = message.params.message; + + // Now request data to check validity of offer. + + const dcId = SmartContractInstance.sc.getDcForBid(dataId); + + + node.ot.replicationRequest({ dataId }, dcId, (err) => { + if (err) { + log.warn(err); + } + }); +}); + +globalEmitter.on('eth-offer-created', (event) => { + log.info('eth-offer-created'); + // ( DC_wallet, DC_node_id, data_id, total_escrow_time, min_stake_amount, data_size); + + const { + DC_wallet, + DC_node_id, + data_id, + total_escrow_time, + min_stake_amount, + data_size, + } = event.returnValues; + + DHService.handleOffer( + DC_wallet, + DC_node_id, + data_id, + total_escrow_time, + min_stake_amount, + data_size, + ); +}); + +globalEmitter.on('eth-offer-canceled', (event) => { + log.info('eth-offer-canceled'); +}); + +globalEmitter.on('eth-bid-taken', (event) => { + log.info('eth-bid-taken'); + + const { + DC_wallet, + DC_node_id, + data_id, + total_escrow_time, + min_stake_amount, + data_size, + } = event.returnValues; +}); + diff --git a/modules/Network.js b/modules/Network.js index d2f6429411..78ad30cc35 100644 --- a/modules/Network.js +++ b/modules/Network.js @@ -9,23 +9,24 @@ const config = require('./Config'); const async = require('async'); const deasync = require('deasync-promise'); const fs = require('fs'); -var node = require('./Node'); +const node = require('./Node'); const NetworkUtilities = require('./NetworkUtilities'); const utilities = require('./Utilities'); const globalEvents = require('./GlobalEvents'); -const { globalEmitter } = globalEvents; -var ns = {}; +// TODO remove below after SC intro +const SmartContractInstance = require('./temp/MockSmartContractInstance'); +const { globalEmitter } = globalEvents; +let ns = {}; /** * DHT module (Kademlia) */ - class Network { /** - * Setup options and construct a node - */ + * Setup options and construct a node + */ constructor() { kadence.constants.T_RESPONSETIMEOUT = 20000; kadence.constants.K = 20; @@ -37,19 +38,17 @@ class Network { this.index = parseInt(config.child_derivation_index, 10); // Initialize private extended key - utilities.createPrivateExtendedKey(kadence); } /** - * Starts the node - * @return {Promise} - */ + * Starts the node + * @return {Promise} + */ async start() { - // Check config + // Check config ns.verifyConfiguration(config); - log.info('Checking SSL certificate'); deasync(ns.setSelfSignedCertificate(config)); @@ -57,15 +56,11 @@ class Network { this.xprivkey = fs.readFileSync(`${__dirname}/../keys/${config.private_extended_key_path}`).toString(); this.identity = new kadence.eclipse.EclipseIdentity(this.xprivkey, this.index); - log.info('Checking the identity'); - // Check if identity is valid ? - ns.checkIdentity(this.identity, this.xprivkey); + ns.checkIdentity(this.identity, this.xprivkey); // Check if identity is valid const { childkey, parentkey } = ns.getIdentityKeys(this.xprivkey); - - this.identity = kadence.utils.toPublicKeyHash(childkey.publicKey) - .toString('hex'); + this.identity = kadence.utils.toPublicKeyHash(childkey.publicKey).toString('hex'); log.notify(`My identity: ${this.identity}`); config.identity = this.identity; @@ -73,9 +68,22 @@ class Network { log.info('Initializing network'); // Initialize public contact data - const contact = this.setContact(config, parentkey); + const contact = { + hostname: config.node_rpc_ip, + protocol: 'https:', + port: parseInt(config.node_port, 10), + xpub: parentkey.publicExtendedKey, + index: parseInt(config.child_derivation_index, 10), + agent: kadence.version.protocol, + wallet: config.node_wallet, + }; - const transport = this._HTTPSTransport(); + const key = fs.readFileSync(`${__dirname}/../keys/${config.ssl_keypath}`); + const cert = fs.readFileSync(`${__dirname}/../keys/${config.ssl_certificate_path}`); + const ca = config.ssl_authority_paths.map(fs.readFileSync); + + // Initialize transport adapter + const transport = new kadence.HTTPSTransport({ key, cert, ca }); // Initialize protocol implementation node.ot = new kadence.KademliaNode({ @@ -92,9 +100,11 @@ class Network { } }), }); - log.info('Starting OT Node...'); + // Enable Quasar plugin used for publish/subscribe mechanism + node.ot.quasar = node.ot.plugin(kadence.quasar()); + // We use Hashcash for relaying messages to prevent abuse and make large scale // DoS and spam attacks cost prohibitive node.ot.hashcash = node.ot.plugin(kadence.hashcash({ @@ -103,40 +113,14 @@ class Network { })); log.info('Hashcash initialised'); - // Use Tor for an anonymous overlay if (parseInt(config.onion_enabled, 10)) { - // noinspection JSAnnotator - kadence.constants.T_RESPONSETIMEOUT = 20000; - node.ot.onion = node.plugin(kadence.onion({ - dataDirectory: `${__dirname}/../data/hidden_service`, - virtualPort: config.onion_virtual_port, - localMapping: `127.0.0.1:${config.node_port}`, - torrcEntries: { - CircuitBuildTimeout: 10, - KeepalivePeriod: 60, - NewCircuitPeriod: 60, - NumEntryGuards: 8, - Log: 'notice stdout', - }, - passthroughLoggingEnabled: 1, - })); + this.enableOnion(); } if (parseInt(config.traverse_nat_enabled, 10)) { - log.info('Trying NAT traversal'); - node.ot.traverse = node.ot.plugin(kadence.traverse([ - new kadence.traverse.UPNPStrategy({ - mappingTtl: parseInt(config.traverse_port_forward_ttl, 10), - publicPort: parseInt(node.ot.contact.port, 10), - }), - new kadence.traverse.NATPMPStrategy({ - mappingTtl: parseInt(config.traverse_port_forward_ttl, 10), - publicPort: parseInt(node.ot.contact.port, 10), - }), - ])); + this.enableNatTraversal(); } - - this.registerRoutes(); + this._registerRoutes(); // Use verbose logging if enabled if (parseInt(config.verbose_logging, 10)) { @@ -149,8 +133,7 @@ class Network { } node.ot.listen(parseInt(config.node_port, 10), () => { - log.notify('OT Node listening ' + - `at https://${node.ot.contact.hostname}:${node.ot.contact.port}`); + log.notify(`OT Node listening at https://${node.ot.contact.hostname}:${node.ot.contact.port}`); ns.registerControlInterface(config, node); if (parseInt(config.solve_hashes, 10)) { @@ -160,62 +143,56 @@ class Network { async.retry({ times: Infinity, interval: 60000, - }, done => this.joinNetwork(done), (err, entry) => { + }, done => this._joinNetwork(done), (err, entry) => { if (err) { log.error(err.message); process.exit(1); } - log.info(`Connected to network via ${entry[0]} ` + - `(https://${entry[1].hostname}:${entry[1].port})`); + log.info(`Connected to network via ${entry[0]} (https://${entry[1].hostname}:${entry[1].port})`); log.info(`Discovered ${node.ot.router.size} peers from seed`); }); }); } - - /** - * Set contact data - * @param config - * @param parentkey - * @return {{hostname: *, protocol: string, port: number, xpub: *, index: number, agent: string}} - */ - setContact(config, parentkey) { - const contact = { - hostname: config.node_rpc_ip, - protocol: 'https:', - port: parseInt(config.node_port, 10), - xpub: parentkey.publicExtendedKey, - index: parseInt(config.child_derivation_index, 10), - agent: kadence.version.protocol, - wallet: config.node_wallet, - }; - return contact; + static enableNatTraversal() { + log.info('Trying NAT traversal'); + node.ot.traverse = node.ot.plugin(kadence.traverse([ + new kadence.traverse.UPNPStrategy({ + mappingTtl: parseInt(config.traverse_port_forward_ttl, 10), + publicPort: parseInt(node.ot.contact.port, 10), + }), + new kadence.traverse.NATPMPStrategy({ + mappingTtl: parseInt(config.traverse_port_forward_ttl, 10), + publicPort: parseInt(node.ot.contact.port, 10), + }), + ])); } - /** - * HTTPS Transport - * @param config - * @return {HTTPSTransport} - * @private - */ - _HTTPSTransport() { - const key = fs.readFileSync(`${__dirname}/../keys/${config.ssl_keypath}`); - const cert = fs.readFileSync(`${__dirname}/../keys/${config.ssl_certificate_path}`); - const ca = config.ssl_authority_paths.map(fs.readFileSync); - - // Initialize transport adapter - const transport = new kadence.HTTPSTransport({ key, cert, ca }); - - return transport; + static enableOnion() { + log.info('Use Tor for an anonymous overlay'); + kadence.constants.T_RESPONSETIMEOUT = 20000; + node.ot.onion = node.plugin(kadence.onion({ + dataDirectory: `${__dirname}/../data/hidden_service`, + virtualPort: config.onion_virtual_port, + localMapping: `127.0.0.1:${config.node_port}`, + torrcEntries: { + CircuitBuildTimeout: 10, + KeepalivePeriod: 60, + NewCircuitPeriod: 60, + NumEntryGuards: 8, + Log: 'notice stdout', + }, + passthroughLoggingEnabled: 1, + })); } /** - * Join network - */ - joinNetwork(callback) { - const peers = config.network_bootstrap_nodes; - if (peers.length === 0) { + * Join network if there are some of the bootstrap nodes + */ + _joinNetwork(callback) { + const bootstrapNodes = config.network_bootstrap_nodes; + if (bootstrapNodes.length === 0) { log.warn('No bootstrap seeds provided and no known profiles'); log.trace('Running in seed mode (waiting for connections)'); return node.ot.router.events.once('add', (identity) => { @@ -225,12 +202,12 @@ class Network { node.ot.router.getContactByNodeId(identity), ]), ]; - this.joinNetwork(callback); + this._joinNetwork(callback); }); } - log.info(`Joining network from ${peers.length} seeds`); - async.detectSeries(peers, (url, done) => { + log.info(`Joining network from ${bootstrapNodes.length} seeds`); + async.detectSeries(bootstrapNodes, (url, done) => { const contact = kadence.utils.parseContactURL(url); node.ot.join(contact, (err) => { done(null, (!err) && node.ot.router.size >= 1); @@ -241,7 +218,6 @@ class Network { callback(new Error('Failed to join network')); } else { log.important('Joined the network'); - /* eslint-disable-next-line no-undef */ const contact = kadence.utils.parseContactURL(result); config.dh = contact; callback(null, contact); @@ -249,7 +225,16 @@ class Network { }); } - registerRoutes() { + /** + * Register Kademlia routes and error handlers + */ + _registerRoutes() { + node.ot.quasar.quasarSubscribe('bidding-broadcast-channel', (message, err) => { + log.info('New bidding offer received'); + globalEmitter.emit('bidding-broadcast', message); + }); + + // add payload-request route node.ot.use('payload-request', (request, response, next) => { log.info('payload-request received'); globalEmitter.emit('payload-request', request, response); @@ -257,6 +242,21 @@ class Network { status: 'OK', }); }); + + // add payload-request error handler + node.ot.use('payload-request', (err, request, response, next) => { + response.send({ + error: 'payload-request error', + }); + }); + + // add replication-request route + node.ot.use('replication-request', (request, response, next) => { + log.info('replication-request received'); + globalEmitter.emit('replication-request', request); + }); + + // add replication-finished route node.ot.use('replication-finished', (request, response, next) => { log.info('replication-finished received'); globalEmitter.emit('replication-finished', request); @@ -264,42 +264,137 @@ class Network { status: 'OK', }); }); + + // add replication-finished error handler + node.ot.use('replication-finished', (err, request, response, next) => { + response.send({ + error: 'replication-finished error', + }); + }); + + // add challenge-request route node.ot.use('challenge-request', (request, response, next) => { log.info('challenge-request received'); globalEmitter.emit('kad-challenge-request', request, response); }); + // add challenge-request error handler + node.ot.use('challenge-request', (err, request, response, next) => { + response.send({ + error: 'challenge-request error', + }); + }); - node.ot.use('payload-request', (err, request, response, next) => { + // TODO remove temp add bid route + node.ot.use('add-bid', (request, response, next) => { + log.info('add-bid'); + const { offerId, bid } = request.params.message; + [bid.dhId] = request.contact; + SmartContractInstance.sc.addDhBid(offerId, bid); response.send({ - error: 'error', + status: 'OK', }); }); - node.ot.use('replication-finished', (err, request, response, next) => { + + // TODO remove temp add bid route + node.ot.use('add-bid', (err, request, response, next) => { + log.error('add-bid failed'); response.send({ - error: 'error', + error: 'add-bid error', }); }); + + // add kad-bidding-won route + node.ot.use('kad-bidding-won', (request, response, next) => { + log.info('kad-bidding-won received'); + globalEmitter.emit('kad-bidding-won', request, response); + }); + + // add kad-bidding-won error handler + node.ot.use('kad-bidding-won', (err, request, response, next) => { + response.send({ + error: 'kad-bidding-won error', + }); + }); + + // creates Kadence plugin for RPC calls node.ot.plugin((node) => { + /** + * Helper method for getting nearest contact (used for testing purposes only) + * @returns {*} + */ node.getNearestNeighbour = () => [...node.router.getClosestContactsToKey(this.identity).entries()].shift(); - node.payloadRequest = (message, callback) => { - const neighbor = [ - ...node.router.getClosestContactsToKey(this.identity).entries(), - ].shift(); - node.send('payload-request', { message }, neighbor, callback); + /** + * Gets contact by ID + * @param contactId Contact ID + * @returns {{"{": Object}|Array} + */ + node.getContact = contactId => node.router.getContactByNodeId(contactId); + + /** + * Sends payload request to DH + * @param message Payload to be sent + * @param contactId KADemlia contact ID to be sent to + * @param callback Response/Error callback + */ + node.payloadRequest = (message, contactId, callback) => { + const contact = node.getContact(contactId); + node.send('payload-request', { message }, [contactId, contact], callback); + }; + + /** + * Sends replication request to the DC + * @param message + * @param contactId KADemlia contact ID to be sent to + * @param callback + */ + node.replicationRequest = (message, contactId, callback) => { + const contact = node.getContact(contactId); + node.send('replication-request', { message }, [contactId, contact], callback); }; - node.replicationFinished = (message, callback) => { + /** + * Sends replication finished direct message + * @param message Payload to be sent + * @param contactId KADemlia contact ID to be sent to + * @param callback Response/Error callback + */ + node.replicationFinished = (message, contactId, callback) => { + const contact = node.getContact(contactId); + node.send('replication-finished', { message }, [contactId, contact], callback); }; + + /** + * Sends challenge request direct message + * @param message Payload to be sent + * @param contactId KADemlia contact ID to be sent to + * @param callback Response/Error callback + */ node.challengeRequest = (message, contactId, callback) => { - const contact = node.router.getContactByNodeId(contactId); + const contact = node.getContact(contactId); node.send('challenge-request', { message }, [contactId, contact], callback); }; + + /** + * Sends add bid to DC + * TODO remove after SC intro + * @param message Payload to be sent + * @param contactId KADemlia contact ID to be sent to + * @param callback Response/Error callback + */ + node.addBid = (message, contactId, callback) => { + const contact = node.getContact(contactId); + node.send('add-bid', { message }, [contactId, contact], callback); + }; + + node.biddingWon = (message, contactId, callback) => { + const contact = node.getContact(contactId); + node.send('kad-bidding-won', { message }, [contactId, contact], callback); + }; }); - // Define a global custom error handler rule, simply by including the `err` - // argument in the handler + // Define a global custom error handler rule node.ot.use((err, request, response, next) => { response.send({ error: err.message }); }); diff --git a/modules/blockchain_interface/ethereum/contracts/bidding_abi.json b/modules/blockchain_interface/ethereum/contracts/bidding_abi.json new file mode 100644 index 0000000000..5fa68c90be --- /dev/null +++ b/modules/blockchain_interface/ethereum/contracts/bidding_abi.json @@ -0,0 +1,379 @@ +[ + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "node_id", + "type": "uint256" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "stake_amount", + "type": "uint256" + }, + { + "name": "bidIndex", + "type": "uint256" + } + ], + "name": "revealBid", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "data_id", + "type": "uint256" + } + ], + "name": "chooseBids", + "outputs": [ + { + "name": "chosen_data_holders", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "bid", + "outputs": [ + { + "name": "bid_hash", + "type": "bytes32" + }, + { + "name": "DH_wallet", + "type": "address" + }, + { + "name": "node_id", + "type": "uint256" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "stake_amount", + "type": "uint256" + }, + { + "name": "active", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "node_id", + "type": "uint256" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "stake_amount", + "type": "uint256" + } + ], + "name": "addBid", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "bidIndex", + "type": "uint256" + } + ], + "name": "cancelBid", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "offer", + "outputs": [ + { + "name": "total_escrow_time", + "type": "uint256" + }, + { + "name": "min_stake_amount", + "type": "uint256" + }, + { + "name": "reveal_start_time", + "type": "uint256" + }, + { + "name": "choose_start_time", + "type": "uint256" + }, + { + "name": "min_number_of_bids", + "type": "uint256" + }, + { + "name": "data_size", + "type": "uint256" + }, + { + "name": "replication_factor", + "type": "uint256" + }, + { + "name": "number_of_bids", + "type": "uint256" + }, + { + "name": "total_bid_token_amount", + "type": "uint256" + }, + { + "name": "random_number_seed", + "type": "uint256" + }, + { + "name": "active", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "total_escrow_time", + "type": "uint256" + }, + { + "name": "min_stake_amount", + "type": "uint256" + }, + { + "name": "bidding_phase_time", + "type": "uint256" + }, + { + "name": "min_number_of_bids", + "type": "uint256" + }, + { + "name": "data_size", + "type": "uint256" + }, + { + "name": "replication_factor", + "type": "uint256" + } + ], + "name": "createOffer", + "outputs": [ + { + "name": "choose_start_time", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "data_id", + "type": "uint256" + } + ], + "name": "cancelOffer", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "token", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "tokenAddress", + "type": "address" + }, + { + "name": "escrowAddress", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + }, + { + "indexed": false, + "name": "total_escrow_time", + "type": "uint256" + }, + { + "indexed": false, + "name": "min_stake_amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "data_size", + "type": "uint256" + } + ], + "name": "OfferCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + } + ], + "name": "OfferCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "DC_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "DH_wallet", + "type": "address" + }, + { + "indexed": false, + "name": "data_id", + "type": "uint256" + } + ], + "name": "BidTaken", + "type": "event" + } +] diff --git a/modules/temp/MockSmartContract.js b/modules/temp/MockSmartContract.js new file mode 100644 index 0000000000..d5eb5d2232 --- /dev/null +++ b/modules/temp/MockSmartContract.js @@ -0,0 +1,59 @@ +const globalEvents = require('../GlobalEvents'); +const log = require('../Utilities').getLogger(); + +const { globalEmitter } = globalEvents; + +class MockSmartContract { + constructor() { + this.offers = []; + this.dhs = []; + this.dcs = []; + + // TODO: Check for already send offers and bids in database and start timers. + } + + /** + * Creates offer + */ + createOffer(dataId, offer) { + this.offers[dataId] = offer; + this.dhs[dataId] = []; + + // simulate timed event + // setTimeout(() => { + // log.info('Offer ended'); + // globalEmitter.emit('offer-ended', { + // scId: dataId, + // }); + // }, 15 * 1000); + return dataId; + } + + /** + * Adds single DH bid + */ + addDhBid(dataId, dhBid) { + this.dhs[dataId].push(dhBid); + } + + addDcOffer(dataId, dcId) { + this.dcs[dataId] = dcId; + } + + /** + * Choose some of the DHs + */ + choose(dataId) { + return this.dhs[dataId]; + } + + getDcForBid(dataId) { + return this.dcs[dataId]; + } + + getBid(dataId, dhId) { + return this.dhs[dataId].find(element => element.dhId === dhId); + } +} + +module.exports = MockSmartContract; diff --git a/modules/temp/MockSmartContractInstance.js b/modules/temp/MockSmartContractInstance.js new file mode 100644 index 0000000000..7805edaaa0 --- /dev/null +++ b/modules/temp/MockSmartContractInstance.js @@ -0,0 +1,12 @@ +let instance = null; + +class MockSmartContractInstance { + constructor() { + if (!instance) { + instance = this; + } + return instance; + } +} + +module.exports = new MockSmartContractInstance(); diff --git a/ot-node.js b/ot-node.js index 62326c57fa..287a4b17c3 100644 --- a/ot-node.js +++ b/ot-node.js @@ -17,6 +17,8 @@ const BCInstance = require('./modules/BlockChainInstance'); const GraphInstance = require('./modules/GraphInstance'); const GSInstance = require('./modules/GraphStorageInstance'); const ProductInstance = require('./modules/ProductInstance'); +const MockSmartContract = require('./modules/temp/MockSmartContract'); +const MockSmartContractInstance = require('./modules/temp/MockSmartContractInstance'); require('./modules/EventHandlers'); var pjson = require('./package.json'); @@ -73,6 +75,7 @@ class OTNode { BCInstance.bc = new Blockchain(selectedBlockchain); ProductInstance.p = new Product(); GraphInstance.g = new Graph(); + MockSmartContractInstance.sc = new MockSmartContract(); // Connecting to graph database try { diff --git a/seeders/20180407223548-blockchain_data.js b/seeders/20180407223548-blockchain_data.js index edd14d7f29..64e796c693 100644 --- a/seeders/20180407223548-blockchain_data.js +++ b/seeders/20180407223548-blockchain_data.js @@ -14,7 +14,8 @@ module.exports = { gas_price: '5000000000', ot_contract_address: '0x8126e8a02bcae11a631d4413b9bd4f01f14e045d', token_contract_address: '0x98d9a611ad1b5761bdc1daac42c48e4d54cf5882', - escrow_contract_address: '0xa6563b91684a63dff511e8d5b06189e2b9ef291d', + escrow_contract_address: '0x4757bce64f70d099549e086558c73bd7d2150a59', + bidding_contract_address: '0xfb868a872eadc14665f1eeb4b333c0dbc713596c', rpc_node_host: 'https://rinkeby.infura.io/1WRiEqAQ9l4SW6fGdiDt', rpc_node_port: '80', wallet_address: process.env.NODE_WALLET, diff --git a/seeders/20180420143224-node-config.js b/seeders/20180420143224-node-config.js new file mode 100644 index 0000000000..a559981947 --- /dev/null +++ b/seeders/20180420143224-node-config.js @@ -0,0 +1,22 @@ +require('dotenv').config(); + +module.exports = { + up: (queryInterface, Sequelize) => queryInterface.bulkInsert('node_config', [{ + key: 'dh_min_price', + value: '1000', + }, + { + key: 'dh_max_price', + value: '10000', + }, + { + key: 'dh_max_data_size_bytes', + value: '1000000', + }, + { + key: 'dh_max_stake', + value: '10000', + }, + ], {}), + down: (queryInterface, Sequelize) => queryInterface.bulkDelete('node_config', null, {}), +};