Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: resolved evm addresses for from and to addresses in returned transactions #2185

Merged
merged 7 commits into from
Mar 12, 2024
94 changes: 69 additions & 25 deletions packages/relay/src/lib/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1230,19 +1230,19 @@ export class EthImpl implements Eth {
this.logger.trace(
`${requestIdPrefix} getTransactionByBlockHashAndIndex(hash=${blockHash}, index=${transactionIndex})`,
);
return this.mirrorNodeClient
.getContractResults(
{ blockHash: blockHash, transactionIndex: Number(transactionIndex) },
undefined,

try {
return await this.getTransactionByBlockHashOrBlockNumAndIndex(
{ title: 'blockHash', value: blockHash },
transactionIndex,
requestIdPrefix,
)
.then((contractResults) => formatContractResult(contractResults[0] ?? null))
.catch((error: any) => {
throw this.common.genericErrorHandler(
error,
`${requestIdPrefix} Failed to retrieve contract result for blockHash ${blockHash} and index=${transactionIndex}`,
);
});
);
} catch (error) {
throw this.common.genericErrorHandler(
error,
`${requestIdPrefix} Failed to retrieve contract result for blockHash ${blockHash} and index=${transactionIndex}`,
);
}
}

/**
Expand All @@ -1260,19 +1260,19 @@ export class EthImpl implements Eth {
`${requestIdPrefix} getTransactionByBlockNumberAndIndex(blockNum=${blockNumOrTag}, index=${transactionIndex})`,
);
const blockNum = await this.translateBlockTag(blockNumOrTag, requestIdPrefix);
return this.mirrorNodeClient
.getContractResults(
{ blockNumber: blockNum, transactionIndex: Number(transactionIndex) },
undefined,

try {
return await this.getTransactionByBlockHashOrBlockNumAndIndex(
{ title: 'blockNumber', value: blockNum },
transactionIndex,
requestIdPrefix,
)
.then((contractResults) => formatContractResult(contractResults[0] ?? null))
.catch((e: any) => {
throw this.common.genericErrorHandler(
e,
`${requestIdPrefix} Failed to retrieve contract result for blockNum ${blockNum} and index=${transactionIndex}`,
);
});
);
} catch (error) {
throw this.common.genericErrorHandler(
error,
`${requestIdPrefix} Failed to retrieve contract result for blockNum ${blockNum} and index=${transactionIndex}`,
);
}
}

/**
Expand Down Expand Up @@ -1500,6 +1500,40 @@ export class EthImpl implements Eth {
}
}

/**
* Gets transactions by block hash or block number and index with resolved EVM addresses
* @param blockParam
* @param transactionIndex
* @param requestIdPrefix
* @returns Promise<Transaction | null>
*/
private async getTransactionByBlockHashOrBlockNumAndIndex(
blockParam: {
title: 'blockHash' | 'blockNumber';
value: string | number;
},
transactionIndex: string,
requestIdPrefix?: string,
): Promise<Transaction | null> {
const contractResults = await this.mirrorNodeClient.getContractResults(
{
[blockParam.title]: blockParam.value,
transactionIndex: Number(transactionIndex),
},
undefined,
requestIdPrefix,
);

if (!contractResults[0]) return null;

const resolvedToAddress = await this.resolveEvmAddress(contractResults[0].to, requestIdPrefix);
const resolvedFromAddress = await this.resolveEvmAddress(contractResults[0].from, requestIdPrefix, [
constants.TYPE_ACCOUNT,
]);

return formatContractResult({ ...contractResults[0], from: resolvedFromAddress, to: resolvedToAddress });
}

// according to EIP-1898 (https://eips.ethereum.org/EIPS/eip-1898) block param can either be a string (blockNumber or Block Tag) or an object (blockHash or blockNumber)
private async extractBlockNumberOrTag(
blockParam: string | object | null,
Expand Down Expand Up @@ -2004,8 +2038,18 @@ export class EthImpl implements Eth {
throw predefined.MAX_BLOCK_SIZE(blockResponse.count);
}

// prepare transactionArray
let transactionArray: any[] = [];
for (const contractResult of contractResults) {
contractResult.from = await this.resolveEvmAddress(contractResult.from, requestIdPrefix, [
constants.TYPE_ACCOUNT,
]);
contractResult.to = await this.resolveEvmAddress(contractResult.to, requestIdPrefix);

transactionArray.push(showDetails ? formatContractResult(contractResult) : contractResult.hash);
}

const blockHash = toHash32(blockResponse.hash);
const transactionArray = contractResults.map((cr) => (showDetails ? formatContractResult(cr) : cr.hash));
// Gating feature in case of unexpected behavior with other apps.
if (this.shouldPopulateSyntheticContractResults) {
this.filterAndPopulateSyntheticContractResults(showDetails, logs, transactionArray, requestIdPrefix);
Expand Down
26 changes: 26 additions & 0 deletions packages/server/tests/acceptance/rpc_batch1.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () {
const ONE_TINYBAR = Utils.add0xPrefix(Utils.toHex(Constants.TINYBAR_TO_WEIBAR_COEF));
const sendRawTransaction = relay.sendRawTransaction;

/**
* resolves long zero addresses to EVM addresses by querying mirror node
* @param tx: any - supposedly a proper transaction that has `from` and `to` fields
* @returns Promise<{from: any|null, to: any|null}>
*/
const resolveAccountEvmAddresses = async (tx: any) => {
const fromAccountInfo = await mirrorNode.get(`/accounts/${tx.from}`);
const toAccountInfo = await mirrorNode.get(`/accounts/${tx.to}`);
return {
from: fromAccountInfo?.evm_address ?? tx.from,
to: toAccountInfo?.evm_address ?? tx.to,
};
};

describe('RPC Server Acceptance Tests', function () {
this.timeout(240 * 1000); // 240 seconds

Expand Down Expand Up @@ -88,6 +102,10 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () {
`/contracts/${contractId}/results/${contractExecuteTimestamp}`,
requestId,
);

const resolvedAddresses = await resolveAccountEvmAddresses(mirrorContractDetails);
mirrorContractDetails.from = resolvedAddresses.from;
mirrorContractDetails.to = resolvedAddresses.to;
});

this.beforeEach(async () => {
Expand Down Expand Up @@ -376,6 +394,14 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () {
await mirrorNode.get(`/contracts/${res.contract_id}/results/${res.timestamp}`, requestId),
);
}

// resolve EVM address for `from` and `to`
for (const mirrorTx of mirrorTransactions) {
const resolvedAddresses = await resolveAccountEvmAddresses(mirrorTx);

mirrorTx.from = resolvedAddresses.from;
mirrorTx.to = resolvedAddresses.to;
}
});

it('should execute "eth_getBlockByHash", hydrated transactions = false', async function () {
Expand Down
Loading