-
Notifications
You must be signed in to change notification settings - Fork 74
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
chore: add precheck for receivers account in sendRawTransactionCheck #3310
base: main
Are you sure you want to change the base?
Conversation
Test Results 22 files + 2 306 suites +31 58m 58s ⏱️ + 15m 20s For more details on these failures, see this check. Results for commit 3b85b1a. ± Comparison against base commit b5e747f. This pull request removes 3 and adds 4 tests. Note that renamed tests count towards both.
♻️ This comment has been updated with latest results. |
589773c
to
92c28db
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3310 +/- ##
==========================================
+ Coverage 77.96% 84.96% +6.99%
==========================================
Files 66 69 +3
Lines 4475 4641 +166
Branches 1003 1043 +40
==========================================
+ Hits 3489 3943 +454
+ Misses 612 394 -218
+ Partials 374 304 -70
Flags with carried forward coverage won't be shown. Click here to find out more.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! Some blocking requests
packages/relay/src/lib/precheck.ts
Outdated
if (parsedTx.to) { | ||
await this.receiverAccount(parsedTx, requestDetails); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move the parsedTx.to check inside the receiverAccount() precheck instead.
packages/relay/src/lib/precheck.ts
Outdated
* @param {RequestDetails} requestDetails - The request details for logging and tracking. | ||
*/ | ||
async receiverAccount(tx: Transaction, requestDetails: RequestDetails) { | ||
const verifyAccount = await this.mirrorNodeClient.getAccount(tx.to!, requestDetails); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add the parsedTx.to check here. We can make it only run this precheck of parsedTx.to is found so in line 390 we don't have to use the !
operator.
packages/relay/src/lib/precheck.ts
Outdated
const verifyAccount = await this.mirrorNodeClient.getAccount(tx.to!, requestDetails); | ||
|
||
if (verifyAccount !== null && verifyAccount.receiver_sig_required === true) { | ||
throw predefined.INTERNAL_ERROR("Receiver's signature is required."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm not sure if INTERNAL_ERROR
is appropriate here. Looks like other prechecks have their own dedicated predefined errors. Should we follow the pattern and create a dedicated prefined error for receiver account?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, there may be an existing error that could be used but if not add a new one
packages/relay/src/lib/precheck.ts
Outdated
async receiverAccount(tx: Transaction, requestDetails: RequestDetails) { | ||
const verifyAccount = await this.mirrorNodeClient.getAccount(tx.to!, requestDetails); | ||
|
||
if (verifyAccount !== null && verifyAccount.receiver_sig_required === true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you kindly did some extra research and add a comment here stating why we want to make sure receiver_sig_required
attribute is turned off?
* @param {Transaction} tx - The transaction. | ||
* @param {RequestDetails} requestDetails - The request details for logging and tracking. | ||
*/ | ||
async receiverAccount(tx: Transaction, requestDetails: RequestDetails) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add test coverage for this method in the precheck.spec.ts
|
||
if (verifyAccount !== null && verifyAccount.receiver_sig_required === true) { | ||
throw predefined.INTERNAL_ERROR("Receiver's signature is required."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add another check to see if verifyAccount is null then throw a RESOURCE_NOT_FOUND
and include the value of tx.to.
throw predefined.RESOURCE_NOT_FOUND(`Cannot find receiver account: tx.to=${tx.to}`);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Careful on this one since there are valid cases for tx.to
not being set e.g. contract create.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh yeah you're right tx.to is nullable if the transaction is a contract create transaction. Then maybe in the test make the tx.to a non-null address but mock not found. @nadezhdapopovaa please let me know if this is clear enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait this block only executes when tx.to
is not null; therefore, it is still possible for the mirror node to return a null result if tx.to
is not found on the network. I'd suggest instead of checking if (verifyAccount !== null && verifyAccount.receiver_sig_required === true)
for the sig required, we can pull the verifyAccount !== null out and add a new block to check the validity of the verifyAccount. If it's null then throw RESOURCE_NOT_FOUND like how we did with the tx.from.
66403c6
to
7931099
Compare
Signed-off-by: Nadezhda Popova <[email protected]>
…nCheck Signed-off-by: Nadezhda Popova <[email protected]>
…nsactionCheck Signed-off-by: Nadezhda Popova <[email protected]>
Signed-off-by: Nadezhda Popova <[email protected]>
7931099
to
3b85b1a
Compare
Quality Gate passedIssues Measures |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! However, additional tests are still needed. Also a batch of unit tests is required in the precheck.spec.ts
file to functionally test the method.
|
||
if (verifyAccount !== null && verifyAccount.receiver_sig_required === true) { | ||
throw predefined.INTERNAL_ERROR("Receiver's signature is required."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait this block only executes when tx.to
is not null; therefore, it is still possible for the mirror node to return a null result if tx.to
is not found on the network. I'd suggest instead of checking if (verifyAccount !== null && verifyAccount.receiver_sig_required === true)
for the sig required, we can pull the verifyAccount !== null out and add a new block to check the validity of the verifyAccount. If it's null then throw RESOURCE_NOT_FOUND like how we did with the tx.from.
it('should fail "eth_sendRawTransaction" if receiver\'s account has receiver_sig_required enabled', async function () { | ||
const newPrivateKey = PrivateKey.generateED25519(); | ||
const newAccount = await new AccountCreateTransaction() | ||
.setKey(newPrivateKey.publicKey) | ||
.setInitialBalance(100) | ||
.setReceiverSignatureRequired(true) | ||
.freezeWith(servicesNode.client) | ||
.sign(newPrivateKey); | ||
|
||
const transaction = await newAccount.execute(servicesNode.client); | ||
const receipt = await transaction.getReceipt(servicesNode.client); | ||
|
||
if (!receipt.accountId) { | ||
throw new Error('Failed to create new account - accountId is null'); | ||
} | ||
|
||
const toAddress = Utils.idToEvmAddress(receipt.accountId.toString()); | ||
const tx = { | ||
nonce: await accounts[0].wallet.getNonce(), | ||
chainId: CHAIN_ID, | ||
to: toAddress, | ||
from: accounts[0].address, | ||
value: '0x2E90EDD000', | ||
gasLimit: defaultGasLimit, | ||
accessList: [], | ||
maxPriorityFeePerGas: defaultGasPrice, | ||
maxFeePerGas: defaultGasPrice, | ||
}; | ||
|
||
const signedTx = await accounts[0].wallet.signTransaction(tx); | ||
await new Promise((r) => setTimeout(r, 3000)); | ||
|
||
const error = predefined.RECEIVER_SIGNATURE_REQUIRED; | ||
|
||
await Assertions.assertPredefinedRpcError(error, sendRawTransaction, false, relay, [ | ||
signedTx, | ||
requestDetails, | ||
]); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great test! Let's add another test to ensure it works fine when receiver.to
has receiver_sig_required
disabled.
Additionally, if we decide to throw a RESOURCE_NOT_FOUND
error for tx.to
, we should include another test that uses an address not present in the system to verify that it blocks the request.
Description:
Added precheck for receiver's account in sendRawTransactionCheck
Fixes #3286