From 05182fe3871d7bdee29aa9ba294e50eb2c1cc031 Mon Sep 17 00:00:00 2001 From: harpagon210 Date: Thu, 27 Jun 2019 16:52:41 -0500 Subject: [PATCH] adding contract version and callingContractInfo object --- libs/SmartContracts.js | 20 ++++++++++++++++++++ plugins/Streamer.js | 7 +++++++ test/steemsmartcontracts.js | 6 +++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/libs/SmartContracts.js b/libs/SmartContracts.js index 14ade11..b95cb69 100644 --- a/libs/SmartContracts.js +++ b/libs/SmartContracts.js @@ -136,6 +136,10 @@ class SmartContracts { BigNumber.set({ DECIMAL_PLACES: 3 }); } + const contractVersion = existingContract && existingContract.version + ? existingContract.version + : 1; + // initialize the state that will be available in the VM const vmState = { api: { @@ -145,6 +149,7 @@ class SmartContracts { blockNumber, refSteemBlockNumber, steemBlockTimestamp: timestamp, + contractVersion, db, BigNumber, validator, @@ -158,6 +163,7 @@ class SmartContracts { JSON.stringify(parameters), blockNumber, timestamp, refSteemBlockNumber, refSteemBlockId, prevRefSteemBlockId, jsVMTimeout, + name, contractVersion, ), // emit an event that will be stored in the logs emit: (event, data) => typeof event === 'string' && logs.events.push({ contract: name, event, data }), @@ -187,12 +193,14 @@ class SmartContracts { code: codeTemplate, codeHash: SHA256(codeTemplate).toString(enchex), tables, + version: 1, }; // if contract already exists, update it if (existingContract !== null) { newContract.$loki = existingContract.$loki; newContract.tables = Object.assign(existingContract.tables, newContract.tables); + newContract.version = existingContract.version + 1; await ipc.send( { @@ -248,6 +256,7 @@ class SmartContracts { const contractCode = contractInDb.code; const contractOwner = contractInDb.owner; + const contractVersion = contractInDb.version; // prepare the db object that will be available in the VM const db = { @@ -300,6 +309,7 @@ class SmartContracts { owner: contractOwner, refSteemBlockNumber, steemBlockTimestamp: timestamp, + contractVersion, transactionId, blockNumber, action, @@ -317,6 +327,7 @@ class SmartContracts { JSON.stringify(parameters), blockNumber, timestamp, refSteemBlockNumber, refSteemBlockId, prevRefSteemBlockId, jsVMTimeout, + contract, contractVersion, ), // execute a smart contract from the current smart contract // with the contractOwner authority level @@ -327,6 +338,7 @@ class SmartContracts { JSON.stringify(parameters), blockNumber, timestamp, refSteemBlockNumber, refSteemBlockId, prevRefSteemBlockId, jsVMTimeout, + contract, contractVersion, ), // execute a token transfer from the contract balance transferTokens: async ( @@ -342,6 +354,7 @@ class SmartContracts { }), blockNumber, timestamp, refSteemBlockNumber, refSteemBlockId, prevRefSteemBlockId, jsVMTimeout, + contract, contractVersion, ), // emit an event that will be stored in the logs emit: (event, data) => typeof event === 'string' && results.logs.events.push({ contract, event, data }), @@ -405,6 +418,7 @@ class SmartContracts { timestamp, refSteemBlockNumber, refSteemBlockId, prevRefSteemBlockId, jsVMTimeout, + callingContractName, callingContractVersion, ) { if (typeof contract !== 'string' || typeof action !== 'string' || (parameters && typeof parameters !== 'string')) return null; const sanitizedParams = parameters ? JSON.parse(parameters) : null; @@ -423,6 +437,12 @@ class SmartContracts { sanitizedParams.isSignedWithActiveKey = originalParameters.isSignedWithActiveKey; } + // pass the calling contract name and calling contract version to the contract + sanitizedParams.callingContractInfo = { + name: callingContractName, + version: callingContractVersion, + }; + const results = {}; try { const res = await SmartContracts.executeSmartContract( diff --git a/plugins/Streamer.js b/plugins/Streamer.js index 65b7104..3a6ce2a 100644 --- a/plugins/Streamer.js +++ b/plugins/Streamer.js @@ -171,6 +171,13 @@ function parseTransactions(refBlockNumber, block) { delete contractPayload.permlink; } + // callingContractInfo is a reserved property + // it is used to provide information about a contract when calling + // a contract action from another contract + if (contractPayload.callingContractInfo) { + delete contractPayload.callingContractInfo; + } + // set the sender to null when calling the comment action // this way we allow people to create comments only via the comment operation if (operation[0] === 'comment' && contractName === 'comments' && contractAction === 'comment') { diff --git a/test/steemsmartcontracts.js b/test/steemsmartcontracts.js index a021fcc..f39e0e3 100644 --- a/test/steemsmartcontracts.js +++ b/test/steemsmartcontracts.js @@ -1058,7 +1058,10 @@ describe('Smart Contracts', () => { } actions.addBook = async (payload) => { - const { title } = payload; + const { title, callingContractInfo } = payload; + + api.debug(callingContractInfo.name) + api.debug(callingContractInfo.version) let user = await api.db.findOneInTable('usersContract', 'users', { "id": api.sender }); @@ -1598,6 +1601,7 @@ describe('Smart Contracts', () => { let res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND_CONTRACT, payload: { name: 'testContract' } }); const contract = res.payload; + assert.equal(contract.version, 2); assert.notEqual(contract.tables['testContract_testTable'], undefined); assert.notEqual(contract.tables['testContract_testUpdateTable'], undefined);