2022-10-16 10:11:45 -07:00
|
|
|
use std::collections::HashMap;
|
2023-03-27 17:30:11 -06:00
|
|
|
use std::ops::Deref;
|
2022-10-16 10:11:45 -07:00
|
|
|
|
2023-03-27 17:30:11 -06:00
|
|
|
use eth_trie_utils::nibbles::Nibbles;
|
2023-03-28 14:38:58 -06:00
|
|
|
use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie};
|
2022-10-04 15:12:44 -07:00
|
|
|
use ethereum_types::{BigEndianHash, H256, U256};
|
2022-10-16 10:11:45 -07:00
|
|
|
use keccak_hash::keccak;
|
2022-10-04 15:12:44 -07:00
|
|
|
use rlp_derive::{RlpDecodable, RlpEncodable};
|
2022-09-18 09:45:31 -07:00
|
|
|
|
|
|
|
|
use crate::cpu::kernel::constants::trie_type::PartialTrieType;
|
2022-09-22 20:09:48 -07:00
|
|
|
use crate::generation::TrieInputs;
|
2023-03-28 14:38:58 -06:00
|
|
|
use crate::Node;
|
2022-09-18 09:45:31 -07:00
|
|
|
|
2022-10-04 15:12:44 -07:00
|
|
|
#[derive(RlpEncodable, RlpDecodable, Debug)]
|
2022-12-03 21:09:57 -08:00
|
|
|
pub struct AccountRlp {
|
|
|
|
|
pub nonce: U256,
|
|
|
|
|
pub balance: U256,
|
|
|
|
|
pub storage_root: H256,
|
|
|
|
|
pub code_hash: H256,
|
2022-10-04 15:12:44 -07:00
|
|
|
}
|
|
|
|
|
|
2022-12-06 23:05:47 -08:00
|
|
|
impl Default for AccountRlp {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
nonce: U256::zero(),
|
|
|
|
|
balance: U256::zero(),
|
2023-03-28 14:38:58 -06:00
|
|
|
storage_root: HashedPartialTrie::from(Node::Empty).hash(),
|
2022-12-06 23:05:47 -08:00
|
|
|
code_hash: keccak([]),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-22 20:09:48 -07:00
|
|
|
pub(crate) fn all_mpt_prover_inputs_reversed(trie_inputs: &TrieInputs) -> Vec<U256> {
|
|
|
|
|
let mut inputs = all_mpt_prover_inputs(trie_inputs);
|
|
|
|
|
inputs.reverse();
|
|
|
|
|
inputs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Generate prover inputs for the initial MPT data, in the format expected by `mpt/load.asm`.
|
|
|
|
|
pub(crate) fn all_mpt_prover_inputs(trie_inputs: &TrieInputs) -> Vec<U256> {
|
2022-09-18 09:45:31 -07:00
|
|
|
let mut prover_inputs = vec![];
|
|
|
|
|
|
2022-10-16 10:11:45 -07:00
|
|
|
let storage_tries_by_state_key = trie_inputs
|
|
|
|
|
.storage_tries
|
|
|
|
|
.iter()
|
2022-12-15 13:56:48 -08:00
|
|
|
.map(|(address, storage_trie)| {
|
|
|
|
|
let key = Nibbles::from_bytes_be(keccak(address).as_bytes()).unwrap();
|
|
|
|
|
(key, storage_trie)
|
|
|
|
|
})
|
2022-10-16 10:11:45 -07:00
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
mpt_prover_inputs_state_trie(
|
|
|
|
|
&trie_inputs.state_trie,
|
|
|
|
|
empty_nibbles(),
|
|
|
|
|
&mut prover_inputs,
|
|
|
|
|
&storage_tries_by_state_key,
|
|
|
|
|
);
|
2022-09-18 09:45:31 -07:00
|
|
|
|
2022-09-22 20:09:48 -07:00
|
|
|
mpt_prover_inputs(&trie_inputs.transactions_trie, &mut prover_inputs, &|rlp| {
|
|
|
|
|
rlp::decode_list(rlp)
|
|
|
|
|
});
|
2022-09-18 09:45:31 -07:00
|
|
|
|
2022-09-22 20:09:48 -07:00
|
|
|
mpt_prover_inputs(&trie_inputs.receipts_trie, &mut prover_inputs, &|_rlp| {
|
|
|
|
|
// TODO: Decode receipt RLP.
|
|
|
|
|
vec![]
|
|
|
|
|
});
|
2022-09-18 09:45:31 -07:00
|
|
|
|
|
|
|
|
prover_inputs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Given a trie, generate the prover input data for that trie. In essence, this serializes a trie
|
|
|
|
|
/// into a `U256` array, in a simple format which the kernel understands. For example, a leaf node
|
|
|
|
|
/// is serialized as `(TYPE_LEAF, key, value)`, where key is a `(nibbles, depth)` pair and `value`
|
|
|
|
|
/// is a variable-length structure which depends on which trie we're dealing with.
|
|
|
|
|
pub(crate) fn mpt_prover_inputs<F>(
|
2023-03-28 14:38:58 -06:00
|
|
|
trie: &HashedPartialTrie,
|
2022-09-18 09:45:31 -07:00
|
|
|
prover_inputs: &mut Vec<U256>,
|
2022-10-16 10:11:45 -07:00
|
|
|
parse_value: &F,
|
2022-09-18 09:45:31 -07:00
|
|
|
) where
|
|
|
|
|
F: Fn(&[u8]) -> Vec<U256>,
|
|
|
|
|
{
|
|
|
|
|
prover_inputs.push((PartialTrieType::of(trie) as u32).into());
|
2023-03-27 17:30:11 -06:00
|
|
|
|
|
|
|
|
match trie.deref() {
|
|
|
|
|
Node::Empty => {}
|
|
|
|
|
Node::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())),
|
|
|
|
|
Node::Branch { children, value } => {
|
2022-10-06 16:05:28 -07:00
|
|
|
if value.is_empty() {
|
2022-10-17 11:31:08 -07:00
|
|
|
prover_inputs.push(U256::zero()); // value_present = 0
|
2022-10-06 16:05:28 -07:00
|
|
|
} else {
|
2022-10-16 10:11:45 -07:00
|
|
|
let parsed_value = parse_value(value);
|
2022-10-17 11:31:08 -07:00
|
|
|
prover_inputs.push(U256::one()); // value_present = 1
|
2022-10-16 10:11:45 -07:00
|
|
|
prover_inputs.extend(parsed_value);
|
2022-10-06 16:05:28 -07:00
|
|
|
}
|
2022-09-18 09:45:31 -07:00
|
|
|
for child in children {
|
2022-10-16 10:11:45 -07:00
|
|
|
mpt_prover_inputs(child, prover_inputs, parse_value);
|
2022-09-18 09:45:31 -07:00
|
|
|
}
|
|
|
|
|
}
|
2023-03-27 17:30:11 -06:00
|
|
|
Node::Extension { nibbles, child } => {
|
2022-09-18 09:45:31 -07:00
|
|
|
prover_inputs.push(nibbles.count.into());
|
|
|
|
|
prover_inputs.push(nibbles.packed);
|
2022-10-16 10:11:45 -07:00
|
|
|
mpt_prover_inputs(child, prover_inputs, parse_value);
|
2022-09-18 09:45:31 -07:00
|
|
|
}
|
2023-03-27 17:30:11 -06:00
|
|
|
Node::Leaf { nibbles, value } => {
|
2022-09-18 09:45:31 -07:00
|
|
|
prover_inputs.push(nibbles.count.into());
|
|
|
|
|
prover_inputs.push(nibbles.packed);
|
2022-10-16 10:11:45 -07:00
|
|
|
let leaf = parse_value(value);
|
2022-09-22 20:09:48 -07:00
|
|
|
prover_inputs.extend(leaf);
|
2022-09-18 09:45:31 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-16 10:11:45 -07:00
|
|
|
|
|
|
|
|
/// Like `mpt_prover_inputs`, but for the state trie, which is a bit unique since each value
|
|
|
|
|
/// leads to a storage trie which we recursively traverse.
|
|
|
|
|
pub(crate) fn mpt_prover_inputs_state_trie(
|
2023-03-28 14:38:58 -06:00
|
|
|
trie: &HashedPartialTrie,
|
2022-10-16 10:11:45 -07:00
|
|
|
key: Nibbles,
|
|
|
|
|
prover_inputs: &mut Vec<U256>,
|
2023-03-28 14:38:58 -06:00
|
|
|
storage_tries_by_state_key: &HashMap<Nibbles, &HashedPartialTrie>,
|
2022-10-16 10:11:45 -07:00
|
|
|
) {
|
|
|
|
|
prover_inputs.push((PartialTrieType::of(trie) as u32).into());
|
2023-03-27 17:30:11 -06:00
|
|
|
match trie.deref() {
|
|
|
|
|
Node::Empty => {}
|
|
|
|
|
Node::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())),
|
|
|
|
|
Node::Branch { children, value } => {
|
2022-10-16 10:11:45 -07:00
|
|
|
assert!(value.is_empty(), "State trie should not have branch values");
|
2022-10-17 11:31:08 -07:00
|
|
|
prover_inputs.push(U256::zero()); // value_present = 0
|
2022-10-16 10:11:45 -07:00
|
|
|
|
|
|
|
|
for (i, child) in children.iter().enumerate() {
|
2022-10-24 16:23:03 -06:00
|
|
|
let extended_key = key.merge_nibbles(&Nibbles {
|
2022-10-16 10:11:45 -07:00
|
|
|
count: 1,
|
|
|
|
|
packed: i.into(),
|
|
|
|
|
});
|
|
|
|
|
mpt_prover_inputs_state_trie(
|
|
|
|
|
child,
|
|
|
|
|
extended_key,
|
|
|
|
|
prover_inputs,
|
|
|
|
|
storage_tries_by_state_key,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-27 17:30:11 -06:00
|
|
|
Node::Extension { nibbles, child } => {
|
2022-10-16 10:11:45 -07:00
|
|
|
prover_inputs.push(nibbles.count.into());
|
|
|
|
|
prover_inputs.push(nibbles.packed);
|
2022-10-24 16:23:03 -06:00
|
|
|
let extended_key = key.merge_nibbles(nibbles);
|
2022-10-16 10:11:45 -07:00
|
|
|
mpt_prover_inputs_state_trie(
|
|
|
|
|
child,
|
|
|
|
|
extended_key,
|
|
|
|
|
prover_inputs,
|
|
|
|
|
storage_tries_by_state_key,
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-03-27 17:30:11 -06:00
|
|
|
Node::Leaf { nibbles, value } => {
|
2022-10-16 10:11:45 -07:00
|
|
|
let account: AccountRlp = rlp::decode(value).expect("Decoding failed");
|
|
|
|
|
let AccountRlp {
|
|
|
|
|
nonce,
|
|
|
|
|
balance,
|
|
|
|
|
storage_root,
|
|
|
|
|
code_hash,
|
|
|
|
|
} = account;
|
|
|
|
|
|
2023-03-28 14:38:58 -06:00
|
|
|
let storage_hash_only = HashedPartialTrie::new(Node::Hash(storage_root));
|
2023-02-27 17:34:12 -08:00
|
|
|
let merged_key = key.merge_nibbles(nibbles);
|
2023-03-28 14:38:58 -06:00
|
|
|
let storage_trie: &HashedPartialTrie = storage_tries_by_state_key
|
2023-02-27 17:34:12 -08:00
|
|
|
.get(&merged_key)
|
2022-10-16 10:11:45 -07:00
|
|
|
.copied()
|
|
|
|
|
.unwrap_or(&storage_hash_only);
|
|
|
|
|
|
2023-03-27 17:30:11 -06:00
|
|
|
assert_eq!(storage_trie.hash(), storage_root,
|
2022-10-16 10:11:45 -07:00
|
|
|
"In TrieInputs, an account's storage_root didn't match the associated storage trie hash");
|
|
|
|
|
|
|
|
|
|
prover_inputs.push(nibbles.count.into());
|
|
|
|
|
prover_inputs.push(nibbles.packed);
|
|
|
|
|
prover_inputs.push(nonce);
|
|
|
|
|
prover_inputs.push(balance);
|
|
|
|
|
mpt_prover_inputs(storage_trie, prover_inputs, &parse_storage_value);
|
|
|
|
|
prover_inputs.push(code_hash.into_uint());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_storage_value(value_rlp: &[u8]) -> Vec<U256> {
|
|
|
|
|
let value: U256 = rlp::decode(value_rlp).expect("Decoding failed");
|
|
|
|
|
vec![value]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn empty_nibbles() -> Nibbles {
|
|
|
|
|
Nibbles {
|
|
|
|
|
count: 0,
|
|
|
|
|
packed: U256::zero(),
|
|
|
|
|
}
|
|
|
|
|
}
|