eqlabs / pathfinder

A Starknet full node written in Rust
https://eqlabs.github.io/pathfinder/
Other
613 stars 222 forks source link

Implement 0.13.2 block hash #2077

Closed kkovaacs closed 2 weeks ago

kkovaacs commented 1 month ago

The new algorithm is already implemented in the starknet-api crate.

More info: https://community.starknet.io/t/starknet-v0-13-2-pre-release-notes/114223#new-block-hash-definition-4

sistemd commented 1 month ago

The following needs to be changed:

Currently, we calculate state diff commitments as a Poseidon hash over the following:

  1. A single 0 element.
  2. _Poseidon(num deployed contracts, address 0, class hash 0, address 1, class hash 1, ...)_
  3. _Poseidon(num declared classes, class hash 0, compiled class hash 0, class hash 1, compiled class hash 1, ...)_
  4. _Poseidon(num old declared classes, class hash 0, class hash 1, ...)_
  5. A single 0 element.
  6. A single 1 element.
  7. _Poseidon(num updated contracts, contract address 0, num of updates in contract 0, key 0, value 0, key 1, value 1, ... contract address 1, ..., num of updated contract nonces, address 0, nonce 0, address 1, nonce 1)_.

Note that all of the lists are ordered (lists of pairs are ordered by the first element of the pair), which is why our code uses BTreeMap and BTreeHash.

In v0.13.2, the structure gets more flat, i.e. there is no nested hashing, and the first element is a string instead of a single 0. The state diff commitment should be a Poseidon hash over the following:

  1. The felt representation of the string "STARKNET_STATE_DIFF0".
  2. num deployed contracts, address 0, class hash 0, address 1, class hash 1, ...
  3. num declared classes, class hash 0, compiled class hash 0, class hash 1, compiled class hash 1, ...
  4. num old declared classes, class hash 0, class hash 1, ...
  5. A single 0 element.
  6. A single 1 element.
  7. num updated contracts, contract address 0, num of updates in contract 0, key 0, value 0, key 1, value 1, ... contract address 1, ...
  8. num of updated contract nonces, address 0, nonce 0, address 1, nonce 1, ...

The receipt commitment is a Merkle tree hash where the leaves are Poseidon hashes over the following:

  1. Transaction hash.
  2. Actual fee paid.
  3. Poseidon(num of messages sent, from address 0, to address 0, num payloads 0, payload 0, payload 1, ..., from address 1, to address 1, ...).
  4. If transaction succeeded, a single 0 felt. If it failed, StarknetKeccak(revert reason as ASCII bytes).
  5. A single 0 felt.
  6. L1 gas consumed by transaction.
  7. L1 data gas consumed by transaction.

The block hash should be a Poseidon hash (currently it's Pedersen!) over the following:

  1. The felt representation of the string "STARKNET_BLOCK_HASH0".
  2. Block number.
  3. State root.
  4. Sequencer address.
  5. Block timestamp.
  6. The concatenation of the following values, in big endian:
    1. Transaction count (64 bits).
    2. Event count (64 bits).
    3. State diff length (64 bits) = num of storage diffs in all contacts + num of nonce updates + num deployed contracts + num declared contracts + num old declared contracts.
    4. A single 0 byte if L1 data availability mode is calldata, 0b10000000 otherwise.
    5. 7 zero bytes for padding.
  7. State diff commitment as defined above.
  8. Transaction commitment as defined above.
  9. Event commitment as defined above.
  10. Receipt commitment as defined above.
  11. L1 gas price in wei.
  12. L1 gas price in fri.
  13. L1 data gas price in wei.
  14. L1 data gas price in fri.
  15. The felt representation of the Starknet version from the block header, where the version is encoded as a string.
  16. A single 0 felt.
  17. Parent block hash.