Skip to content

Commit

Permalink
Add support for keccak256 trie host functions (#906)
Browse files Browse the repository at this point in the history
* Add support for keccak256 trie host functions

* CHANGELOG

* Replace `tiny_keccak` with `sha3`

* Clean up `ext_hashing_sha2_256_version_1` implementation

* Fix full node build

* Fix doctest
  • Loading branch information
tomaka authored Jul 13, 2023
1 parent 2019705 commit 0a68d97
Show file tree
Hide file tree
Showing 16 changed files with 244 additions and 91 deletions.
21 changes: 11 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions full-node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ async fn open_database(
partial_key,
storage_value,
},
trie::HashFunction::Blake2,
is_root_node,
)
.unwrap();
Expand Down
2 changes: 1 addition & 1 deletion lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ schnorrkel = { version = "0.10.2", default-features = false, features = ["preaud
serde = { version = "1.0.167", default-features = false, features = ["alloc", "derive"] }
serde_json = { version = "1.0.102", default-features = false, features = ["alloc", "raw_value"] }
sha2 = { version = "0.10.7", default-features = false }
sha3 = { version = "0.10.8", default-features = false }
siphasher = { version = "0.3.10", default-features = false }
slab = { version = "0.4.8", default-features = false }
smallvec = { version = "1.11.0", default-features = false }
tiny-keccak = { version = "2.0", features = ["keccak"] }
twox-hash = { version = "1.6.3", default-features = false }
wasmi = { version = "0.30.0", default-features = false }
x25519-dalek = { version = "2.0.0-rc.3", default-features = false, features = ["alloc", "precomputed-tables", "static_secrets", "zeroize"] }
Expand Down
2 changes: 1 addition & 1 deletion lib/src/chain/chain_information/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ impl ChainInformationBuild {
parent_hash: &[0; 32],
number: 0,
state_root: &state_trie_root_hash,
extrinsics_root: &trie::EMPTY_TRIE_MERKLE_VALUE,
extrinsics_root: &trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE,
digest: header::DigestRef::empty(),
}
.scale_encoding_vec(inner.block_number_bytes);
Expand Down
3 changes: 2 additions & 1 deletion lib/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ impl ChainSpec {
match self.genesis_storage() {
GenesisStorage::TrieRootHash(hash) => *hash,
GenesisStorage::Items(genesis_storage) => {
let mut calculation = trie::calculate_root::root_merkle_value();
let mut calculation =
trie::calculate_root::root_merkle_value(trie::HashFunction::Blake2);

loop {
match calculation {
Expand Down
3 changes: 2 additions & 1 deletion lib/src/database/full_sqlite/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ fn empty_database_fill_then_query() {
partial_key,
storage_value,
},
trie::HashFunction::Blake2,
is_root_node,
)
.unwrap();
Expand All @@ -118,7 +119,7 @@ fn empty_database_fill_then_query() {
let state_root = &trie
.root_user_data()
.map(|n| *<&[u8; 32]>::try_from(n.1.as_ref().unwrap().as_ref()).unwrap())
.unwrap_or(trie::EMPTY_TRIE_MERKLE_VALUE);
.unwrap_or(trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE);

let trie_entries_linear =
trie.iter_unordered()
Expand Down
86 changes: 51 additions & 35 deletions lib/src/executor/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,6 @@ use alloc::{
vec::Vec,
};
use core::{fmt, hash::Hasher as _, iter, str};
use sha2::Digest as _;
use tiny_keccak::Hasher as _;

pub mod runtime_version;

Expand Down Expand Up @@ -1608,31 +1606,21 @@ impl ReadyToRun {
})
}
HostFunction::ext_hashing_keccak_256_version_1 => {
let mut keccak = tiny_keccak::Keccak::v256();
keccak.update(expect_pointer_size!(0).as_ref());
let mut out = [0u8; 32];
keccak.finalize(&mut out);

let hash =
<sha3::Keccak256 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
self.inner
.alloc_write_and_return_pointer(host_fn.name(), iter::once(&out))
.alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
}
HostFunction::ext_hashing_keccak_512_version_1 => {
let mut keccak = tiny_keccak::Keccak::v512();
keccak.update(expect_pointer_size!(0).as_ref());
let mut out = [0u8; 64];
keccak.finalize(&mut out);

let hash =
<sha3::Keccak512 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
self.inner
.alloc_write_and_return_pointer(host_fn.name(), iter::once(&out))
.alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
}
HostFunction::ext_hashing_sha2_256_version_1 => {
let mut hasher = sha2::Sha256::new();
hasher.update(expect_pointer_size!(0));

self.inner.alloc_write_and_return_pointer(
host_fn.name(),
iter::once(hasher.finalize().as_slice()),
)
let hash = <sha2::Sha256 as sha2::Digest>::digest(expect_pointer_size!(0).as_ref());
self.inner
.alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
}
HostFunction::ext_hashing_blake2_128_version_1 => {
let out = {
Expand Down Expand Up @@ -1815,13 +1803,18 @@ impl ReadyToRun {
host_fn_not_implemented!()
}
HostFunction::ext_trie_blake2_256_root_version_1
| HostFunction::ext_trie_blake2_256_root_version_2 => {
let state_version =
if matches!(host_fn, HostFunction::ext_trie_blake2_256_root_version_2) {
expect_state_version!(1)
} else {
TrieEntryVersion::V0
};
| HostFunction::ext_trie_blake2_256_root_version_2
| HostFunction::ext_trie_keccak_256_root_version_1
| HostFunction::ext_trie_keccak_256_root_version_2 => {
let state_version = if matches!(
host_fn,
HostFunction::ext_trie_blake2_256_root_version_2
| HostFunction::ext_trie_keccak_256_root_version_2
) {
expect_state_version!(1)
} else {
TrieEntryVersion::V0
};

let result = {
let input = expect_pointer_size!(0);
Expand All @@ -1848,7 +1841,19 @@ impl ReadyToRun {
.map(|(_, parse_result)| parse_result);

match parsing_result {
Ok(elements) => Ok(trie::trie_root(state_version, &elements[..])),
Ok(elements) => Ok(trie::trie_root(
state_version,
if matches!(
host_fn,
HostFunction::ext_trie_blake2_256_root_version_1
| HostFunction::ext_trie_blake2_256_root_version_2
) {
trie::HashFunction::Blake2
} else {
trie::HashFunction::Keccak256
},
&elements[..],
)),
Err(_) => Err(()),
}
};
Expand All @@ -1864,10 +1869,13 @@ impl ReadyToRun {
}
}
HostFunction::ext_trie_blake2_256_ordered_root_version_1
| HostFunction::ext_trie_blake2_256_ordered_root_version_2 => {
| HostFunction::ext_trie_blake2_256_ordered_root_version_2
| HostFunction::ext_trie_keccak_256_ordered_root_version_1
| HostFunction::ext_trie_keccak_256_ordered_root_version_2 => {
let state_version = if matches!(
host_fn,
HostFunction::ext_trie_blake2_256_ordered_root_version_2
| HostFunction::ext_trie_keccak_256_ordered_root_version_2
) {
expect_state_version!(1)
} else {
Expand All @@ -1893,7 +1901,19 @@ impl ReadyToRun {
.map(|(_, parse_result)| parse_result);

match parsing_result {
Ok(elements) => Ok(trie::ordered_root(state_version, &elements[..])),
Ok(elements) => Ok(trie::ordered_root(
state_version,
if matches!(
host_fn,
HostFunction::ext_trie_blake2_256_ordered_root_version_1
| HostFunction::ext_trie_blake2_256_ordered_root_version_2
) {
trie::HashFunction::Blake2
} else {
trie::HashFunction::Keccak256
},
&elements[..],
)),
Err(_) => Err(()),
}
};
Expand All @@ -1908,10 +1928,6 @@ impl ReadyToRun {
},
}
}
HostFunction::ext_trie_keccak_256_root_version_1 => host_fn_not_implemented!(),
HostFunction::ext_trie_keccak_256_root_version_2 => host_fn_not_implemented!(),
HostFunction::ext_trie_keccak_256_ordered_root_version_1 => host_fn_not_implemented!(),
HostFunction::ext_trie_keccak_256_ordered_root_version_2 => host_fn_not_implemented!(),
HostFunction::ext_trie_blake2_256_verify_proof_version_1 => host_fn_not_implemented!(),
HostFunction::ext_trie_blake2_256_verify_proof_version_2 => host_fn_not_implemented!(),
HostFunction::ext_trie_keccak_256_verify_proof_version_1 => host_fn_not_implemented!(),
Expand Down
2 changes: 1 addition & 1 deletion lib/src/executor/runtime_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1361,7 +1361,7 @@ impl Inner {
main_trie_key.extend_from_slice(DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX);
main_trie_key.extend_from_slice(child_trie);

if trie_root_hash != trie::EMPTY_TRIE_MERKLE_VALUE {
if trie_root_hash != trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE {
self.pending_storage_changes
.trie_diffs
.entry(None)
Expand Down
7 changes: 4 additions & 3 deletions lib/src/executor/trie_root_calculator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ impl ClosestDescendant {
} else {
// If the element doesn't have a parent, then the trie is completely empty.
InProgress::Finished {
trie_root_hash: trie::EMPTY_TRIE_MERKLE_VALUE,
trie_root_hash: trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE,
}
};
}
Expand Down Expand Up @@ -339,7 +339,7 @@ impl StorageValue {
// This case is handled separately in order to not generate
// a `TrieNodeInsertUpdateEvent` for a node that doesn't actually exist.
InProgress::Finished {
trie_root_hash: trie::EMPTY_TRIE_MERKLE_VALUE,
trie_root_hash: trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE,
}
}

Expand Down Expand Up @@ -373,6 +373,7 @@ impl StorageValue {
(None, _) => trie::trie_node::StorageValue::None,
},
},
trie::HashFunction::Blake2,
parent_node.is_none(),
)
.unwrap_or_else(|_| panic!());
Expand Down Expand Up @@ -582,7 +583,7 @@ impl TrieNodeRemoveEvent {
self.inner.next()
} else {
InProgress::Finished {
trie_root_hash: trie::EMPTY_TRIE_MERKLE_VALUE,
trie_root_hash: trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE,
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions lib/src/executor/trie_root_calculator/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn empty_trie_works() {
loop {
match calculation {
InProgress::Finished { trie_root_hash } => {
assert_eq!(trie_root_hash, trie::EMPTY_TRIE_MERKLE_VALUE);
assert_eq!(trie_root_hash, trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE);
return;
}
InProgress::ClosestDescendant(req) => {
Expand Down Expand Up @@ -72,6 +72,7 @@ fn one_inserted_node_in_diff() {
partial_key: trie::bytes_to_nibbles(vec![0xaa, 0xaa].into_iter()),
storage_value: trie::trie_node::StorageValue::Unhashed(b"foo"),
},
trie::HashFunction::Blake2,
true,
)
.unwrap();
Expand Down Expand Up @@ -263,6 +264,7 @@ fn fuzzing() {
partial_key,
storage_value,
},
trie::HashFunction::Blake2,
is_root_node,
)
.unwrap();
Expand Down Expand Up @@ -410,7 +412,7 @@ fn fuzzing() {
let expected_hash = trie_after_diff
.root_user_data()
.map(|n| *<&[u8; 32]>::try_from(n.1.as_ref().unwrap().as_ref()).unwrap())
.unwrap_or(trie::EMPTY_TRIE_MERKLE_VALUE);
.unwrap_or(trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE);
if obtained_hash != expected_hash {
panic!(
"\nexpected = {:?}\ncalculated = {:?}\ntrie_before = {:?}\ndiff = {:?}",
Expand Down
6 changes: 5 additions & 1 deletion lib/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ pub fn hash_from_scale_encoded_header_vectored(
/// transactions in that block.
pub fn extrinsics_root(transactions: &[impl AsRef<[u8]>]) -> [u8; 32] {
// The extrinsics root is always calculated with V0 of the trie.
trie::ordered_root(trie::TrieEntryVersion::V0, transactions)
trie::ordered_root(
trie::TrieEntryVersion::V0,
trie::HashFunction::Blake2,
transactions,
)
}

/// Attempt to decode the given SCALE-encoded header.
Expand Down
Loading

0 comments on commit 0a68d97

Please sign in to comment.