Get wrong root hash by cita-trie
Closed this issue · 8 comments
When get the root hash from an empty trie, cita-trie might returns the wrong hash. See codes bellows:
use cita_trie::codec::RLPNodeCodec;
use cita_trie::db::MemoryDB;
use cita_trie::trie::{PatriciaTrie, Trie};
use hex::FromHex;
use ethereum_types::*;
use keccak_hasher::KeccakHasher;
use kvdb::DBValue;
use memorydb;
use patricia_trie::{TrieFactory, TrieSpec};
use patricia_trie_ethereum::RlpCodec;
fn cita_empty_trie_root() {
let mut memdb = MemoryDB::new();
let mut trie = PatriciaTrie::new(&mut memdb, RLPNodeCodec::default());
println!("{:?}", hex::encode(trie.root().unwrap()));
}
fn parity_empty_trie_root() {
let factory = TrieFactory::<_, RlpCodec>::new(TrieSpec::Generic);
let mut memdb = memorydb::MemoryDB::<KeccakHasher, DBValue>::new();
let mut root = H256::default();
let mut t = factory.create(&mut memdb, &mut root);
println!("{:?}", t.root());
}
fn main() {
cita_empty_trie_root();
parity_empty_trie_root();
}
outputs:
root_hash_by_cita_trie: 0xbc2071a4de846f285702447f2589dd163678e0972a8a1b0d28b04ed5c094547f
root_hash_by_parity: 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
The hash gives by parity equals with go-Ethereum: https://github.com/ethereum/go-ethereum/blob/master/trie/trie.go#L32, so I thought there are some bugs in cita-trie.
[dependencies]
cita_trie = { path = "/src/cita-trie" }
hex = "*"
# parity_ethereum = { path = "/src/parity-ethereum" }
patricia-trie = "0.3.0"
patricia-trie-ethereum = { path = "/src/parity-ethereum/util/patricia-trie-ethereum" }
memorydb = "*"
ethereum-types = "*"
keccak-hasher = { path = "/src/parity-ethereum/util/keccak-hasher" }
kvdb = "0.1"
Full tests should be added. See: https://github.com/ethereum/tests/blob/develop/TrieTests
I will push a PR contains the tests in the near future.
CITA-trie
uses sha3 by default, and Keccak results are different.
OK.
I have switched to keccak and take a full test,
assert failed at: https://github.com/ethereum/tests/blob/develop/TrieTests/trieanyorder.json#L8
and paniced at https://github.com/ethereum/tests/blob/develop/TrieTests/trietest.json#L97.
thread 'main' panicked at 'index out of bounds: the len is 16 but the index is 16', C:\src\cita-trie\src\node.rs:71:10
note: Run with `RUST_BACKTRACE=1` for a backtrace.
The hash algorithm used by this branch https://github.com/cryptape/cita-trie/tree/keccak has been modified to keccak and full test have been added(tests will fail at now).
I have switched to keccak and take a full test,
assert failed at: https://github.com/ethereum/tests/blob/develop/TrieTests/trieanyorder.json#L8and paniced at https://github.com/ethereum/tests/blob/develop/TrieTests/trietest.json#L97.
thread 'main' panicked at 'index out of bounds: the len is 16 but the index is 16', C:\src\cita-trie\src\node.rs:71:10 note: Run with `RUST_BACKTRACE=1` for a backtrace.
Found some implementation bugs:
- For node where the child node's encoded bytes length is less than 32, the node should be encoded as a nested list other than treating the encoded child node as the value. For example, for node
ExtentionNode(shared_nibbles, LeafNode(prefix, value))
, the encode method now isRLP([HP(shared_nibbles), RLP([HP(prefix), value])])
, which should beRLP([HP(shared_nibbles), [HP(prefix), value]])
- The
delete_at
method does not reformat the trie when needed. For example, after the deletion, if a branch node only have one branch, the node should be deleted.
I fixed 1 and still working on 2.