Skip to content

Commit

Permalink
feat(connector-go-ethereum): add getBlock and
Browse files Browse the repository at this point in the history
getTransactionReceipt methods to connector

- getBlock and getTransactionReceipt added in
go-ethereum-socketio-connector
- Added nullish coalescing in monitor options

Closes: #2255
Signed-off-by: tomasz awramski <tomasz.awramski@fujitsu.com>
  • Loading branch information
rwat17 committed Mar 2, 2023
1 parent 6335787 commit 25fe556
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -252,19 +252,20 @@ export async function startGoEthereumSocketIOConnector() {
* startMonitor: starting block generation event monitoring
**/
client.on("startMonitor", function (monitorOptions) {

monitorOptions = monitorOptions ?? {allBlocks: false};
logger.debug("monitorOptions", monitorOptions);
Smonitor.startMonitor(client.id, monitorOptions.allBlocks, (event) => {
let emitType = "";
if (event.status == 200) {
emitType = "eventReceived";
logger.info("event data callbacked.");
} else {
emitType = "monitor_error";
}
client.emit(emitType, event);
});
Smonitor.startMonitor(
client.id,
monitorOptions?.allBlocks ?? false,
(event) => {
let emitType = "";
if (event.status == 200) {
emitType = "eventReceived";
logger.info("event data callbacked.");
} else {
emitType = "monitor_error";
}
client.emit(emitType, event);
},
);
});

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ import * as SplugUtil from "./PluginUtil";
// Load libraries, SDKs, etc. according to specifications of endchains as needed
import Web3 from "web3";
import { AbiItem } from "web3-utils";
import { BlockNumber } from "web3-core";
import { safeStringifyException } from "@hyperledger/cactus-common";

var WEB3_HTTP_PROVIDER_OPTIONS = {
const WEB3_HTTP_PROVIDER_OPTIONS = {
keepAlive: true,
};

Expand Down Expand Up @@ -60,7 +61,12 @@ function getWeb3Provider(host: string) {
}
}

const web3 = new Web3(getWeb3Provider(configRead("ledgerUrl")));
const web3Provider = getWeb3Provider(configRead("ledgerUrl"));
const web3 = new Web3(web3Provider);

export function shutdown() {
web3Provider.disconnect();
}

/*
* ServerPlugin
Expand Down Expand Up @@ -93,6 +99,135 @@ export class ServerPlugin {
}
}

/*
* getBlock
*
* @param {String|Number} block hash, block number or string:"earliest", "latest" or "pending"
*
* @return {Object} JSON object
*/

async getBlock(args: any) {
logger.debug("getBlock start");

const blockID: BlockNumber = args.args.args[0];
const returnTransactionObjects = args.args.args[1] ?? false;
const reqID = args["reqID"];

if (!blockID) {
const emsg = "JSON parse error!";
logger.warn(emsg);
throw {
resObj: {
status: 504,
errorDetail: emsg,
},
id: reqID,
};
}

try {
const blockData = await web3.eth.getBlock(
blockID,
returnTransactionObjects,
);
const result = {
blockData: blockData,
};
logger.debug(`getBlock(): result: ${result}`);

const signedResults = signMessageJwt({ result });
logger.debug(`getBlock(): signedResults: ${signedResults}`);

return {
resObj: {
status: 200,
data: signedResults,
},
id: reqID,
};
} catch (e) {
const retObj = {
resObj: {
status: 504,
errorDetail: safeStringifyException(e),
},
id: reqID,
};

logger.error(`##getBlock: retObj: ${JSON.stringify(retObj)}`);

throw retObj;
}
}

/*
* getTransactionReceipt
*
* @param {String} transaction hash
*
* @return {Object} JSON object
*/

async getTransactionReceipt(args: any) {
logger.debug("getTransactionReceipt start");

const txHash: string = args.args.args[0];
const reqID = args["reqID"];

if (txHash === undefined) {
const emsg = "JSON parse error!";
logger.warn(emsg);
throw {
resObj: {
status: 504,
errorDetail: emsg,
},
id: reqID,
};
}

try {
const txReceipt = await web3.eth.getTransactionReceipt(txHash);
logger.info(`getTransactionReceipt(): txReceipt: ${txReceipt}`);

const result = {
txReceipt: txReceipt,
};
logger.debug(`getTransactionReceipt(): result: ${result}`);

const signedResults = signMessageJwt({ result: result });
logger.debug(`getTransactionReceipt(): signedResults: ${signedResults}`);

const retObj = {
resObj: {
status: 200,
data: signedResults,
},
id: reqID,
};

logger.debug(
`##getTransactionReceipt: retObj: ${JSON.stringify(retObj)}`,
);
return retObj;
} catch (e) {
const retObj = {
resObj: {
status: 504,
errorDetail: safeStringifyException(e),
},
id: reqID,
};

logger.error(
`##getTransactionReceipt: retObj: ${JSON.stringify(retObj)}`,
);

throw retObj;
}
}

// Define an arbitrary function and implement it according to specifications of end-chains
/**
* getNumericBalance
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { startGoEthereumSocketIOConnector } from "./common/core/bin/www"
export { startGoEthereumSocketIOConnector } from "./common/core/bin/www";
export { shutdown } from "./connector/ServerPlugin";
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,17 @@ describe("Go-Ethereum-SocketIO connector tests", () => {
let connectorServer: HttpsServer;
let apiClient: SocketIOApiClient;
let constTestAcc: Account;
let connectorModule: any;
const constTestAccBalance = 5 * 1000000;

//////////////////////////////////
// Environment Setup
//////////////////////////////////

async function deploySmartContract(): Promise<string> {
async function deploySmartContract(): Promise<{
contractAddress: string;
blockNumber: number;
}> {
const txReceipt = await ledger.deployContract(
HelloWorldContractJson.abi as any,
"0x" + HelloWorldContractJson.bytecode,
Expand All @@ -74,7 +78,11 @@ describe("Go-Ethereum-SocketIO connector tests", () => {
"Deployed test smart contract, TX on block number",
txReceipt.blockNumber,
);
return txReceipt.contractAddress ?? "";

return {
contractAddress: txReceipt.contractAddress ?? "",
blockNumber: txReceipt.blockNumber,
};
}

beforeAll(async () => {
Expand All @@ -99,7 +107,8 @@ describe("Go-Ethereum-SocketIO connector tests", () => {
web3 = new Web3(ledgerRpcUrl);

// Deploy test smart contract
contractAddress = await deploySmartContract();
const deployOutput = await deploySmartContract();
contractAddress = deployOutput.contractAddress;

// Generate connector private key and certificate
const pkiGenerator = new SelfSignedPkiGenerator();
Expand All @@ -125,7 +134,7 @@ describe("Go-Ethereum-SocketIO connector tests", () => {
process.env["NODE_CONFIG"] = configJson;

// Load connector module
const connectorModule = await import("../../../main/typescript/index");
connectorModule = await import("../../../main/typescript/index");

// Run the connector
connectorServer = await connectorModule.startGoEthereumSocketIOConnector();
Expand Down Expand Up @@ -160,6 +169,10 @@ describe("Go-Ethereum-SocketIO connector tests", () => {
afterAll(async () => {
log.info("FINISHING THE TESTS");

if (connectorModule) {
connectorModule.shutdown();
}

if (apiClient) {
log.info("Close ApiClient connection...");
apiClient.close();
Expand Down Expand Up @@ -200,6 +213,97 @@ describe("Go-Ethereum-SocketIO connector tests", () => {
expect(balance).toEqual(constTestAccBalance.toString());
});

test("getBlock returns valid block data for different methods", async () => {
const getBlock = async (param: string | number) => {
const method = { type: "function", command: "getBlock" };
const args = { args: [param] };
const response = await apiClient.sendSyncRequest({}, method, args);
expect(response).toBeTruthy();
return response;
};

const latestBlock = await getBlock("latest");
expect(latestBlock.status).toEqual(200);
const { data: blockDataByHash } = await getBlock(
latestBlock.data.blockData.hash,
);
expect(blockDataByHash.blockData.hash).toEqual(
latestBlock.data.blockData.hash,
);
const { data: blockDataByNumber } = await getBlock(
latestBlock.data.blockData.number,
);
expect(blockDataByNumber.blockData.hash).toEqual(
blockDataByHash.blockData.hash,
);

// Assert transaction data is not returned
const { blockNumber } = await deploySmartContract();
const blockWithTx = await getBlock(blockNumber);
const firstTx = blockWithTx.data.blockData.transactions[0];
expect(firstTx).toBeTruthy();
// Only string hashes are returned when flag is false
expect(typeof firstTx).toEqual("string");
});

test("getBlock returns transaction data when requested", async () => {
const method = { type: "function", command: "getBlock" };
const { blockNumber } = await deploySmartContract();
const args = { args: [blockNumber, true] };

const response = await apiClient.sendSyncRequest({}, method, args);

// Assert correct response
expect(response).toBeTruthy();
expect(response.status).toEqual(200);

// Assert valid block data
const block = response.data.blockData;
expect(block).toBeTruthy();
expect(block.hash).toBeTruthy();

// Assert transaction data was returned as requested
expect(block.transactions.length).toBeGreaterThan(0);
const firstTx = block.transactions[0];
expect(firstTx).toBeTruthy();
expect(firstTx.hash).toBeTruthy();
});

test("Function getTransactionReceipt returns transaction receipt of given transaction", async () => {
async function getTransactionHash() {
const fromAccInitBalance = 1500;
const toAccInitBalance = 1500;
const transferAmount = 500;
//creating two accounts to perform transaction on them
const fromAddress = await ledger.createEthTestAccount(fromAccInitBalance);
const toAcc = await ledger.createEthTestAccount(toAccInitBalance);
// adding account using a private key to the wallet
web3.eth.accounts.wallet.add(fromAddress.privateKey);

const signedTx = await fromAddress.signTransaction({
from: fromAddress.address,
to: toAcc.address,
value: transferAmount,
gas: 1000000,
});
const method = { type: "function", command: "sendRawTransaction" };
const args = { args: [{ serializedTx: signedTx.rawTransaction }] };
// transfering funds to trigger transaction
const response = await apiClient.sendSyncRequest({}, method, args);
// returning only transaction hash
return response.data.txid;
}

const transactionHash = await getTransactionHash();
const method = { type: "function", command: "getTransactionReceipt" };
const args = { args: [transactionHash] };

const response = await apiClient.sendSyncRequest({}, method, args);
expect(response).toBeTruthy();
expect(response.status).toEqual(200);
expect(response.data.txReceipt.transactionHash).toEqual(transactionHash);
});

/**
* Test ServerPlugin getNumericBalance function.
*/
Expand Down Expand Up @@ -294,7 +398,6 @@ describe("Go-Ethereum-SocketIO connector tests", () => {
gas: 1000000,
});
expect(signedTx).toBeTruthy();
log.warn(signedTx);

const method = { type: "function", command: "sendRawTransaction" };
const args = { args: [{ serializedTx: signedTx.rawTransaction }] };
Expand Down Expand Up @@ -377,7 +480,7 @@ describe("Go-Ethereum-SocketIO connector tests", () => {
/**
* Test ServerMonitorPlugin startMonitor/stopMonitor functions.
*/
test.only(
test(
"Monitoring returns new block",
async () => {
// Create monitoring promise and subscription
Expand Down

0 comments on commit 25fe556

Please sign in to comment.