Skip to content

Commit bbc34c6

Browse files
authored
Add support for optional data field on eth_call flow (#317)
* Fix schema mismatch for nums in eth_getTransactionReceipt response Add support for optional data field on eth_call flow - Add check to populate functionParams only on valid data field - Update servicesClient transaction with memo to help differentiate - Add caller name to `sdkClient` to help track - Update Basic contract with `receive` function to support no data param test Signed-off-by: Nana-EC <[email protected]>
1 parent 637d3af commit bbc34c6

File tree

6 files changed

+50
-26
lines changed

6 files changed

+50
-26
lines changed

packages/relay/src/lib/clients/sdkClient.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,23 +189,26 @@ export class SDKClient {
189189
return transactionResponse.getRecord(this.clientMain);
190190
}
191191

192-
async submitEthereumTransaction(transactionBuffer: Uint8Array): Promise<TransactionResponse> {
192+
async submitEthereumTransaction(transactionBuffer: Uint8Array, callerName: string): Promise<TransactionResponse> {
193193
return this.executeTransaction(new EthereumFlow()
194-
.setEthereumData(transactionBuffer));
194+
.setEthereumData(transactionBuffer), callerName);
195195
}
196196

197197
async submitContractCallQuery(to: string, data: string, gas: number, callerName: string): Promise<ContractFunctionResult> {
198198
const contract = SDKClient.prune0x(to);
199-
const callData = SDKClient.prune0x(data);
200199
const contractId = contract.startsWith("00000000000")
201200
? ContractId.fromSolidityAddress(contract)
202201
: ContractId.fromEvmAddress(0, 0, contract);
203202

204203
const contractCallQuery = new ContractCallQuery()
205204
.setContractId(contractId)
206-
.setFunctionParameters(Buffer.from(callData, 'hex'))
207205
.setGas(gas);
208206

207+
// data is optional and can be omitted in which case fallback function will be employed
208+
if (data) {
209+
contractCallQuery.setFunctionParameters(Buffer.from(SDKClient.prune0x(data), 'hex'));
210+
}
211+
209212
if (this.clientMain.operatorAccountId !== null) {
210213
contractCallQuery
211214
.setPaymentTransactionId(TransactionId.generate(this.clientMain.operatorAccountId));
@@ -262,7 +265,7 @@ export class SDKClient {
262265
}
263266
};
264267

265-
private executeTransaction = async (transaction: Transaction | EthereumFlow): Promise<TransactionResponse> => {
268+
private executeTransaction = async (transaction: Transaction | EthereumFlow, callerName: string): Promise<TransactionResponse> => {
266269
const transactionType = transaction.constructor.name;
267270
try {
268271
this.logger.info(`Execute ${transactionType} transaction`);
@@ -273,6 +276,12 @@ export class SDKClient {
273276
catch (e: any) {
274277
const statusCode = e.status ? e.status._code : Status.Unknown._code;
275278
this.logger.info(`Consensus Node ${transactionType} transaction response: ${statusCode}`);
279+
this.captureMetrics(
280+
SDKClient.transactionMode,
281+
transactionType,
282+
statusCode,
283+
0,
284+
callerName);
276285

277286
// capture sdk transaction response errors and shorten familiar stack trace
278287
if (e.status && e.status._code) {

packages/relay/src/lib/eth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ export class EthImpl implements Eth {
669669
const transactionBuffer = Buffer.from(EthImpl.prune0x(transaction), 'hex');
670670

671671
try {
672-
const contractExecuteResponse = await this.sdkClient.submitEthereumTransaction(transactionBuffer);
672+
const contractExecuteResponse = await this.sdkClient.submitEthereumTransaction(transactionBuffer, EthImpl.ethSendRawTransaction);
673673

674674
try {
675675
// Wait for the record from the execution.

packages/server/tests/acceptance/rpc.spec.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import { AccountBalanceQuery, ContractFunctionParameters } from '@hashgraph/sdk'
2929
// local resources
3030
import parentContractJson from '../contracts/Parent.json';
3131
import basicContractJson from '../contracts/Basic.json';
32-
import {JsonRpcError} from "@hashgraph/json-rpc-relay";
3332
import logsContractJson from '../contracts/Logs.json';
3433
import { predefined } from '../../../relay/src/lib/errors';
3534

@@ -994,6 +993,17 @@ describe('RPC Server Acceptance Tests', function () {
994993
expect(res).to.eq(BASIC_CONTRACT_PING_RESULT);
995994
});
996995

996+
it('should fail "eth_call" request without data field', async function () {
997+
const callData = {
998+
from: accounts[2].address,
999+
to: evmAddress,
1000+
gas: 30000
1001+
};
1002+
1003+
const res = await relay.call('eth_call', [callData]);
1004+
expect(res).to.eq('0x'); // confirm no error
1005+
});
1006+
9971007
it('should fail "eth_call" for non-existing contract address', async function () {
9981008
const callData = {
9991009
from: accounts[2].address,
@@ -1026,16 +1036,6 @@ describe('RPC Server Acceptance Tests', function () {
10261036
const res = await relay.call('eth_call', [callData]);
10271037
expect(res).to.eq(BASIC_CONTRACT_PING_RESULT);
10281038
});
1029-
1030-
it('should fail "eth_call" request without data field', async function () {
1031-
const callData = {
1032-
from: accounts[2].address,
1033-
to: evmAddress,
1034-
gas: 30000
1035-
};
1036-
1037-
await relay.callFailing('eth_call', [callData]);
1038-
});
10391039
});
10401040
});
10411041

packages/server/tests/clients/servicesClient.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ export default class ServicesClient {
114114
.setTokenSymbol(symbol)
115115
.setDecimals(3)
116116
.setInitialSupply(new Hbar(initialSupply).toTinybars())
117-
.setTreasuryAccountId(this._thisAccountId()));
117+
.setTreasuryAccountId(this._thisAccountId())
118+
.setTransactionMemo('Relay test token create'));
118119

119120
this.logger.trace(`get token id from receipt`);
120121
const tokenId = resp?.tokenId;
@@ -126,7 +127,8 @@ export default class ServicesClient {
126127
await this.executeAndGetTransactionReceipt(
127128
await new TokenAssociateTransaction()
128129
.setAccountId(this._thisAccountId())
129-
.setTokenIds([tokenId]));
130+
.setTokenIds([tokenId])
131+
.setTransactionMemo('Relay test token association'));
130132

131133
this.logger.debug(
132134
`Associated account ${this._thisAccountId()} with token ${tokenId.toString()}`
@@ -136,7 +138,8 @@ export default class ServicesClient {
136138
async transferToken(tokenId, recipient: AccountId, amount = 10) {
137139
await this.executeAndGetTransactionReceipt(new TransferTransaction()
138140
.addTokenTransfer(tokenId, this._thisAccountId(), -amount)
139-
.addTokenTransfer(tokenId, recipient, amount));
141+
.addTokenTransfer(tokenId, recipient, amount)
142+
.setTransactionMemo('Relay test token transfer'));
140143

141144
this.logger.debug(
142145
`Sent 10 tokens from account ${this._thisAccountId()} to account ${recipient.toString()} on token ${tokenId.toString()}`
@@ -157,7 +160,8 @@ export default class ServicesClient {
157160

158161
const fileReceipt = await this.executeAndGetTransactionReceipt(new FileCreateTransaction()
159162
.setKeys([this.client.operatorPublicKey || this.DEFAULT_KEY])
160-
.setContents(contractByteCode));
163+
.setContents(contractByteCode)
164+
.setTransactionMemo('Relay test file create'));
161165

162166
// Fetch the receipt for transaction that created the file
163167
// The file ID is located on the transaction receipt
@@ -172,7 +176,8 @@ export default class ServicesClient {
172176
.setGas(75000)
173177
.setInitialBalance(1)
174178
.setBytecodeFileId(fileId || '')
175-
.setAdminKey(this.client.operatorPublicKey || this.DEFAULT_KEY));
179+
.setAdminKey(this.client.operatorPublicKey || this.DEFAULT_KEY)
180+
.setTransactionMemo('Relay test contract create'));
176181

177182
// The contract ID is located on the transaction receipt
178183
const contractId = contractReceipt?.contractId;
@@ -192,7 +197,8 @@ export default class ServicesClient {
192197
.setFunction(
193198
functionName,
194199
params
195-
));
200+
)
201+
.setTransactionMemo('Relay test contract execution'));
196202

197203
// @ts-ignore
198204
const resp = await this.getRecordResponseDetails(contractExecTransactionResponse);
@@ -213,7 +219,8 @@ export default class ServicesClient {
213219

214220
const aliasCreationResponse = await this.executeTransaction(new TransferTransaction()
215221
.addHbarTransfer(this._thisAccountId(), new Hbar(initialBalance).negated())
216-
.addHbarTransfer(aliasAccountId, new Hbar(initialBalance)));
222+
.addHbarTransfer(aliasAccountId, new Hbar(initialBalance))
223+
.setTransactionMemo('Relay test crypto transfer'));
217224

218225
this.logger.debug(`Get ${aliasAccountId.toString()} receipt`);
219226
await aliasCreationResponse?.getReceipt(this.client);
@@ -275,6 +282,7 @@ export default class ServicesClient {
275282
const response = await new FileUpdateTransaction()
276283
.setFileId(fileId)
277284
.setContents(Buffer.from(content, 'hex'))
285+
.setTransactionMemo('Relay test update')
278286
.execute(this.client);
279287

280288
const receipt = await response.getReceipt(this.client);

packages/server/tests/contracts/Basic.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@
2020
],
2121
"stateMutability": "pure",
2222
"type": "function"
23+
},
24+
{
25+
"stateMutability": "payable",
26+
"type": "receive"
2327
}
2428
],
25-
"bytecode": "0x608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80635c36b18614602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212206ad62fc0dbb8a1f3b6389e460d953f0f7fb0ce2eb71250d4057992f62dfc56d264736f6c63430008040033",
26-
"deployedBytecode": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c80635c36b18614602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212206ad62fc0dbb8a1f3b6389e460d953f0f7fb0ce2eb71250d4057992f62dfc56d264736f6c63430008040033",
29+
"bytecode": "0x608060405234801561001057600080fd5b5060bf8061001f6000396000f3fe608060405260043610601f5760003560e01c80635c36b18614602a576025565b36602557005b600080fd5b348015603557600080fd5b50603c6050565b604051604791906070565b60405180910390f35b60006001905090565b6000819050919050565b606a816059565b82525050565b6000602082019050608360008301846063565b9291505056fea2646970667358221220defb1b1fca12d2d0cdcb178a4117d75fe5c8500fae15807c82c8c3db9b32e5b764736f6c63430008090033",
30+
"deployedBytecode": "0x608060405260043610601f5760003560e01c80635c36b18614602a576025565b36602557005b600080fd5b348015603557600080fd5b50603c6050565b604051604791906070565b60405180910390f35b60006001905090565b6000819050919050565b606a816059565b82525050565b6000602082019050608360008301846063565b9291505056fea2646970667358221220defb1b1fca12d2d0cdcb178a4117d75fe5c8500fae15807c82c8c3db9b32e5b764736f6c63430008090033",
2731
"linkReferences": {},
2832
"deployedLinkReferences": {}
2933
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
//SPDX-License-Identifier: Unlicense
22
pragma solidity ^0.8.0;
33
contract Basic {
4+
45
constructor() {}
56

67
function ping() public pure returns (int) {
78
return 1;
89
}
10+
11+
receive() external payable { }
912
}

0 commit comments

Comments
 (0)