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

Add a new RPC method eth_getBlockReceipt to get a block's "system calls" receipt #1628

Merged
merged 7 commits into from
Aug 25, 2021

Conversation

oneeman
Copy link
Contributor

@oneeman oneeman commented Jul 16, 2021

Description

If systems calls made by celo-blockchain result in logs, we add a receipt including those logs, which lists the block's hash as the transaction hash field on the receipt. This PR adds a new method, eth_getBlockReceipt to return this receipt when given a block hash or block number.

One key difference, however, is that no receipt is added in case there were no logs, whereas eth_getBlockReceipt will return an empty receipt in such cases, so that the case of no logs can't be confused with the case of not having the block. We may in the future wish to change it so that the receipt is also created during block processing, but that would be a hard fork change.

The method can be added to a web3 instance as follows (where web3 is a Web3 instance, as for example the one available in contractkit as kit.web3):

web3.eth.extend({methods: [{name: "getBlockReceipt", call: "eth_getBlockReceipt", params: 1, outputFormatter: web3.extend.formatters.outputTransactionReceiptFormatter}]})

Once this is merged, released, and deployed to services such as Forno and Figment, we should consider adding support for it in contractkit.

An earlier version of this PR added support for block receipts to eth_getTransactionReceipt, but after more consideration it was found that adding a separate method results in both a cleaner API and a cleaner implementation.

Other changes

Factored out parts of eth_getTransactionReceipt to a separate function so that it can also be used in the new method.

Tested

Manual testing using geth attach, against a client running lightest sync mode (light client) and against a client running fast sync mode (non-light client). For the ones using transaction hashes I also compared the values against those you get using master to see they don't change. Also confirmed that it works via direct RPC calls using http rather than with geth attach.

Note that the results listed below (from geth attach) differ somewhat from the results you get via RPC. For example, some fields which are numbers here are given as hex strings in the RPC (block number, gas used, etc.). This is the same behavior as in other methods such as eth_getTransactionReceipt, eth_getBlockByNumber, etc.

Mainnet, a block without a system receipt (note this block has one transaction, which is why the fake system receipt's transactionIndex is 1):

> eth.getBlockReceipt(eth.getBlock(2937).hash)
{
  blockHash: "0xec1a0a90deae1d622be8a9430050d97b67cb6a3bbc2ba2f54a2315a1b412c915",
  blockNumber: 2937,
  contractAddress: null,
  cumulativeGasUsed: 0,
  from: "0x0000000000000000000000000000000000000000",
  gasUsed: 0,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  status: "0x1",
  to: null,
  transactionHash: "0xec1a0a90deae1d622be8a9430050d97b67cb6a3bbc2ba2f54a2315a1b412c915",
  transactionIndex: 1
}

Mainnet, a block with a system receipt and no transactions:

> eth.getBlockReceipt(eth.getBlock(10000).hash)
{
  blockHash: "0x334111831abd05a6f4d4e157596ffbb95ff9a8bc1da7173c0c7616c738395185",
  blockNumber: 10000,
  contractAddress: null,
  cumulativeGasUsed: 0,
  from: "0x0000000000000000000000000000000000000000",
  gasUsed: 0,
  logs: [{
      address: "0xdfca3a8d7699d8bafe656823ad60c17cb8270ecc",
      blockHash: "0x334111831abd05a6f4d4e157596ffbb95ff9a8bc1da7173c0c7616c738395185",
      blockNumber: 10000,
      data: "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      logIndex: 0,
      removed: false,
      topics: ["0x6e53b2f8b69496c2a175588ad1326dbabe2f66df4d82f817aeca52e3474807fb"],
      transactionHash: "0x334111831abd05a6f4d4e157596ffbb95ff9a8bc1da7173c0c7616c738395185",
      transactionIndex: 0
  }],
  logsBloom: "0x00000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000200000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000",
  status: "0x1",
  to: null,
  transactionHash: "0x334111831abd05a6f4d4e157596ffbb95ff9a8bc1da7173c0c7616c738395185",
  transactionIndex: 0
}

Mainnet, a block with a system receipt and regular transactions:

> eth.getBlockReceipt(eth.getBlock(2947).hash)
{
  blockHash: "0x823dded758ee49fcdf3d51f7aef4aeca4475d22dcceec952e72b6bb3b0ecd51c",
  blockNumber: 2947,
  contractAddress: null,
  cumulativeGasUsed: 0,
  from: "0x0000000000000000000000000000000000000000",
  gasUsed: 0,
  logs: [{
      address: "0xdfca3a8d7699d8bafe656823ad60c17cb8270ecc",
      blockHash: "0x823dded758ee49fcdf3d51f7aef4aeca4475d22dcceec952e72b6bb3b0ecd51c",
      blockNumber: 2947,
      data: "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      logIndex: 1,
      removed: false,
      topics: ["0x6e53b2f8b69496c2a175588ad1326dbabe2f66df4d82f817aeca52e3474807fb"],
      transactionHash: "0x823dded758ee49fcdf3d51f7aef4aeca4475d22dcceec952e72b6bb3b0ecd51c",
      transactionIndex: 1
  }],
  logsBloom: "0x00000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000200000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000",
  status: "0x1",
  to: null,
  transactionHash: "0x823dded758ee49fcdf3d51f7aef4aeca4475d22dcceec952e72b6bb3b0ecd51c",
  transactionIndex: 1
}

Mainnet, transaction receipt with a contract creation transaction's hash (unchanged):

> eth.getTransactionReceipt("0x72c7a019b235d466462262b14df00a3221ec97be7cc8658d06e67bc4359f3704")
{
  blockHash: "0x823dded758ee49fcdf3d51f7aef4aeca4475d22dcceec952e72b6bb3b0ecd51c",
  blockNumber: 2947,
  contractAddress: "0x9380fa34fd9e4fd14c06305fd7b6199089ed4eb9",
  cumulativeGasUsed: 633202,
  from: "0xe23a4c6615669526ab58e9c37088bee4ed2b2dee",
  gasUsed: 633202,
  logs: [{
      address: "0x9380fa34fd9e4fd14c06305fd7b6199089ed4eb9",
      blockHash: "0x823dded758ee49fcdf3d51f7aef4aeca4475d22dcceec952e72b6bb3b0ecd51c",
      blockNumber: 2947,
      data: "0x",
      logIndex: 0,
      removed: false,
      topics: ["0x50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe2", "0x000000000000000000000000e23a4c6615669526ab58e9c37088bee4ed2b2dee"],
      transactionHash: "0x72c7a019b235d466462262b14df00a3221ec97be7cc8658d06e67bc4359f3704",
      transactionIndex: 0
  }],
  logsBloom: "0x00000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000020000000000000800000000100000000000000000000008000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  status: "0x1",
  to: null,
  transactionHash: "0x72c7a019b235d466462262b14df00a3221ec97be7cc8658d06e67bc4359f3704",
  transactionIndex: 0
}

Mainnet, transaction receipt with a non-contract-creation transaction's hash (unchanged):

> eth.getTransactionReceipt("0x3acf66f1e37e2c02f4326044d47494430c1d3467ce0508f2720405895cd6b3af")
{
  blockHash: "0xe8363444c3df2d1d44517a7b5f2472aeb9d21fbf2766dd57698f4c586d7bbef3",
  blockNumber: 2950,
  contractAddress: null,
  cumulativeGasUsed: 24251,
  from: "0xe23a4c6615669526ab58e9c37088bee4ed2b2dee",
  gasUsed: 24251,
  logs: [{
      address: "0x9380fa34fd9e4fd14c06305fd7b6199089ed4eb9",
      blockHash: "0xe8363444c3df2d1d44517a7b5f2472aeb9d21fbf2766dd57698f4c586d7bbef3",
      blockNumber: 2950,
      data: "0x",
      logIndex: 0,
      removed: false,
      topics: ["0x50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe2", "0x000000000000000000000000e23a4c6615669526ab58e9c37088bee4ed2b2dee"],
      transactionHash: "0x3acf66f1e37e2c02f4326044d47494430c1d3467ce0508f2720405895cd6b3af",
      transactionIndex: 0
  }],
  logsBloom: "0x00000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000020000000000000800000000100000000000000000000008000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  status: "0x1",
  to: "0x9380fa34fd9e4fd14c06305fd7b6199089ed4eb9",
  transactionHash: "0x3acf66f1e37e2c02f4326044d47494430c1d3467ce0508f2720405895cd6b3af",
  transactionIndex: 0
}

Mainnet, using a hash that does not correspond to any block:

> eth.getBlockReceipt("0x8888888888888888888888888888888888888888888888888888888888888888")
null

Backwards compatibility

No changes to existing functionality, it only adds a new RPC method.

@oneeman oneeman force-pushed the oneeman/rpc-support-block-receipt branch from 52e3072 to ca9373f Compare July 16, 2021 20:05
If systems calls made by celo-blockchain result in logs, we add a receipt including those logs, which lists the block's hash as the transaction hash field on the receipt.  This PR adds support to eth_getTransactionReceipt to return this receipt when given a block hash.  One key difference, however, is that no receipt is added in case there were no logs, whereas eth_getTransactionReceipt will return an empty receipt in such cases, so that the case of no logs can't be confused with the case of not having the block.  We may in the future wish to change it so that the receipt is also created during block processing, but that would be a hard fork change.
@oneeman oneeman force-pushed the oneeman/rpc-support-block-receipt branch from ca9373f to a90e71f Compare July 16, 2021 20:21
@mcortesi
Copy link
Contributor

Why do we have examples of contract creation and not contract creation? I guess those are regular transactions so should not be affected by this PR?

Also, not sure if ease, but when creating an empty receipt it would good to use the txIndex that corresponds to "after the last tx". In the example was zero, but was not clear if the block was empty

@oneeman
Copy link
Contributor Author

oneeman commented Jul 16, 2021

Why do we have examples of contract creation and not contract creation? I guess those are regular transactions so should not be affected by this PR?

Correct, they're not affected, just including them as part of the testing (to confirm they're not affected). An earlier version I tried had a bug that broke that functionality.

Also, not sure if ease, but when creating an empty receipt it would good to use the txIndex that corresponds to "after the last tx". In the example was zero, but was not clear if the block was empty

It's ok as is, because the method's code sets that field (and some other "derived fields") in the return value:

		"transactionIndex":  hexutil.Uint64(index),

So even though it isn't set on the receipt variable's object, it will be set correctly in the response. I will see whether I can replace that example with one for a block that does have some transactions so that the example can reflect that as well.

Also, I will check the e2e transfer test which seems to be failing.

@oneeman
Copy link
Contributor Author

oneeman commented Jul 16, 2021

The failing end-to-end-transfer-test is due to #1627 (the tests include sending transactions through light clients, and it seems like web3 polls using eth_getTransactionReceipt). This means that we shouldn't merge this PR until we fix #1627, because doing so would essentially break the ability to send transactions through light clients and wait for their receipts using contractkit or web3 (kind of obvious in hindsight).

@oneeman
Copy link
Contributor Author

oneeman commented Jul 16, 2021

Updated the example of a block without a system receipt to use block 2937 (which contains one transaction) instead of block 10 (which doesn't contain any transactions).

@oneeman oneeman changed the title Add support for "system calls receipt" in eth_getTransactionReceipt Add a new RPC method eth_getBlockReceipt to get a block's "system calls" receipt Jul 21, 2021
@oneeman
Copy link
Contributor Author

oneeman commented Jul 21, 2021

Updated the PR to add a new method eth_getBlockReceipt instead of overloading eth_getTransactionReceipt. Updated the PR description accordingly. The new method currently takes in a block hash. I initially had it take either a block number or block hash, but when you do that it also accepts "earlier", "latest", and "pending". And, while they were working, "pending" doesn't really make sense for this method, so I changed it to take only the hash. But this is up for discussion and can be changed back or to something else.

@codecov
Copy link

codecov bot commented Jul 21, 2021

Codecov Report

Merging #1628 (aa6da2a) into master (8b8e717) will increase coverage by 0.02%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1628      +/-   ##
==========================================
+ Coverage   56.04%   56.07%   +0.02%     
==========================================
  Files         606      606              
  Lines       80261    80261              
==========================================
+ Hits        44980    45004      +24     
+ Misses      31753    31727      -26     
- Partials     3528     3530       +2     
Impacted Files Coverage Δ
p2p/discover/ntp.go 54.76% <0.00%> (-11.91%) ⬇️
core/state_prefetcher.go 86.66% <0.00%> (-6.67%) ⬇️
...nsensus/istanbul/core/roundstate_save_decorator.go 91.37% <0.00%> (-3.45%) ⬇️
p2p/rlpx.go 71.38% <0.00%> (-1.14%) ⬇️
p2p/peer.go 73.33% <0.00%> (-0.79%) ⬇️
consensus/istanbul/core/commit.go 66.44% <0.00%> (-0.66%) ⬇️
eth/downloader/downloader.go 76.19% <0.00%> (ø)
p2p/simulations/http.go 70.10% <0.00%> (+0.54%) ⬆️
trie/proof.go 77.15% <0.00%> (+1.12%) ⬆️
consensus/istanbul/core/handler.go 83.20% <0.00%> (+1.60%) ⬆️
... and 5 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8b8e717...aa6da2a. Read the comment docs.

@oneeman oneeman marked this pull request as ready for review August 23, 2021 20:31
@oneeman oneeman requested a review from a team as a code owner August 23, 2021 20:31
@oneeman oneeman requested review from gastonponti, piersy and mcortesi and removed request for a team August 23, 2021 20:31
Copy link
Contributor

@mcortesi mcortesi left a comment

Choose a reason for hiding this comment

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

LGTM

@oneeman oneeman merged commit 0458ca3 into master Aug 25, 2021
@oneeman oneeman deleted the oneeman/rpc-support-block-receipt branch August 25, 2021 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants