Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Use H64 for Block Nonce #1396

Merged
merged 2 commits into from
Jun 23, 2022
Merged

Conversation

jpopesculian
Copy link
Contributor

@jpopesculian jpopesculian commented Jun 20, 2022

Motivation

geth and other libraries represent the block nonce as a 8 byte fixed array. ethers-rs uses an unsigned 64 bit integer to represent the nonce. This causes the nonce to be serialized without leading 0's as specified by the JSON-RPC spec, which therefore may cause deserialization problems with other libraries that expect a fixed byte array. This is the case with web3 for example which fails to deserialize the nonce because it uses H64

Solution

Use H64 instead of U64 for nonce

PR Checklist

  • Added Tests
  • Added Documentation
  • Updated the changelog

Signed-off-by: Julian Popescu <hi@julian.dev>
Signed-off-by: Julian Popescu <hi@julian.dev>
Copy link
Collaborator

@mattsse mattsse left a comment

Choose a reason for hiding this comment

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

This causes the nonce to be serialized without leading 0's as specified by the JSON-RPC spec, which therefore may cause deserialization problems with other libraries that expect a fixed byte array.

I don't think we should deviate from the spec just because other libraries do that.

When encoding quantities (integers, numbers): encode as hex, prefix with "0x", the most compact representation (slight exception: zero should be represented as "0x0").

@@ -81,7 +81,7 @@ pub struct Block<TX> {
pub mix_hash: Option<H256>,
/// Nonce
#[cfg(not(feature = "celo"))]
pub nonce: Option<U64>,
pub nonce: Option<H64>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

how does H64 serialize, deserialize compared to U64?

H64 is a hash type, and since nonce is an uint, this change doesn't seem necessary,

also H64 lacks common conversion trait impls for primitive types and I'm not sure it even as a as_u64 function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

H64 will encode as a byte array, and not like number so it won't serialize to the most compact representation and it will expect the length to be 16 on deserialization. The reason this change is necessary is because a client of anvil (in my experience here graph-node) may expect the the value to have a length of 16 (or 18 with 0x prefix) and will fail to deserialize something like 0x0. Because the specs say this value is Bytes8 https://github.com/ethereum/execution-specs/blob/master/src/ethereum/muir_glacier/eth_types.py#L118 and geth also implements it as such, I think failing to deserialize 0x0 for the nonce is reasonable

@gakonst
Copy link
Owner

gakonst commented Jun 22, 2022

Did we encounter this as a bug in someone's code, or is this a proactive change?

@mattsse
Copy link
Collaborator

mattsse commented Jun 23, 2022

I just double checked the RPC docs

for blocks, nonce is indeed DATA whereas only for tx it is QUANTITY...

so @jpopesculian you're totally right, and we should change this to H64,
geth also returns block nonces like that and so does hardhat
"nonce": "0x0000000000000042",

ref foundry-rs/foundry#2088

@mattsse
Copy link
Collaborator

mattsse commented Jun 23, 2022

@gakonst we can merge this, the failing tests are due to installed Anvil which uses the old nonce format

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants