diff --git a/examples/cartrade/README.md b/examples/cartrade/README.md index 1d97e75bf3..2c30ef0fc7 100644 --- a/examples/cartrade/README.md +++ b/examples/cartrade/README.md @@ -103,4 +103,3 @@ Before you begin, you need to check that you have all the prerequisites installe 1. Stop the docker containers of Ethereum and Fabric - Press the command `docker stop ` to stop the container corresponding to the above containers which were launched by `./script-start-ledgers.sh` on the boot method. If you want to destroy the docker containers, press the command `docker rm ` after the above. - If any other docker containers are not running on your machine, you can destroy the Docker containers only with `docker ps -aq | xargs docker stop` and `docker ps -aq | xargs docker rm`. - diff --git a/examples/cartrade/TransactionEthereum.ts b/examples/cartrade/TransactionEthereum.ts index 357333a10f..99b280c469 100644 --- a/examples/cartrade/TransactionEthereum.ts +++ b/examples/cartrade/TransactionEthereum.ts @@ -5,6 +5,8 @@ * TransactionEthereum.ts */ +import { LPInfoHolder } from '../../packages/routing-interface/util/LPInfoHolder'; +import { VerifierBase } from '../../packages/ledger-plugin/VerifierBase'; import { TransactionSigner } from '../../packages/ledger-plugin/util/TransactionSigner'; const ethJsCommon = require('ethereumjs-common').default; @@ -20,51 +22,103 @@ const logger = getLogger(`${moduleName}`); logger.level = config.logLevel; const mapFromAddressNonce: Map = new Map(); +let xConnectInfo: LPInfoHolder = null; // connection information +let xVerifierEthereum: VerifierBase = null; export function makeRawTransaction(txParam: { fromAddress: string, fromAddressPkey: string, toAddress: string, amount: number, gas: number }): Promise<{ data: {}, txId: string }> { return new Promise(async (resolve, reject) => { try { - logger.debug("txParam : " + JSON.stringify(txParam)); - // Initial setting - logger.debug('gethUrl: ' + config.cartradeInfo.ethereum.gethURL); - const provider = new libWeb3.providers.HttpProvider(config.cartradeInfo.ethereum.gethURL); - const web3 = new libWeb3(provider); + logger.debug(`makeRawTransaction: txParam: ${JSON.stringify(txParam)}`); + + getNewNonce(txParam.fromAddress) + .then(result => { + logger.debug(`##makeRawTransaction(A): result: ${JSON.stringify(result)}`); + + const txnCountHex: string = result.txnCountHex; + + const rawTx: { nonce: string, to: string, value: number, gas: number } = { + "nonce": txnCountHex, + "to": txParam.toAddress, + "value": txParam.amount, + "gas": txParam.gas, + } + logger.debug(`##makeRawTransaction(B), rawTx: ${JSON.stringify(rawTx)}`); - // web3_v1.2.9_support - web3.eth.getTransactionCount(txParam.fromAddress) - .then(_nonce => { - let txnCount: number = _nonce; - // NOTE: No need to count up. + const signedTx = TransactionSigner.signTxEthereum(rawTx, txParam.fromAddressPkey); + const resp: { data: {}, txId: string } = { + data: { serializedTx: signedTx["serializedTx"] }, + txId: signedTx["txId"] + } - // NOTE: gasPrice is not used - // const gasPrice: string = web3.eth.getGasPrice(); - - const latestNonce = getLatestNonce(txParam.fromAddress); - logger.debug(`#####(A) _nonce: ${_nonce}, latestNonce: ${latestNonce}`); - logger.debug(`####makeRawTransaction(): fromAddress: ${txParam.fromAddress}, txnCount: ${web3.utils.toHex(txnCount)}, latestNonce: ${web3.utils.toHex(latestNonce)}`); - if (txnCount <= latestNonce) { - txnCount = latestNonce + 1; - logger.debug(`####makeRawTransaction(): Adjust txnCount, fromAddress: ${txParam.fromAddress}, txnCount: ${web3.utils.toHex(txnCount)}, latestNonce: ${web3.utils.toHex(latestNonce)}`); - } - logger.debug(`#####(B) _nonce: ${_nonce}, latestNonce: ${latestNonce}, txnCount: ${txnCount}`); - setLatestNonce(txParam.fromAddress, txnCount); - - const rawTx: { nonce: number, to: string, value: number, gas: number } = { - "nonce": web3.utils.toHex(txnCount), - "to": txParam.toAddress, - "value": txParam.amount, - "gas": txParam.gas, - } + return resolve(resp); + }) + } catch (err) { + logger.error(err); + return reject(err); + }; + }); +} - const signedTx = TransactionSigner.signTxEthereum(rawTx, txParam.fromAddressPkey); - const result: { data: {}, txId: string } = { - data: { serializedTx: signedTx["serializedTx"] }, - txId: signedTx["txId"] - } +function getNewNonce(fromAddress: string): Promise<{txnCountHex: string}> { + return new Promise(async (resolve, reject) => { + try { + logger.debug(`getNewNonce start: fromAddress: ${fromAddress}`); + + if (xConnectInfo === null) { + xConnectInfo = new LPInfoHolder(); + } + + if (xVerifierEthereum === null) { + logger.debug("create verifierEthereum"); + const ledgerPluginInfo: string = xConnectInfo.getLegerPluginInfo("84jUisrs"); + xVerifierEthereum = new VerifierBase(ledgerPluginInfo); + } + + + // Get the number of transactions in account + const contract = {}; // NOTE: Since contract does not need to be specified, specify an empty object. + let method = {type: "function", command: "getNonce"}; + const template = "default"; + let args = {"args": {"args": [fromAddress]}}; - return resolve(result); - }) + logger.debug(`##getNewNonce(A): call validator#getNonce()`); + xVerifierEthereum.execSyncFunction(contract, method, template, args) + .then(result => { + // logger.debug(`##getNewNonce(A): result: ${JSON.stringify(result)}`); + + let txnCount: number = result.data.nonce; + let txnCountHex: string = result.data.nonceHex; + + const latestNonce = getLatestNonce(fromAddress); + // logger.debug(`##getNewNonce(B): fromAddress: ${fromAddress}, txnCount: ${txnCount}, latestNonce: ${latestNonce}`); + if (txnCount <= latestNonce) { + // nonce correction + txnCount = latestNonce + 1; + logger.debug(`##getNewNonce(C): Adjust txnCount, fromAddress: ${fromAddress}, txnCount: ${txnCount}, latestNonce: ${latestNonce}`); + + const method = {type: "function", command: "toHex"}; + const args = {"args": {"args": [txnCount]}}; + + logger.debug(`##getNewNonce(D): call validator#toHex()`); + xVerifierEthereum.execSyncFunction(contract, method, template, args) + .then(result => { + txnCountHex = result.data.hexStr; + logger.debug(`##getNewNonce(E): txnCountHex: ${txnCountHex}`); + + // logger.debug(`##getNewNonce(F) _nonce: ${txnCount}, latestNonce: ${latestNonce}`); + setLatestNonce(fromAddress, txnCount); + + return resolve({txnCountHex: txnCountHex}); + }) + } else { + // logger.debug(`##getNewNonce(F) _nonce: ${txnCount}, latestNonce: ${latestNonce}`); + setLatestNonce(fromAddress, txnCount); + + logger.debug(`##getNewNonce(G): txnCountHex: ${txnCountHex}`); + return resolve({txnCountHex: txnCountHex}); + } + }) } catch (err) { logger.error(err); return reject(err); @@ -81,6 +135,8 @@ function getLatestNonce(fromAddress: string): number { return -1; } + function setLatestNonce(fromAddress: string, nonce: number): void { mapFromAddressNonce.set(fromAddress, nonce); } + diff --git a/packages/ledger-plugin/ValidatorAuthentication.ts b/packages/ledger-plugin/ValidatorAuthentication.ts index 4ae768accb..d17f1c3153 100644 --- a/packages/ledger-plugin/ValidatorAuthentication.ts +++ b/packages/ledger-plugin/ValidatorAuthentication.ts @@ -24,6 +24,7 @@ export class ValidatorAuthentication { expiresIn: '1000' } + // logger.debug(`payload = ${JSON.stringify(payload)}`); const signature: string = jwt.sign(payload, privateKey, option); logger.debug(`signature = ${signature}`); return signature; diff --git a/packages/ledger-plugin/go-ethereum/validator/src/core/bin/www.ts b/packages/ledger-plugin/go-ethereum/validator/src/core/bin/www.ts index 6a141f0ae5..cb317f53ec 100644 --- a/packages/ledger-plugin/go-ethereum/validator/src/core/bin/www.ts +++ b/packages/ledger-plugin/go-ethereum/validator/src/core/bin/www.ts @@ -221,6 +221,34 @@ io.on('connection', function(client) { logger.error('Detail :' + JSON.stringify(errObj)); client.emit("connector_error", errObj); }); + } else if (methodType === "function") { + const func = args["method"].command; + // Check for the existence of the specified function and call it if it exists. + if (Splug.isExistFunction(func)) { + // Can be called with Server plugin function name. + Splug[func](args) + .then((respObj) => { + logger.info('*** RESPONSE ***'); + logger.info('Client ID :' + client.id); + logger.info('Response :' + JSON.stringify(respObj)); + client.emit("response", respObj); + }) + .catch((errObj) => { + logger.error('*** ERROR ***'); + logger.error('Client ID :' + client.id); + logger.error('Detail :' + JSON.stringify(errObj)); + client.emit("connector_error", errObj); + }); + } else { + // No such function + const emsg = "Function " + func + " not found!"; + logger.error(emsg); + const retObj = { + "status" : 504, + "errorDetail" : emsg + }; + client.emit("connector_error", retObj); + } } else { // No such function const emsg = "method.type " + methodType + " not found!"; diff --git a/packages/ledger-plugin/go-ethereum/validator/src/dependent/ServerPlugin.ts b/packages/ledger-plugin/go-ethereum/validator/src/dependent/ServerPlugin.ts index 552170631f..e9d10e39ad 100644 --- a/packages/ledger-plugin/go-ethereum/validator/src/dependent/ServerPlugin.ts +++ b/packages/ledger-plugin/go-ethereum/validator/src/dependent/ServerPlugin.ts @@ -102,7 +102,6 @@ export class ServerPlugin { "amount" : amountVal } }; - logger.debug("##getNumericBalance: add reqID"); if (reqID !== undefined) { retObj["id"] = reqID; } @@ -117,7 +116,6 @@ export class ServerPlugin { "errorDetail" : emsg } }; - logger.debug("##getNumericBalance: add reqID"); if (reqID !== undefined) { retObj["id"] = reqID; } @@ -189,7 +187,6 @@ export class ServerPlugin { "txid" : res } }; - logger.debug("##transferNumericAsset: add reqID"); if (reqID !== undefined) { retObj["reqID"] = reqID; } @@ -204,7 +201,6 @@ export class ServerPlugin { "errorDetail" : emsg } }; - logger.debug("##transferNumericAsset: add reqID"); if (reqID !== undefined) { retObj["reqID"] = reqID; } @@ -214,6 +210,166 @@ export class ServerPlugin { }); } + + /* + * getNonce + * Get nonce. nonce is transaction count. + * + * @param {Object} args JSON Object + * { + * "targetAddress":, + * "reqID": (option) + * } + * @return {Object} JSON object + */ + getNonce(args) { + // * The Web3 API can be used synchronously, but each function is always an asynchronous specification because of the use of other APIs such as REST, + return new Promise((resolve, reject) => { + logger.info("getNonce start"); + var retObj = {}; + + var targetAddress = args.args.args.args[0]; + var reqID = args['reqID']; + + + if(targetAddress === undefined) { + let emsg = "JSON parse error!"; + logger.info(emsg); + retObj = { + "resObj" : { + "status" : 504, + "errorDetail" : emsg + } + }; + return reject(retObj); + } + + // var ethargs = '0x' + targetAddress; + var ethargs = targetAddress; + logger.debug(`getNonce(): ethargs: ${ethargs}, targetAddress: ${targetAddress}`); + // Handling exceptions to absorb the difference of interest. + try { + var web3 = new Web3(); + web3.setProvider(new web3.providers.HttpProvider(SplugConfig.provider)); + var txnCount = web3.eth.getTransactionCount(ethargs); + logger.info(`getNonce(): txnCount: ${txnCount}`); + var hexStr = web3.toHex(txnCount); + logger.info(`getNonce(): hexStr: ${hexStr}`); + const result = { + "nonce" : txnCount, + "nonceHex" : hexStr + }; + logger.debug(`getNonce(): result: ${result}`); + + const signedResults = ValidatorAuthentication.sign({"result":result}); + logger.debug(`getNonce(): signedResults: ${signedResults}`); + retObj = { + "resObj" : { + "status" : 200, + "data" : signedResults + } + }; + if (reqID !== undefined) { + retObj["id"] = reqID; + } + logger.debug(`##getNonce: retObj: ${JSON.stringify(retObj)}`); + return resolve(retObj); + } catch (e) { + let emsg = e.toString().replace(/Error: /g , ""); + logger.error(emsg); + retObj = { + "resObj" : { + "status" : 504, + "errorDetail" : emsg + } + }; + if (reqID !== undefined) { + retObj["id"] = reqID; + } + logger.debug(`##getNonce: retObj: ${JSON.stringify(retObj)}`); + return reject(retObj); + } + }); + } + + + /* + * toHex + * Convert to hex string. + * + * @param {Object} args JSON Object + * { + * "value":, + * "reqID": (option) + * } + * @return {Object} JSON object + */ + toHex(args) { + // * The Web3 API can be used synchronously, but each function is always an asynchronous specification because of the use of other APIs such as REST, + return new Promise((resolve, reject) => { + logger.info("toHex start"); + var retObj = {}; + + var targetValue = args.args.args.args[0]; + var reqID = args['reqID']; + + + if(targetValue === undefined) { + let emsg = "JSON parse error!"; + logger.info(emsg); + retObj = { + "resObj" : { + "status" : 504, + "errorDetail" : emsg + } + }; + return reject(retObj); + } + + logger.debug(`toHex(): targetValue: ${targetValue}`); + // Handling exceptions to absorb the difference of interest. + try { + var web3 = new Web3(); + web3.setProvider(new web3.providers.HttpProvider(SplugConfig.provider)); + var hexStr = web3.toHex(targetValue); + logger.info(`toHex(): hexStr: ${hexStr}`); + const result = { + "hexStr" : hexStr + }; + logger.debug(`toHex(): result: ${result}`); + + const signedResults = ValidatorAuthentication.sign({"result":result}); + logger.debug(`toHex(): signedResults: ${signedResults}`); + retObj = { + "resObj" : { + "status" : 200, + "data" : signedResults + } + }; + if (reqID !== undefined) { + retObj["id"] = reqID; + } + logger.debug(`##toHex: retObj: ${JSON.stringify(retObj)}`); + return resolve(retObj); + } catch (e) { + let emsg = e.toString().replace(/Error: /g , ""); + logger.error(emsg); + retObj = { + "resObj" : { + "status" : 504, + "errorDetail" : emsg + } + }; + if (reqID !== undefined) { + retObj["id"] = reqID; + } + logger.debug(`##toHex: retObj: ${JSON.stringify(retObj)}`); + return reject(retObj); + } + }); + } + + /* * sendRawTransaction * send row trancastion @@ -310,7 +466,6 @@ export class ServerPlugin { "data" : signedResults } }; - logger.debug("##web3Eth: add reqID"); if (reqID !== undefined) { retObj["id"] = reqID; } @@ -325,7 +480,6 @@ export class ServerPlugin { "errorDetail" : emsg } }; - logger.debug("##web3Eth: add reqID"); if (reqID !== undefined) { retObj["id"] = reqID; } @@ -396,7 +550,6 @@ export class ServerPlugin { "data" : signedResults } }; - logger.debug("##contract: add reqID"); if (reqID !== undefined) { retObj["id"] = reqID; } @@ -411,7 +564,6 @@ export class ServerPlugin { "errorDetail" : emsg } }; - logger.debug("##contract: add reqID"); if (reqID !== undefined) { retObj["id"] = reqID; } diff --git a/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_getNonceHex.ts b/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_getNonceHex.ts new file mode 100644 index 0000000000..17ba8c3d74 --- /dev/null +++ b/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_getNonceHex.ts @@ -0,0 +1,130 @@ +/* + * Copyright 2021 Hyperledger Cactus Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * validatorDriver_getNonceHex.js + */ + +//////// +// Usage +// 1) Set parameter to parameter variable +// [parameter variables of getNonceHex] referredAddress +// 2) Specify the function to execute with "requestData" +// 3) execute +// +//////// + +{ + +// Validator test program.(socket.io client) +var io = require('socket.io-client'); +var config = require('config'); + +// Specify the server (Validator) of the communication destination +var validatorUrl = config.validatorUrl; +console.log('validatorUrl: ' + validatorUrl); +var options = { + rejectUnauthorized: false, // temporary avoidance since self-signed certificates are used + reconnection : false, + timeout : 20000 +}; +var socket = io(validatorUrl, options); + +// for test +// ec1-accounts[0] Address: {ec709e1774f0ce4aba47b52a499f9abaaa159f71} +// ec1-accounts[1] Address: {36e146d5afab61ab125ee671708eeb380aea05b6} +// ec1-accounts[2] Address: {06fc56347d91c6ad2dae0c3ba38eb12ab0d72e97} +// ec1-accounts[3] Address: {9d624f7995e8bd70251f8265f2f9f2b49f169c55} +// ec1-accounts[4] Address: {2666a32bf7594ab5395d766dcfbf03d557dab538} + +// ## Request for "getNonceHex" +//var referedAddress = "36e146d5afab61ab125ee671708eeb380aea05b6"; +var referedAddress = "ec709e1774f0ce4aba47b52a499f9abaaa159f71"; + +var reqID = "reqID_001"; + +// function param +const requestData = { + contract: {}, // NOTE: Since contract does not need to be specified, specify an empty object. + // method: {type: "web3Eth", command: "getNonceHex"}, + method: {type: "function", command: "getNonceHex"}, + // args: {"args": [referedAddress]}, + args: {"args": {"args": [referedAddress]}}, + reqID: reqID +}; + +const requestData_A = { + contract: {}, // NOTE: Since contract does not need to be specified, specify an empty object. + func: "getNonceHex", + args: {"args": {"args": [referedAddress]}}, + reqID: reqID +}; + + + +const json2str = (jsonObj) => { + try { + return JSON.stringify(jsonObj); + } + catch (error) { + return null; + } +} + + +socket.on('connect_error', (err) => { + console.log('####connect_error:', err); + // end communication + socket.disconnect(); + process.exit(0); +}); + +socket.on('connect_timeout', (err) => { + console.log('####Error:', err); + // end communication + socket.disconnect(); + process.exit(0); +}); + +socket.on('error', (err) => { + console.log('####Error:', err); +}); + +socket.on('eventReceived', function (res) { + // output the data received from the client + console.log('#[recv]eventReceived, res: ' + json2str(res)); +}); + + +const requestStopMonitor = () => { + console.log('##exec requestStopMonitor()'); + socket.emit('stopMonitor'); + + setTimeout(function(){ + // end communication + socket.disconnect(); + process.exit(0); + },5000); +} + +// request StartMonitor +const requestStartMonitor = () => { + console.log('##exec requestStartMonitor()'); + socket.emit('startMonitor'); + + setTimeout(requestStopMonitor,15000); +} + + +const sendRequest = () => { + // + console.log('exec sendRequest()'); + console.log('#[send]requestData: ' + json2str(requestData)); + socket.emit('request2', requestData); + // socket.emit('request', requestData_A); +} + +setTimeout(requestStartMonitor, 2000); +setTimeout(sendRequest, 4000); + +} diff --git a/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_getNumericBalance.ts b/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_getNumericBalance.ts index a92ed4dc0e..99c56e1064 100644 --- a/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_getNumericBalance.ts +++ b/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_getNumericBalance.ts @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Fujitsu Laboratories Ltd. + * Copyright 2021 Hyperledger Cactus Contributors * SPDX-License-Identifier: Apache-2.0 * * validatorDriver_getNumericBalance.js @@ -46,9 +46,18 @@ const requestData = { contract: {}, // NOTE: Since contract does not need to be specified, specify an empty object. method: {type: "web3Eth", command: "getBalance"}, args: {"args": [referedAddress]}, + // args: {"args": {"args": [referedAddress]}}, reqID: reqID }; +const requestData_A = { + contract: {}, // NOTE: Since contract does not need to be specified, specify an empty object. + func: "getNumericBalance", + args: {"args": {"args": [referedAddress]}}, + reqID: reqID +}; + + const json2str = (jsonObj) => { try { @@ -108,8 +117,8 @@ const sendRequest = () => { // console.log('exec sendRequest()'); console.log('#[send]requestData: ' + json2str(requestData)); - // socket.emit('request', requestData); - socket.emit('request2', requestData); + socket.emit('request', requestData_A); + // socket.emit('request2', requestData); } setTimeout(requestStartMonitor, 2000); diff --git a/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_sendRawTransaction.ts b/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_sendRawTransaction.ts index b5778a8e7b..b5e5bc7372 100644 --- a/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_sendRawTransaction.ts +++ b/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_sendRawTransaction.ts @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Fujitsu Laboratories Ltd. + * Copyright 2021 Hyperledger Cactus Contributors * SPDX-License-Identifier: Apache-2.0 * * validatorDriver_sendRawTransaction.js diff --git a/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_transferNumericAsset.ts b/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_transferNumericAsset.ts index 364bad8ac0..f43a4bf674 100644 --- a/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_transferNumericAsset.ts +++ b/packages/ledger-plugin/go-ethereum/validator/unit-test/validatorDriver_transferNumericAsset.ts @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Fujitsu Laboratories Ltd. + * Copyright 2021 Hyperledger Cactus Contributors * SPDX-License-Identifier: Apache-2.0 * * validatorDriver_transferNumericAsset.js