GithubHelp home page GithubHelp logo

cita_trie's People

Contributors

jerry-yu avatar kaoimin avatar laizy avatar mohanson avatar nopestack avatar pencil-yao avatar u2 avatar yangby-cryptape avatar yejiayu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cita_trie's Issues

Get wrong root hash by cita-trie

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.

Reconstruction from db and then remove keys will result wrong root hash

See codes below, I think it should be root1 == root2 == root3, but (root1 == root2) != root3 in fact.

fn main() {
    let root1 = {
        let mut db = cita_trie::db::MemoryDB::new();
        let mut trie = cita_trie::trie::PatriciaTrie::new(&mut db, cita_trie::codec::RLPNodeCodec::default());
        trie.insert(b"a", b"a").unwrap();
        trie.root().unwrap()
    };

    let root2 = {
        let mut db = cita_trie::db::MemoryDB::new();
        let mut trie = cita_trie::trie::PatriciaTrie::new(&mut db, cita_trie::codec::RLPNodeCodec::default());
        trie.insert(b"a", b"a").unwrap();
        trie.insert(b"b", b"b").unwrap();
        trie.root().unwrap();
        trie.remove(b"b").unwrap();
        trie.root().unwrap()
    };

    let root3 = {
        let mut db = cita_trie::db::MemoryDB::new();
        let mut t1 = cita_trie::trie::PatriciaTrie::new(&mut db, cita_trie::codec::RLPNodeCodec::default());
        t1.insert(b"a", b"a").unwrap();
        t1.insert(b"b", b"b").unwrap();
        let root = t1.root().unwrap();
        let mut t2 = cita_trie::trie::PatriciaTrie::from(&mut db, cita_trie::codec::RLPNodeCodec::default(), &root).unwrap();
        t2.remove(b"b").unwrap();
        t2.root().unwrap()
    };

    println!("{:?}", hex::encode(root1)); // "668aee9307d4b41714f33b61fd7e0704d31b95e42169292ba56af48929079580"
    println!("{:?}", hex::encode(root2)); // "668aee9307d4b41714f33b61fd7e0704d31b95e42169292ba56af48929079580"
    println!("{:?}", hex::encode(root3)); // "f3313809b6501771b8a698b8c70979f3f8340b4f7e90dc5db96caf81cf5a25e0"
}

[bug] Wrong root hash when keys are removed

The root hash calculation returns a wrong value when some keys are removed. This does not happen for all keys.
Here is a test that reproduces the bug:

    #[test]
    fn test_insert_and_revert() {
        // Arrange
        let db = Arc::new(MemoryDB::new(true));
        let mut trie = PatriciaTrie::new(db.clone(), Arc::new(HasherKeccak::new()));
        let root_0 = trie.commit().unwrap();

        // Insert "do"
        let root_1 = {
            trie.insert(b"do".to_vec(), b"verb".to_vec()).unwrap();
            trie.root().unwrap()
        };

        // Insert "doge"
        let root_2 = {
            trie.insert(b"doge".to_vec(), b"coin".to_vec()).unwrap();
            trie.root().unwrap()
        };

        // Insert "dog"
        {
            trie.insert(b"dog".to_vec(), b"puppy".to_vec()).unwrap();
            trie.root().unwrap()
        };

        // Remove "dog"
        {
            trie.remove(b"dog").unwrap();
            // It fails here, the root hash does not match the expected one
            assert_eq!(root_2, trie.root().unwrap());
        }

        // Remove "doge"
        {
            trie.remove(b"doge").unwrap();
            assert_eq!(root_1, trie.root().unwrap());
        }

        // Remove "do"
        {
            trie.remove(b"do").unwrap();
            // Now the trie is empty but the hash is not the one of an empty trie
            assert_eq!(root_0, trie.root().unwrap());
        }

    }

Production ready

In order to ensure production is ready, we also need to complete the following work.

  • Eth-trie tests #13
  • Remove root clone #20
  • Avoid unnecessarily clone in remove
  • Benchmark case(vs parity-trie)

Useless code hint

warning: method is never used: `encode_raw`
  --> src/nibbles.rs:88:5
   |
88 |     pub fn encode_raw(&self) -> (Vec<u8>, bool) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: #[warn(dead_code)] on by default

    Finished dev [unoptimized + debuginfo] target(s) in 1.51s

Delete or Note ?

Problems when import cita-trie crate

Add cita_trie = "0.1.3" in Cargo.toml dependencies will cause compile problems. I checked this problem in the simple test project.

error: this file contains an un-closed delimiter
  --> /home/wpf/.cargo/registry/src/github.com-1ecc6299db9ec823/cita_trie-0.1.3/src/db.rs:93:3
   |
8  | pub trait DB: Send + Sync + Debug {
   |                                   - un-closed delimiter
9  |     type Error: Error;
10 |  State {
   |        - this delimiter might not be properly closed...
...
16 | }
   | - ...as it matches this but it has different indentation
...
93 | }
...
...
...

while add cita_trie = { git = "https://github.com/cryptape/cita-trie.git", branch = "master" }, it's ok.
Is there a problem with the crate posted to crate.io?

RocksDb implementation

First thanks for the great work on this! An easier to understand, Rust based merkle tree is much needed!

I've created a simple RocksDb store implementation. You can find it here:
cita-trie-db .

Couple thoughts on the current cita-trie implementation:

  • Consider renaming the DB Trait to something else (maybe KvDB). This might reduce the chance of it clashing with other crates. For example, I had to alias RocksDB::DB.
  • trie.commit() is private outside the crate. You can call commit via trie.root(), but it might be useful to be more explicit from the API.
  • trie.commit() calls self.db.insert/remove. It'd be nice to be able to batch these calls with RockDb. Maybe the DB trait can expose a commit(...) that would allow this.

Suggestion for ParticialTrie::from()

pub fn from(db: &'db mut D, codec: C, root: &C::Hash) -> TrieResult<Self, C, D> {
        match db.get(root.as_ref()).map_err(TrieError::DB)? {
            Some(data) => {
                let mut trie = PatriciaTrie {
                    root: Node::Empty,
                    db,
                    codec,

                    cache: HashMap::new(),
                    deleted_keys: vec![],
                };

                trie.root = trie.decode_node(&data).map_err(TrieError::NodeCodec)?;
                Ok(trie)
            }
            None => Err(TrieError::InvalidStateRoot),
        }
    }

root already passed as a parameter, maybe we should not calculate it again in trie.root = trie.decode_node(&data).map_err(TrieError::NodeCodec)?;

So... Could we just use

pub fn from(db: &'db mut D, codec: C, root: &C::Hash) -> TrieResult<Self, C, D> {
        Ok(PatriciaTrie {
            root: Node::Hash(HashNode::new(root.as_ref())),
            db,
            codec,

            cache: HashMap::new(),
            deleted_keys: vec![],
        })
    }

not all stale keys are deleted from db

stale keys can be introduced by deletion and insertion, #10 only handled the deletion part.

        let mut memdb = MemoryDB::new();
        let mut trie = PatriciaTrie::new(&mut memdb, RLPNodeCodec::default());
        for i in 0..10 {
            trie.insert(format!("test{}", i).as_bytes(), b"testvalue");
            trie.commit();
        }
        for i in 0..10 {
            trie.remove(format!("test{}", i).as_bytes());
            trie.commit();
        }
        println!("clear all:trie.root={:?}", trie.root);
        println!("clear all:{:?}", trie.db);

output:

clear all:trie.root=Empty
clear all:MemoryDB { storage: RwLock { data: {[193, 152, 200, 144, 250, 10, 84, 154, 250, 172, 48, 71, 148, 203, 39, 40, 56, 205, 6, 252, 92, 235, 72, 182, 241, 177, 161, 89, 29, 125, 114, 0]: [231, 133, 23, 70, 87, 55, 67, 160, 36, 48, 168, 10, 138, 13... ]} } }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.