{"action":"created","comment":{"url":"https://api.github.com/repos/OriginTrail/ot-node/pulls/comments/205049642","pull_request_review_id":140241099,"id":205049642,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwNTA0OTY0Mg==","diff_hunk":"@@ -0,0 +1,648 @@\n+/* eslint-disable no-unused-expressions */\n+const {\n+    describe, before, beforeEach, after, afterEach, it,\n+} = require('mocha');\n+const { expect } = require('chai');\n+const Ganache = require('ganache-core');\n+const Web3 = require('web3');\n+const awilix = require('awilix');\n+const Blockchain = require('../../modules/Blockchain');\n+const solc = require('solc');\n+const fs = require('fs');\n+const Umzug = require('umzug');\n+const BN = require('bn.js');\n+const sleep = require('sleep-async')().Promise;\n+\n+const Utilities = require('../../modules/Utilities');\n+const ImportUtilities = require('../../modules/ImportUtilities');\n+const Models = require('../../models');\n+const DCService = require('../../modules/DCService');\n+\n+const sequelizeConfig = require('./../../config/config.json').development;\n+\n+// Thanks solc. At least this works!\n+// This removes solc's overzealous uncaughtException event handler.\n+// process.removeAllListeners('uncaughtException');\n+\n+describe('Protocol tests', () => {\n+// Global functions.\n+    function recreateDatabase() {\n+        fs.closeSync(fs.openSync(sequelizeConfig.storage, 'w'));\n+\n+        const migrator = new Umzug({\n+            storage: 'sequelize',\n+            storageOptions: {\n+                sequelize: Models.sequelize,\n+                tableName: 'migrations',\n+            },\n+            logging: Utilities.getLogger().debug,\n+            migrations: {\n+                params: [Models.sequelize.getQueryInterface(), Models.Sequelize],\n+                path: `${__dirname}/../../migrations`,\n+                pattern: /^\\d+[\\w-]+\\.js$/,\n+            },\n+        });\n+\n+        const seeder = new Umzug({\n+            storage: 'sequelize',\n+            storageOptions: {\n+                sequelize: Models.sequelize,\n+                tableName: 'seeders',\n+            },\n+            logging: Utilities.getLogger().debug,\n+            migrations: {\n+                params: [Models.sequelize.getQueryInterface(), Models.Sequelize],\n+                path: `${__dirname}/../../seeders`,\n+                pattern: /^\\d+[\\w-]+\\.js$/,\n+            },\n+        });\n+\n+        return Models.sequelize.authenticate().then(() => migrator.up().then(() => seeder.up()));\n+    }\n+\n+    function deployContract(\n+        web3,\n+        contract,\n+        contractData,\n+        constructorArguments,\n+        from,\n+    ) {\n+        let deploymentReceipt;\n+        let contractInstance;\n+        return new Promise((accept, reject) => {\n+            contract.deploy({\n+                data: contractData,\n+                arguments: constructorArguments,\n+            })\n+                .send({ from, gas: 6000000 })\n+                .on('receipt', (receipt) => {\n+                    deploymentReceipt = receipt;\n+                })\n+                .on('error', error => reject(error))\n+                .then((instance) => {\n+                    // TODO: ugly workaround - not sure why this is necessary.\n+                    if (!instance._requestManager.provider) {\n+                        instance._requestManager.setProvider(web3.eth._provider);\n+                    }\n+                    contractInstance = instance;\n+                    accept([deploymentReceipt, contractInstance]);\n+                });\n+        });\n+    }\n+\n+    class MockEmitter {\n+        constructor() {\n+            this.events = [];\n+        }\n+\n+        emit(eventName, data) {\n+            this.events.push({ eventName, data });\n+        }\n+\n+        getEvents() {\n+            return this.events;\n+        }\n+    }\n+\n+    class MockGraphStorage {\n+        constructor(importId, vertices, edges) {\n+            this.imports = {};\n+            if (!importId && !vertices && !edges) {\n+                this.imports[importId] = { vertices, edges };\n+            }\n+        }\n+\n+        findEdgesByImportId(importId) {\n+            return this.imports[importId].vertices;\n+        }\n+\n+        findVerticesByImportId(importId) {\n+            return this.imports[importId].edgeds;\n+        }\n+    }\n+\n+    class MockNetwork {\n+        constructor() {\n+            this.requests = [];\n+        }\n+\n+        kademlia() {\n+            return this;\n+        }\n+\n+        sendVerifyImportResponse(message, nodeId) {\n+            this.requests.push({ message, nodeId });\n+        }\n+    }\n+\n+    class MockRemoteControl {\n+        writingRootHash() {}\n+        initializingOffer() {}\n+        biddingStarted() {}\n+        cancelingOffer() {}\n+        biddingComplete() {}\n+        choosingBids() {}\n+        bidChosen() {}\n+        offerFinalized() {}\n+        dcErrorHandling() {}\n+    }\n+\n+    class TestNode {\n+        constructor(identity, wallet, walletPrivateKey) {\n+            this.identity = identity;\n+            this.wallet = wallet;\n+            this.walletPrivateKey = walletPrivateKey;\n+        }\n+\n+        getIdentityExtended() {\n+            return `0x${this.identity}000000000000000000000000`;\n+        }\n+\n+        get blockchain() {\n+            return this.container.resolve('blockchain');\n+        }\n+\n+        get dcService() {\n+            return this.container.resolve('dcService');\n+        }\n+\n+        get graphStorage() {\n+            return this.container.resolve('graphStorage');\n+        }\n+\n+        get network() {\n+            return this.container.resolve('network');\n+        }\n+\n+        get logger() {\n+            return this.container.resolve('logger');\n+        }\n+    }\n+\n+    function waitForEvent(contract, eventName, importId, timeout = 5000) {\n+        return new Promise((accept, reject) => {\n+            const startTime = Date.now();\n+            const timerHandle = setInterval(async () => {\n+                if (Date.now() - startTime > timeout) {\n+                    reject(Error(`Event ${eventName} (${importId}) didn't arrive.`));\n+                    return;\n+                }\n+\n+                const events = await contract.getPastEvents('allEvents', {\n+                    fromBlock: 0,\n+                    toBlock: 'latest',\n+                });\n+\n+                for (let i = 0; i < events.length; i += 1) {\n+                    const event = events[i];\n+                    if (event.event === eventName && !importId) {\n+                        clearTimeout(timerHandle);\n+                        accept(event);\n+                        return;\n+                    } else if (\n+                        event.event === eventName && importId &&\n+                        event.returnValues.import_id === importId\n+                    ) {\n+                        clearTimeout(timerHandle);\n+                        accept(event);\n+                        return;\n+                    }\n+                }\n+            }, 1000);\n+        });\n+    }\n+\n+    const accountPrivateKeys = [\n+        '3cf97be6177acdd12796b387f58f84f177d0fe20d8558004e8db9a41cf90392a',\n+        '1e60c8e9aa35064cd2eaa4c005bda2b76ef1a858feebb6c8e131c472d16f9740',\n+        '2c26a937a1b8b20762e2e578899b98fd48b6ab2f8798cd03ccef2bee865c2c54',\n+        'a76e13d35326f5e06d20655d0edb2f60b8863280fabf8e3f0b1210cf0bb72eec',\n+        'd96876d0711ed11781efe0c04c95716c2e0acabc4eba418516d76be808a2fc54',\n+        '6be9ea24e3c2adf0ac4c6705b445827a57c80e6fefa10df3f480da8aa2c523a4',\n+        '6627e24e68bca3b29c548789aead92b48c0f4ce669842ff7e18ca356429b804c',\n+        '1e3bae753e15ee5e6e2548105b53736a3db7304ac7681d00c77caca0b848b0ba',\n+        '4bc5744a30e928d162ca580f9a034dfac7edc0415e0b9ddc2d221a155f6ec4ff',\n+        '03c5646544ea8e47174ac98e3b97338c486860897e31333318ee62d19e5ea118',\n+    ];\n+\n+    const ganacheProvider =\n+        Ganache.provider({\n+            accounts: [\n+                { secretKey: `0x${accountPrivateKeys[0]}`, balance: Web3.utils.toWei('100', 'ether') },\n+                { secretKey: `0x${accountPrivateKeys[1]}`, balance: Web3.utils.toWei('100', 'ether') },\n+                { secretKey: `0x${accountPrivateKeys[2]}`, balance: Web3.utils.toWei('100', 'ether') },\n+                { secretKey: `0x${accountPrivateKeys[3]}`, balance: Web3.utils.toWei('100', 'ether') },\n+                { secretKey: `0x${accountPrivateKeys[4]}`, balance: Web3.utils.toWei('100', 'ether') },\n+                { secretKey: `0x${accountPrivateKeys[5]}`, balance: Web3.utils.toWei('100', 'ether') },\n+                { secretKey: `0x${accountPrivateKeys[6]}`, balance: Web3.utils.toWei('100', 'ether') },\n+                { secretKey: `0x${accountPrivateKeys[7]}`, balance: Web3.utils.toWei('100', 'ether') },\n+                { secretKey: `0x${accountPrivateKeys[8]}`, balance: Web3.utils.toWei('100', 'ether') },\n+                { secretKey: `0x${accountPrivateKeys[9]}`, balance: Web3.utils.toWei('100', 'ether') },\n+            ],\n+        });\n+    // new Web3.providers.HttpProvider('http://localhost:7545');\n+\n+    const web3 = new Web3(ganacheProvider); // Used for deployment and is bound to accounts[7].\n+    let accounts;\n+    let tokenContractData;\n+    let tokenContractAbi;\n+    let tokenContract;\n+    let tokenInstance;\n+    let tokenDeploymentReceipt;\n+    const tokenSource = fs.readFileSync('./modules/Blockchain/Ethereum/contracts/TracToken.sol', 'utf8');\n+    let escrowContractData;\n+    let escrowContractAbi;\n+    let escrowContract;\n+    let escrowInstance;\n+    let escrowDeploymentReceipt;\n+    const escrowSource = fs.readFileSync('./modules/Blockchain/Ethereum/contracts/Escrow.sol', 'utf8');\n+    let readingContractData;\n+    let readingContractAbi;\n+    let readingContract;\n+    let readingInstance;\n+    let readingDeploymentReceipt;\n+    const readingSource = fs.readFileSync('./modules/Blockchain/Ethereum/contracts/Reading.sol', 'utf8');\n+    let biddingContractData;\n+    let biddingContractAbi;\n+    let biddingContract;\n+    let biddingInstance;\n+    let biddingDeploymentReceipt;\n+    const biddingSource = fs.readFileSync('./modules/Blockchain/Ethereum/contracts/Bidding.sol', 'utf8');\n+    let otFingerprintContractData;\n+    let otFingerprintContractAbi;\n+    let otFingerprintContract;\n+    let otFingerprintInstance;\n+    let otFingerprintDeploymentReceipt;\n+    const otFingerprintSource = fs.readFileSync('./modules/Blockchain/Ethereum/contracts/OTFingerprintStore.sol', 'utf8');\n+\n+    const log = Utilities.getLogger();\n+    const testNodes = [];\n+    let testNode1;\n+    let testNode2;\n+    let testNode3;\n+\n+    before('Compile smart contracts source', async function compile() {\n+        this.timeout(20000);\n+\n+        accounts = await web3.eth.getAccounts();\n+\n+        testNodes.push(\n+            new TestNode('d55b78943898105a0d1cddb140f8aeef6d81cfe0', accounts[0], accountPrivateKeys[0]),\n+            new TestNode('f796e0c221ceef14a3cf9fbd8b995c2a0001fd7d', accounts[1], accountPrivateKeys[1]),\n+            new TestNode('f8896b195f56040cbbb97f5c1d862a91e1dbc2b1', accounts[2], accountPrivateKeys[2]),\n+        );\n+\n+        [testNode1, testNode2, testNode3] = testNodes;\n+\n+        let compileResult = solc.compile({ sources: { 'TracToken.sol': tokenSource } }, 1);\n+        tokenContractData = `0x${compileResult.contracts['TracToken.sol:TracToken'].bytecode}`;\n+        tokenContractAbi = JSON.parse(compileResult.contracts['TracToken.sol:TracToken'].interface);\n+        tokenContract = new web3.eth.Contract(tokenContractAbi);\n+\n+        compileResult = solc.compile({ sources: { 'Escrow.sol': escrowSource } }, 1);\n+        escrowContractData = `0x${compileResult.contracts['Escrow.sol:EscrowHolder'].bytecode}`;\n+        escrowContractAbi = JSON.parse(compileResult.contracts['Escrow.sol:EscrowHolder'].interface);\n+        escrowContract = new web3.eth.Contract(escrowContractAbi);\n+\n+        compileResult = solc.compile({ sources: { 'Reading.sol': readingSource } }, 1);\n+        readingContractData = `0x${compileResult.contracts['Reading.sol:Reading'].bytecode}`;\n+        readingContractAbi = JSON.parse(compileResult.contracts['Reading.sol:Reading'].interface);\n+        readingContract = new web3.eth.Contract(readingContractAbi);\n+\n+        compileResult = solc.compile({ sources: { 'Bidding.sol': biddingSource } }, 1);\n+        biddingContractData = `0x${compileResult.contracts['Bidding.sol:Bidding'].bytecode}`;\n+        biddingContractAbi = JSON.parse(compileResult.contracts['Bidding.sol:Bidding'].interface);\n+        biddingContract = new web3.eth.Contract(biddingContractAbi);\n+\n+        compileResult = solc.compile({ sources: { 'OTFingerprintStore.sol': otFingerprintSource } }, 1);\n+        otFingerprintContractData = `0x${compileResult.contracts['OTFingerprintStore.sol:OTFingerprintStore'].bytecode}`;\n+        otFingerprintContractAbi = JSON.parse(compileResult.contracts['OTFingerprintStore.sol:OTFingerprintStore'].interface);\n+        otFingerprintContract = new web3.eth.Contract(otFingerprintContractAbi);\n+    });\n+\n+    beforeEach('Deploy new contracts', async function deploy() {\n+        this.timeout(15000);\n+        [tokenDeploymentReceipt, tokenInstance] = await deployContract(\n+            web3, tokenContract, tokenContractData,\n+            [accounts[7], accounts[8], accounts[9]], accounts[7],\n+        );\n+        [escrowDeploymentReceipt, escrowInstance] = await deployContract(\n+            web3, escrowContract, escrowContractData,\n+            [tokenInstance._address], accounts[7],\n+        );\n+        [readingDeploymentReceipt, readingInstance] = await deployContract(\n+            web3, readingContract, readingContractData,\n+            [escrowInstance._address], accounts[7],\n+        );\n+        [biddingDeploymentReceipt, biddingInstance] = await deployContract(\n+            web3, biddingContract, biddingContractData,\n+            [\n+                tokenInstance._address,\n+                escrowInstance._address,\n+                readingInstance._address,\n+            ], accounts[7],\n+        );\n+        [otFingerprintDeploymentReceipt, otFingerprintInstance] = await deployContract(\n+            web3, otFingerprintContract, otFingerprintContractData,\n+            undefined, accounts[7],\n+        );\n+\n+        await escrowInstance.methods.setBidding(biddingInstance._address)\n+            .send({ from: accounts[7], gas: 3000000 })\n+            .on('error', console.error);\n+        await escrowInstance.methods.setReading(readingInstance._address)\n+            .send({ from: accounts[7], gas: 3000000 })\n+            .on('error', console.error);\n+        await readingInstance.methods.setBidding(biddingInstance._address)\n+            .send({ from: accounts[7], gas: 3000000 })\n+            .on('error', console.error);\n+        await readingInstance.methods.transferOwnership(escrowInstance._address)\n+            .send({ from: accounts[7], gas: 3000000 })\n+            .on('error', console.error);\n+        await escrowInstance.methods.transferOwnership(biddingInstance._address)\n+            .send({ from: accounts[7], gas: 3000000 })\n+            .on('error', console.error);\n+\n+        // Deploy tokens.\n+        const amountToMint = '50000000000000000000000000'; // 5e25\n+        const amounts = [];\n+        const recipients = [];\n+        for (let i = 0; i < accounts.length; i += 1) {\n+            amounts.push(amountToMint);\n+            recipients.push(accounts[i]);\n+        }\n+        await tokenInstance.methods.mintMany(recipients, amounts)\n+            .send({ from: accounts[7], gas: 3000000 })\n+            .on('error', console.error);\n+\n+        await tokenInstance.methods.finishMinting()\n+            .send({ from: accounts[7], gas: 3000000 })\n+            .on('error', console.error);\n+    });\n+\n+    beforeEach('Recreate database', () => recreateDatabase());\n+\n+    beforeEach('Register container and build objects', () => {\n+        // DCService depends on: blockchain, challenger, graphStorage and logger.\n+\n+        testNodes.forEach((testNode) => {\n+            const config = {\n+                node_wallet: testNode.wallet,\n+                identity: testNode.identity,\n+                blockchain: {\n+                    blockchain_title: 'Ethereum',\n+                    wallet_address: testNode.wallet,\n+                    wallet_private_key: testNode.walletPrivateKey,\n+                    ot_contract_address: otFingerprintInstance._address,\n+                    token_contract_address: tokenInstance._address,\n+                    escrow_contract_address: escrowInstance._address,\n+                    bidding_contract_address: biddingInstance._address,\n+                    reading_contract_address: readingInstance._address,\n+                    gas_limit: 800000,\n+                    gas_price: 5000000000,\n+                },\n+                total_escrow_time_in_milliseconds: '60000',\n+                max_token_amount_per_dh: '1000000000000000000000', // 1e22 == 10000 tokens\n+                dh_min_stake_amount: '100000000000000000', // 1e18 == 1 token\n+                dh_min_reputation: '0',\n+            };\n+\n+            const nodeWeb3 = new Web3(ganacheProvider);\n+\n+            const container = awilix.createContainer({\n+                injectionMode: awilix.InjectionMode.PROXY,\n+            });\n+\n+            container.register({\n+                emitter: awilix.asValue(new MockEmitter()),\n+                config: awilix.asValue(config),\n+                web3: awilix.asValue(nodeWeb3),\n+                blockchain: awilix.asClass(Blockchain).singleton(),\n+                network: awilix.asClass(MockNetwork).singleton(),\n+                graphStorage: awilix.asValue(new MockGraphStorage()),\n+                challenger: awilix.asValue({ startChallennodeWeb3ging: () => { log.info('start challenging.'); } }),\n+                logger: awilix.asValue(log),\n+                dcService: awilix.asClass(DCService),\n+                remoteControl: awilix.asClass(MockRemoteControl),\n+            });\n+\n+            const blockchain = container.resolve('blockchain');\n+            const dcService = container.resolve('dcService');\n+\n+            testNode.container = container;\n+        });\n+\n+        // Let only first node listen to events.\n+        // TODO\n+        // Set event listener\n+        function listenBlockchainEvents(blockchain) {\n+            const delay = 500;\n+            let working = false;\n+            let deadline = Date.now();\n+            return setInterval(() => {\n+                if (!working && Date.now() > deadline) {\n+                    working = true;\n+                    blockchain.getAllPastEvents('BIDDING_CONTRACT');\n+                    blockchain.getAllPastEvents('READING_CONTRACT');\n+                    blockchain.getAllPastEvents('ESCROW_CONTRACT');\n+                    deadline = Date.now() + delay;\n+                    working = false;\n+                }\n+            }, 500);\n+        }\n+\n+        testNode1.eventListener = listenBlockchainEvents(testNode1.blockchain);\n+    });\n+\n+    afterEach('Unregister container', async () => {\n+        testNodes.forEach((testNode) => {\n+            if (testNode.container) {\n+                testNode.container.dispose(); // Promise.\n+                testNode.container = undefined;\n+            }\n+\n+            if (testNode.eventListener) {\n+                clearInterval(testNode.eventListener);\n+            }\n+        });\n+    });\n+\n+    it('should successfully create profile', async function createProfile() {\n+        this.timeout(10000);\n+\n+        let profileInfo = await testNode1.blockchain.getProfile(testNode1.wallet);\n+        expect(profileInfo.active).to.be.false;\n+\n+        await testNode1.blockchain.createProfile(testNode1.identity, 2, '1', '1', '100000');\n+\n+        profileInfo = await testNode1.blockchain.getProfile(testNode1.wallet);\n+        expect(profileInfo.active).to.be.true;\n+\n+        const events = await biddingInstance.getPastEvents('allEvents', {\n+            fromBlock: 0,\n+            toBlock: 'latest',\n+        });\n+\n+        expect(events).to.have.lengthOf(1);\n+        expect(events[0].event).to.equal('ProfileCreated');\n+        expect(events[0].returnValues).to.have.property('wallet').that.deep.equals(testNode1.wallet);\n+        expect(events[0].returnValues).to.have.property('node_id').that.deep.equals(testNode1.getIdentityExtended());\n+    });\n+\n+    describe('DC replication', () => {\n+        const vertices = [","path":"test/protocol/protocol.test.js","position":493,"original_position":493,"commit_id":"43ff27cb5217bcd18e813bd45c31164c7b539da0","original_commit_id":"43ff27cb5217bcd18e813bd45c31164c7b539da0","user":{"login":"kipliklotrika","id":955080,"node_id":"MDQ6VXNlcjk1NTA4MA==","avatar_url":"https://avatars3.githubusercontent.com/u/955080?v=4","gravatar_id":"","url":"https://api.github.com/users/kipliklotrika","html_url":"https://github.com/kipliklotrika","followers_url":"https://api.github.com/users/kipliklotrika/followers","following_url":"https://api.github.com/users/kipliklotrika/following{/other_user}","gists_url":"https://api.github.com/users/kipliklotrika/gists{/gist_id}","starred_url":"https://api.github.com/users/kipliklotrika/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kipliklotrika/subscriptions","organizations_url":"https://api.github.com/users/kipliklotrika/orgs","repos_url":"https://api.github.com/users/kipliklotrika/repos","events_url":"https://api.github.com/users/kipliklotrika/events{/privacy}","received_events_url":"https://api.github.com/users/kipliklotrika/received_events","type":"User","site_admin":false},"body":"Agree. Currently they're here for the demo purpose only. Same logic I'd apply for all mocking classes.","created_at":"2018-07-25T09:55:49Z","updated_at":"2018-07-25T09:55:56Z","html_url":"https://github.com/OriginTrail/ot-node/pull/403#discussion_r205049642","pull_request_url":"https://api.github.com/repos/OriginTrail/ot-node/pulls/403","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/OriginTrail/ot-node/pulls/comments/205049642"},"html":{"href":"https://github.com/OriginTrail/ot-node/pull/403#discussion_r205049642"},"pull_request":{"href":"https://api.github.com/repos/OriginTrail/ot-node/pulls/403"}},"in_reply_to_id":205035475},"pull_request":{"url":"https://api.github.com/repos/OriginTrail/ot-node/pulls/403","id":203548900,"node_id":"MDExOlB1bGxSZXF1ZXN0MjAzNTQ4OTAw","html_url":"https://github.com/OriginTrail/ot-node/pull/403","diff_url":"https://github.com/OriginTrail/ot-node/pull/403.diff","patch_url":"https://github.com/OriginTrail/ot-node/pull/403.patch","issue_url":"https://api.github.com/repos/OriginTrail/ot-node/issues/403","number":403,"state":"open","locked":false,"title":"Base for protocol testing","user":{"login":"kipliklotrika","id":955080,"node_id":"MDQ6VXNlcjk1NTA4MA==","avatar_url":"https://avatars3.githubusercontent.com/u/955080?v=4","gravatar_id":"","url":"https://api.github.com/users/kipliklotrika","html_url":"https://github.com/kipliklotrika","followers_url":"https://api.github.com/users/kipliklotrika/followers","following_url":"https://api.github.com/users/kipliklotrika/following{/other_user}","gists_url":"https://api.github.com/users/kipliklotrika/gists{/gist_id}","starred_url":"https://api.github.com/users/kipliklotrika/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kipliklotrika/subscriptions","organizations_url":"https://api.github.com/users/kipliklotrika/orgs","repos_url":"https://api.github.com/users/kipliklotrika/repos","events_url":"https://api.github.com/users/kipliklotrika/events{/privacy}","received_events_url":"https://api.github.com/users/kipliklotrika/received_events","type":"User","site_admin":false},"body":"A proposition for protocol tests based from middleware point of view. The idea is to have a running blockchain in the background while protocol's services like DC, DH and DV services can be tested during normal workflow.","created_at":"2018-07-24T14:34:42Z","updated_at":"2018-07-25T09:55:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a56ae41b8837f1f08215d31b06e41fa1cbb844d8","assignee":null,"assignees":[],"requested_reviewers":[{"login":"schrink","id":2532619,"node_id":"MDQ6VXNlcjI1MzI2MTk=","avatar_url":"https://avatars0.githubusercontent.com/u/2532619?v=4","gravatar_id":"","url":"https://api.github.com/users/schrink","html_url":"https://github.com/schrink","followers_url":"https://api.github.com/users/schrink/followers","following_url":"https://api.github.com/users/schrink/following{/other_user}","gists_url":"https://api.github.com/users/schrink/gists{/gist_id}","starred_url":"https://api.github.com/users/schrink/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/schrink/subscriptions","organizations_url":"https://api.github.com/users/schrink/orgs","repos_url":"https://api.github.com/users/schrink/repos","events_url":"https://api.github.com/users/schrink/events{/privacy}","received_events_url":"https://api.github.com/users/schrink/received_events","type":"User","site_admin":false},{"login":"simonovic86","id":6579789,"node_id":"MDQ6VXNlcjY1Nzk3ODk=","avatar_url":"https://avatars0.githubusercontent.com/u/6579789?v=4","gravatar_id":"","url":"https://api.github.com/users/simonovic86","html_url":"https://github.com/simonovic86","followers_url":"https://api.github.com/users/simonovic86/followers","following_url":"https://api.github.com/users/simonovic86/following{/other_user}","gists_url":"https://api.github.com/users/simonovic86/gists{/gist_id}","starred_url":"https://api.github.com/users/simonovic86/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/simonovic86/subscriptions","organizations_url":"https://api.github.com/users/simonovic86/orgs","repos_url":"https://api.github.com/users/simonovic86/repos","events_url":"https://api.github.com/users/simonovic86/events{/privacy}","received_events_url":"https://api.github.com/users/simonovic86/received_events","type":"User","site_admin":false},{"login":"Kuki145","id":33048701,"node_id":"MDQ6VXNlcjMzMDQ4NzAx","avatar_url":"https://avatars2.githubusercontent.com/u/33048701?v=4","gravatar_id":"","url":"https://api.github.com/users/Kuki145","html_url":"https://github.com/Kuki145","followers_url":"https://api.github.com/users/Kuki145/followers","following_url":"https://api.github.com/users/Kuki145/following{/other_user}","gists_url":"https://api.github.com/users/Kuki145/gists{/gist_id}","starred_url":"https://api.github.com/users/Kuki145/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Kuki145/subscriptions","organizations_url":"https://api.github.com/users/Kuki145/orgs","repos_url":"https://api.github.com/users/Kuki145/repos","events_url":"https://api.github.com/users/Kuki145/events{/privacy}","received_events_url":"https://api.github.com/users/Kuki145/received_events","type":"User","site_admin":false},{"login":"branarakic","id":33914812,"node_id":"MDQ6VXNlcjMzOTE0ODEy","avatar_url":"https://avatars0.githubusercontent.com/u/33914812?v=4","gravatar_id":"","url":"https://api.github.com/users/branarakic","html_url":"https://github.com/branarakic","followers_url":"https://api.github.com/users/branarakic/followers","following_url":"https://api.github.com/users/branarakic/following{/other_user}","gists_url":"https://api.github.com/users/branarakic/gists{/gist_id}","starred_url":"https://api.github.com/users/branarakic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/branarakic/subscriptions","organizations_url":"https://api.github.com/users/branarakic/orgs","repos_url":"https://api.github.com/users/branarakic/repos","events_url":"https://api.github.com/users/branarakic/events{/privacy}","received_events_url":"https://api.github.com/users/branarakic/received_events","type":"User","site_admin":false},{"login":"alexveljkovic","id":35335520,"node_id":"MDQ6VXNlcjM1MzM1NTIw","avatar_url":"https://avatars0.githubusercontent.com/u/35335520?v=4","gravatar_id":"","url":"https://api.github.com/users/alexveljkovic","html_url":"https://github.com/alexveljkovic","followers_url":"https://api.github.com/users/alexveljkovic/followers","following_url":"https://api.github.com/users/alexveljkovic/following{/other_user}","gists_url":"https://api.github.com/users/alexveljkovic/gists{/gist_id}","starred_url":"https://api.github.com/users/alexveljkovic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexveljkovic/subscriptions","organizations_url":"https://api.github.com/users/alexveljkovic/orgs","repos_url":"https://api.github.com/users/alexveljkovic/repos","events_url":"https://api.github.com/users/alexveljkovic/events{/privacy}","received_events_url":"https://api.github.com/users/alexveljkovic/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":824035339,"node_id":"MDU6TGFiZWw4MjQwMzUzMzk=","url":"https://api.github.com/repos/OriginTrail/ot-node/labels/enhancement","name":"enhancement","color":"a2eeef","default":true},{"id":824035340,"node_id":"MDU6TGFiZWw4MjQwMzUzNDA=","url":"https://api.github.com/repos/OriginTrail/ot-node/labels/help%20wanted","name":"help wanted","color":"008672","default":true}],"milestone":null,"commits_url":"https://api.github.com/repos/OriginTrail/ot-node/pulls/403/commits","review_comments_url":"https://api.github.com/repos/OriginTrail/ot-node/pulls/403/comments","review_comment_url":"https://api.github.com/repos/OriginTrail/ot-node/pulls/comments{/number}","comments_url":"https://api.github.com/repos/OriginTrail/ot-node/issues/403/comments","statuses_url":"https://api.github.com/repos/OriginTrail/ot-node/statuses/43ff27cb5217bcd18e813bd45c31164c7b539da0","head":{"label":"OriginTrail:feature/protocol-unit-tests","ref":"feature/protocol-unit-tests","sha":"43ff27cb5217bcd18e813bd45c31164c7b539da0","user":{"login":"OriginTrail","id":33917872,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMzOTE3ODcy","avatar_url":"https://avatars2.githubusercontent.com/u/33917872?v=4","gravatar_id":"","url":"https://api.github.com/users/OriginTrail","html_url":"https://github.com/OriginTrail","followers_url":"https://api.github.com/users/OriginTrail/followers","following_url":"https://api.github.com/users/OriginTrail/following{/other_user}","gists_url":"https://api.github.com/users/OriginTrail/gists{/gist_id}","starred_url":"https://api.github.com/users/OriginTrail/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OriginTrail/subscriptions","organizations_url":"https://api.github.com/users/OriginTrail/orgs","repos_url":"https://api.github.com/users/OriginTrail/repos","events_url":"https://api.github.com/users/OriginTrail/events{/privacy}","received_events_url":"https://api.github.com/users/OriginTrail/received_events","type":"Organization","site_admin":false},"repo":{"id":119876311,"node_id":"MDEwOlJlcG9zaXRvcnkxMTk4NzYzMTE=","name":"ot-node","full_name":"OriginTrail/ot-node","owner":{"login":"OriginTrail","id":33917872,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMzOTE3ODcy","avatar_url":"https://avatars2.githubusercontent.com/u/33917872?v=4","gravatar_id":"","url":"https://api.github.com/users/OriginTrail","html_url":"https://github.com/OriginTrail","followers_url":"https://api.github.com/users/OriginTrail/followers","following_url":"https://api.github.com/users/OriginTrail/following{/other_user}","gists_url":"https://api.github.com/users/OriginTrail/gists{/gist_id}","starred_url":"https://api.github.com/users/OriginTrail/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OriginTrail/subscriptions","organizations_url":"https://api.github.com/users/OriginTrail/orgs","repos_url":"https://api.github.com/users/OriginTrail/repos","events_url":"https://api.github.com/users/OriginTrail/events{/privacy}","received_events_url":"https://api.github.com/users/OriginTrail/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/OriginTrail/ot-node","description":"OriginTrail network node","fork":false,"url":"https://api.github.com/repos/OriginTrail/ot-node","forks_url":"https://api.github.com/repos/OriginTrail/ot-node/forks","keys_url":"https://api.github.com/repos/OriginTrail/ot-node/keys{/key_id}","collaborators_url":"https://api.github.com/repos/OriginTrail/ot-node/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/OriginTrail/ot-node/teams","hooks_url":"https://api.github.com/repos/OriginTrail/ot-node/hooks","issue_events_url":"https://api.github.com/repos/OriginTrail/ot-node/issues/events{/number}","events_url":"https://api.github.com/repos/OriginTrail/ot-node/events","assignees_url":"https://api.github.com/repos/OriginTrail/ot-node/assignees{/user}","branches_url":"https://api.github.com/repos/OriginTrail/ot-node/branches{/branch}","tags_url":"https://api.github.com/repos/OriginTrail/ot-node/tags","blobs_url":"https://api.github.com/repos/OriginTrail/ot-node/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/OriginTrail/ot-node/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/OriginTrail/ot-node/git/refs{/sha}","trees_url":"https://api.github.com/repos/OriginTrail/ot-node/git/trees{/sha}","statuses_url":"https://api.github.com/repos/OriginTrail/ot-node/statuses/{sha}","languages_url":"https://api.github.com/repos/OriginTrail/ot-node/languages","stargazers_url":"https://api.github.com/repos/OriginTrail/ot-node/stargazers","contributors_url":"https://api.github.com/repos/OriginTrail/ot-node/contributors","subscribers_url":"https://api.github.com/repos/OriginTrail/ot-node/subscribers","subscription_url":"https://api.github.com/repos/OriginTrail/ot-node/subscription","commits_url":"https://api.github.com/repos/OriginTrail/ot-node/commits{/sha}","git_commits_url":"https://api.github.com/repos/OriginTrail/ot-node/git/commits{/sha}","comments_url":"https://api.github.com/repos/OriginTrail/ot-node/comments{/number}","issue_comment_url":"https://api.github.com/repos/OriginTrail/ot-node/issues/comments{/number}","contents_url":"https://api.github.com/repos/OriginTrail/ot-node/contents/{+path}","compare_url":"https://api.github.com/repos/OriginTrail/ot-node/compare/{base}...{head}","merges_url":"https://api.github.com/repos/OriginTrail/ot-node/merges","archive_url":"https://api.github.com/repos/OriginTrail/ot-node/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/OriginTrail/ot-node/downloads","issues_url":"https://api.github.com/repos/OriginTrail/ot-node/issues{/number}","pulls_url":"https://api.github.com/repos/OriginTrail/ot-node/pulls{/number}","milestones_url":"https://api.github.com/repos/OriginTrail/ot-node/milestones{/number}","notifications_url":"https://api.github.com/repos/OriginTrail/ot-node/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/OriginTrail/ot-node/labels{/name}","releases_url":"https://api.github.com/repos/OriginTrail/ot-node/releases{/id}","deployments_url":"https://api.github.com/repos/OriginTrail/ot-node/deployments","created_at":"2018-02-01T18:29:15Z","updated_at":"2018-07-24T19:33:47Z","pushed_at":"2018-07-25T09:01:11Z","git_url":"git://github.com/OriginTrail/ot-node.git","ssh_url":"git@github.com:OriginTrail/ot-node.git","clone_url":"https://github.com/OriginTrail/ot-node.git","svn_url":"https://github.com/OriginTrail/ot-node","homepage":"https://origintrail.io","size":66125,"stargazers_count":45,"watchers_count":45,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10,"mirror_url":null,"archived":false,"open_issues_count":9,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":10,"open_issues":9,"watchers":45,"default_branch":"develop"}},"base":{"label":"OriginTrail:develop","ref":"develop","sha":"4aef58e9a84461e4dc8ad9066071180ad700e4e2","user":{"login":"OriginTrail","id":33917872,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMzOTE3ODcy","avatar_url":"https://avatars2.githubusercontent.com/u/33917872?v=4","gravatar_id":"","url":"https://api.github.com/users/OriginTrail","html_url":"https://github.com/OriginTrail","followers_url":"https://api.github.com/users/OriginTrail/followers","following_url":"https://api.github.com/users/OriginTrail/following{/other_user}","gists_url":"https://api.github.com/users/OriginTrail/gists{/gist_id}","starred_url":"https://api.github.com/users/OriginTrail/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OriginTrail/subscriptions","organizations_url":"https://api.github.com/users/OriginTrail/orgs","repos_url":"https://api.github.com/users/OriginTrail/repos","events_url":"https://api.github.com/users/OriginTrail/events{/privacy}","received_events_url":"https://api.github.com/users/OriginTrail/received_events","type":"Organization","site_admin":false},"repo":{"id":119876311,"node_id":"MDEwOlJlcG9zaXRvcnkxMTk4NzYzMTE=","name":"ot-node","full_name":"OriginTrail/ot-node","owner":{"login":"OriginTrail","id":33917872,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMzOTE3ODcy","avatar_url":"https://avatars2.githubusercontent.com/u/33917872?v=4","gravatar_id":"","url":"https://api.github.com/users/OriginTrail","html_url":"https://github.com/OriginTrail","followers_url":"https://api.github.com/users/OriginTrail/followers","following_url":"https://api.github.com/users/OriginTrail/following{/other_user}","gists_url":"https://api.github.com/users/OriginTrail/gists{/gist_id}","starred_url":"https://api.github.com/users/OriginTrail/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OriginTrail/subscriptions","organizations_url":"https://api.github.com/users/OriginTrail/orgs","repos_url":"https://api.github.com/users/OriginTrail/repos","events_url":"https://api.github.com/users/OriginTrail/events{/privacy}","received_events_url":"https://api.github.com/users/OriginTrail/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/OriginTrail/ot-node","description":"OriginTrail network node","fork":false,"url":"https://api.github.com/repos/OriginTrail/ot-node","forks_url":"https://api.github.com/repos/OriginTrail/ot-node/forks","keys_url":"https://api.github.com/repos/OriginTrail/ot-node/keys{/key_id}","collaborators_url":"https://api.github.com/repos/OriginTrail/ot-node/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/OriginTrail/ot-node/teams","hooks_url":"https://api.github.com/repos/OriginTrail/ot-node/hooks","issue_events_url":"https://api.github.com/repos/OriginTrail/ot-node/issues/events{/number}","events_url":"https://api.github.com/repos/OriginTrail/ot-node/events","assignees_url":"https://api.github.com/repos/OriginTrail/ot-node/assignees{/user}","branches_url":"https://api.github.com/repos/OriginTrail/ot-node/branches{/branch}","tags_url":"https://api.github.com/repos/OriginTrail/ot-node/tags","blobs_url":"https://api.github.com/repos/OriginTrail/ot-node/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/OriginTrail/ot-node/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/OriginTrail/ot-node/git/refs{/sha}","trees_url":"https://api.github.com/repos/OriginTrail/ot-node/git/trees{/sha}","statuses_url":"https://api.github.com/repos/OriginTrail/ot-node/statuses/{sha}","languages_url":"https://api.github.com/repos/OriginTrail/ot-node/languages","stargazers_url":"https://api.github.com/repos/OriginTrail/ot-node/stargazers","contributors_url":"https://api.github.com/repos/OriginTrail/ot-node/contributors","subscribers_url":"https://api.github.com/repos/OriginTrail/ot-node/subscribers","subscription_url":"https://api.github.com/repos/OriginTrail/ot-node/subscription","commits_url":"https://api.github.com/repos/OriginTrail/ot-node/commits{/sha}","git_commits_url":"https://api.github.com/repos/OriginTrail/ot-node/git/commits{/sha}","comments_url":"https://api.github.com/repos/OriginTrail/ot-node/comments{/number}","issue_comment_url":"https://api.github.com/repos/OriginTrail/ot-node/issues/comments{/number}","contents_url":"https://api.github.com/repos/OriginTrail/ot-node/contents/{+path}","compare_url":"https://api.github.com/repos/OriginTrail/ot-node/compare/{base}...{head}","merges_url":"https://api.github.com/repos/OriginTrail/ot-node/merges","archive_url":"https://api.github.com/repos/OriginTrail/ot-node/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/OriginTrail/ot-node/downloads","issues_url":"https://api.github.com/repos/OriginTrail/ot-node/issues{/number}","pulls_url":"https://api.github.com/repos/OriginTrail/ot-node/pulls{/number}","milestones_url":"https://api.github.com/repos/OriginTrail/ot-node/milestones{/number}","notifications_url":"https://api.github.com/repos/OriginTrail/ot-node/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/OriginTrail/ot-node/labels{/name}","releases_url":"https://api.github.com/repos/OriginTrail/ot-node/releases{/id}","deployments_url":"https://api.github.com/repos/OriginTrail/ot-node/deployments","created_at":"2018-02-01T18:29:15Z","updated_at":"2018-07-24T19:33:47Z","pushed_at":"2018-07-25T09:01:11Z","git_url":"git://github.com/OriginTrail/ot-node.git","ssh_url":"git@github.com:OriginTrail/ot-node.git","clone_url":"https://github.com/OriginTrail/ot-node.git","svn_url":"https://github.com/OriginTrail/ot-node","homepage":"https://origintrail.io","size":66125,"stargazers_count":45,"watchers_count":45,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10,"mirror_url":null,"archived":false,"open_issues_count":9,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":10,"open_issues":9,"watchers":45,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/OriginTrail/ot-node/pulls/403"},"html":{"href":"https://github.com/OriginTrail/ot-node/pull/403"},"issue":{"href":"https://api.github.com/repos/OriginTrail/ot-node/issues/403"},"comments":{"href":"https://api.github.com/repos/OriginTrail/ot-node/issues/403/comments"},"review_comments":{"href":"https://api.github.com/repos/OriginTrail/ot-node/pulls/403/comments"},"review_comment":{"href":"https://api.github.com/repos/OriginTrail/ot-node/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/OriginTrail/ot-node/pulls/403/commits"},"statuses":{"href":"https://api.github.com/repos/OriginTrail/ot-node/statuses/43ff27cb5217bcd18e813bd45c31164c7b539da0"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"kipliklotrika"}}