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

feat: transaction with CONTRACT_NEGATIVE_VALUE breaks some routes #3387

Open
wants to merge 16 commits into
base: main
Choose a base branch
from

Conversation

natanasow
Copy link
Collaborator

@natanasow natanasow commented Jan 14, 2025

Description:

It seems like eth_getBlockByNumber fails because one of the transactions in the block was a CONTRACT_NEGATIVE_VALUE failure. The expectation is for the block to be successfully returned.

Steps to reproduce:

  1. call eth_getBlockByNumber on block 73298898
  2. see "Error invoking RPC: Invalid value - cannot pass negative number" response

The problematic transaction is here

Related issue(s):

Fixes #3367

Notes for reviewer:

Checklist

  • Documented (Code comments, README, etc.)
  • Tested (unit, integration, etc.)

@natanasow natanasow self-assigned this Jan 14, 2025
@natanasow natanasow added the bug Something isn't working label Jan 14, 2025
@natanasow natanasow added this to the 0.65.0 milestone Jan 14, 2025
Copy link

github-actions bot commented Jan 14, 2025

Test Results

 18 files   -   4  236 suites   - 35   33m 0s ⏱️ - 32m 43s
614 tests +  5  610 ✅ + 18  4 💤 +1  0 ❌  - 14 
630 runs   - 216  626 ✅  - 198  4 💤 ±0  0 ❌  - 18 

Results for commit 24e6f30. ± Comparison against base commit 373f1dc.

This pull request removes 4 and adds 9 tests. Note that renamed tests count towards both.
"after all" hook in "RPC Server Acceptance Tests" ‑ RPC Server Acceptance Tests "after all" hook in "RPC Server Acceptance Tests"
"before all" hook for "should execute "eth_getCode" for hts token" ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_getCode "before all" hook for "should execute "eth_getCode" for hts token"
"before all" hook in "@api-batch-2 RPC Server Acceptance Tests" ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests "before all" hook in "@api-batch-2 RPC Server Acceptance Tests"
"before each" hook for "from/to Addresses when transferring HTS tokens to the tokenAddress are in evm and long-zero format" ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests "before each" hook for "from/to Addresses when transferring HTS tokens to the tokenAddress are in evm and long-zero format"
@release should execute "eth_getCode" for contract evm_address ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_getCode @release should execute "eth_getCode" for contract evm_address
@release should execute "eth_getCode" for contract with id converted to evm_address ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_getCode @release should execute "eth_getCode" for contract with id converted to evm_address
should execute "eth_getBlockByNumber", hydrated transactions = true for a block that contains a call with CONTRACT_NEGATIVE_VALUE status ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-1 RPC Server Acceptance Tests RPC Server Acceptance Tests Block related RPC calls should execute "eth_getBlockByNumber", hydrated transactions = true for a block that contains a call with CONTRACT_NEGATIVE_VALUE status
should execute "eth_getCode" for hts token ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_getCode should execute "eth_getCode" for hts token
should not return contract bytecode after sefldestruct ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_getCode should not return contract bytecode after sefldestruct
should return 0x0 for account alias on eth_getCode ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_getCode should return 0x0 for account alias on eth_getCode
should return 0x0 for account evm_address on eth_getCode ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_getCode should return 0x0 for account evm_address on eth_getCode
should return 0x0 for non-existing contract on eth_getCode ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_getCode should return 0x0 for non-existing contract on eth_getCode
should return empty logs if `toBlock` is not found ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-1 RPC Server Acceptance Tests RPC Server Acceptance Tests eth_getLogs should return empty logs if `toBlock` is not found

♻️ This comment has been updated with latest results.

Signed-off-by: nikolay <[email protected]>
Signed-off-by: nikolay <[email protected]>
@natanasow natanasow marked this pull request as ready for review January 14, 2025 15:55
@natanasow natanasow requested review from a team as code owners January 14, 2025 15:55
@natanasow natanasow requested a review from stoyanov-st January 14, 2025 15:55
Signed-off-by: nikolay <[email protected]>
Copy link
Member

@quiet-node quiet-node left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work overall. Blocking as one warning needed to be addressed.

Also, is it feasible to add an e2e test to avoid regression?

packages/relay/src/formatters.ts Outdated Show resolved Hide resolved
packages/relay/src/formatters.ts Outdated Show resolved Hide resolved
@natanasow
Copy link
Collaborator Author

Great work overall. Blocking as one warning needed to be addressed.

Also, is it feasible to add an e2e test to avoid regression?

Adding an e2e test is not a straightforward process because that kind of revert can't be reproduced with an EthereumTransaction. In order to re-create it we have to execute ContractCall SDK call which is out of the relay scope IMO.

I have no problem adding that test if you insist 🚀 🙏.

@quiet-node
Copy link
Member

Great work overall. Blocking as one warning needed to be addressed.
Also, is it feasible to add an e2e test to avoid regression?

Adding an e2e test is not a straightforward process because that kind of revert can't be reproduced with an EthereumTransaction. In order to re-create it we have to execute ContractCall SDK call which is out of the relay scope IMO.

I have no problem adding that test if you insist 🚀 🙏.

Ah I see. Just curious how would you reproduice the problem?

@natanasow
Copy link
Collaborator Author

natanasow commented Jan 17, 2025

Great work overall. Blocking as one warning needed to be addressed.
Also, is it feasible to add an e2e test to avoid regression?

Adding an e2e test is not a straightforward process because that kind of revert can't be reproduced with an EthereumTransaction. In order to re-create it we have to execute ContractCall SDK call which is out of the relay scope IMO.
I have no problem adding that test if you insist 🚀 🙏.

Ah I see. Just curious how would you reproduice the problem?

Sending a negative amount via ContractCallTransaction will be enough while it accepts int64 (not uint64).

Here is the link to the doc https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/readme-1-1/contractcall#contractcalltransactionbody.

@natanasow natanasow requested a review from quiet-node January 17, 2025 13:29
@quiet-node
Copy link
Member

Great work overall. Blocking as one warning needed to be addressed.
Also, is it feasible to add an e2e test to avoid regression?

Adding an e2e test is not a straightforward process because that kind of revert can't be reproduced with an EthereumTransaction. In order to re-create it we have to execute ContractCall SDK call which is out of the relay scope IMO.
I have no problem adding that test if you insist 🚀 🙏.

Ah I see. Just curious how would you reproduice the problem?

Sending a negative amount via ContractCallTransaction will be enough while it accepts int64 (not uint64).

Here is the link to the doc https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/readme-1-1/contractcall#contractcalltransactionbody.

Ah I see. So if it's feasible and do not take crazy amount of time, I would encourage we have an e2e just to make sure no regression later. Thanks much Nikki!

Signed-off-by: nikolay <[email protected]>
@natanasow natanasow requested a review from Nana-EC as a code owner January 28, 2025 11:28
@Nana-EC
Copy link
Collaborator

Nana-EC commented Jan 28, 2025

Great work overall. Blocking as one warning needed to be addressed.

Also, is it feasible to add an e2e test to avoid regression?

Adding an e2e test is not a straightforward process because that kind of revert can't be reproduced with an EthereumTransaction. In order to re-create it we have to execute ContractCall SDK call which is out of the relay scope IMO.

I have no problem adding that test if you insist 🚀 🙏.

Ah I see. Just curious how would you reproduice the problem?

Sending a negative amount via ContractCallTransaction will be enough while it accepts int64 (not uint64).

Here is the link to the doc https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/readme-1-1/contractcall#contractcalltransactionbody.

Ah I see. So if it's feasible and do not take crazy amount of time, I would encourage we have an e2e just to make sure no regression later. Thanks much Nikki!

At the least we could mock the CN response that would cause this and have an integration test that ensures the relay responds as expected.

Signed-off-by: nikolay <[email protected]>
@natanasow natanasow requested review from a team and removed request for a team January 28, 2025 14:44
Signed-off-by: nikolay <[email protected]>
Signed-off-by: nikolay <[email protected]>
Signed-off-by: nikolay <[email protected]>
Signed-off-by: nikolay <[email protected]>
Copy link
Member

@quiet-node quiet-node left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work overall! Left some comments and suggestions

packages/relay/src/formatters.ts Show resolved Hide resolved
Comment on lines +373 to +381
try {
// try to parse it, if the json is valid, numbers within it will be converted
// this case will happen on almost every GET mirror node call
return JSONBigInt.parse(data);
} catch (e) {
// in some unit tests, the mocked returned json is not property formatted
// so we have to preprocess it here with JSON.stringify()
return JSONBigInt.parse(JSON.stringify(data));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm then should we parse the stringified data at the begining?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, if the passed data can be parsed with no exception that means it's in the right format. We need to stringify it only if the returned data is not already stringified e.g. here https://github.com/hashgraph/hedera-json-rpc-relay/blob/main/packages/relay/tests/lib/mirrorNodeClient.spec.ts#L277 and that happens only in tests (mirror node HTTP requests always return the data stringified).

Another approach is to refactor all tests where non-stringified mocked data is returned. E.g. here https://github.com/hashgraph/hedera-json-rpc-relay/blob/main/packages/relay/tests/lib/mirrorNodeClient.spec.ts#L275

E.g. this:

    mock.onGet(`accounts/${alias}${noTransactions}`).reply(200, {
      transactions: [
        {
          nonce: 3,
        },
      ],
      links: {
        next: null,
      },
    });

should be refactored to:

    mock.onGet(`accounts/${alias}${noTransactions}`).reply(200, JSON.stringify({
      transactions: [
        {
          nonce: 3,
        },
      ],
      links: {
        next: null,
      },
    }));

then we can completely get rid of:

              // if the data is not valid, just return it to stick to the current behaviour
              if (data) {
                try {
                  // try to parse it, if the json is valid, numbers within it will be converted
                  // this case will happen on almost every GET mirror node call
                  return JSONBigInt.parse(data);
                } catch (e) {
                  // in some unit tests, the mocked returned json is not property formatted
                  // so we have to preprocess it here with JSON.stringify()
                  return JSONBigInt.parse(JSON.stringify(data));
                }
              }

              return data;

and will become just to:

              // if the data is not valid, just return it to stick to the current behaviour
              if (data) {
                return JSONBigInt.parse(data);
              }

              return data;

Does it make sense now? I can create a follow-up issue/PR removing the try/catch and fixing all tests or I can do it in this one but it will become pretty big. 401 tests that need to be fixed if we get rid of try/catch.

  822 passing (21s)
  401 failing

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@quiet-node just created the follow-up PR #3435.

packages/relay/src/lib/clients/mirrorNodeClient.ts Outdated Show resolved Hide resolved
@quiet-node quiet-node modified the milestones: 0.65.0, 0.65.1 Jan 29, 2025
Copy link

codecov bot commented Jan 30, 2025

Codecov Report

Attention: Patch coverage is 84.21053% with 3 lines in your changes missing coverage. Please review.

Project coverage is 85.41%. Comparing base (373f1dc) to head (24e6f30).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
packages/relay/src/formatters.ts 75.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3387      +/-   ##
==========================================
+ Coverage   84.18%   85.41%   +1.23%     
==========================================
  Files          69       69              
  Lines        4711     4753      +42     
  Branches     1048     1059      +11     
==========================================
+ Hits         3966     4060      +94     
+ Misses        428      396      -32     
+ Partials      317      297      -20     
Flag Coverage Δ
config-service 98.14% <ø> (ø)
relay 79.30% <100.00%> (+0.08%) ⬆️
server 83.30% <ø> (ø)
ws-server 36.66% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/relay/src/lib/clients/mirrorNodeClient.ts 88.48% <100.00%> (+0.16%) ⬆️
packages/relay/src/formatters.ts 69.56% <75.00%> (+5.51%) ⬆️

... and 7 files with indirect coverage changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Transaction with CONTRACT_NEGATIVE_VALUE prevents entire block from being retrieved
4 participants