Merge remote-tracking branch 'parity/master' into bft
Conflicts: Cargo.lock
This commit is contained in:
@@ -23,12 +23,12 @@ rlp = { path = "rlp" }
|
||||
heapsize = { version = "0.3", features = ["unstable"] }
|
||||
itertools = "0.4"
|
||||
sha3 = { path = "sha3" }
|
||||
clippy = { version = "0.0.85", optional = true}
|
||||
clippy = { version = "0.0.90", optional = true}
|
||||
ethcore-devtools = { path = "../devtools" }
|
||||
libc = "0.2.7"
|
||||
vergen = "0.1"
|
||||
target_info = "0.1"
|
||||
bigint = { path = "bigint" }
|
||||
ethcore-bigint = { path = "bigint" }
|
||||
parking_lot = "0.2.6"
|
||||
using_queue = { path = "using_queue" }
|
||||
table = { path = "table" }
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
[package]
|
||||
description = "Rust-assembler implementation of big integers arithmetic"
|
||||
description = "Large fixed-size integers and hash function outputs"
|
||||
homepage = "http://ethcore.io"
|
||||
repository = "https://github.com/ethcore/parity"
|
||||
license = "GPL-3.0"
|
||||
name = "bigint"
|
||||
name = "ethcore-bigint"
|
||||
version = "0.1.0"
|
||||
authors = ["Ethcore <admin@ethcore.io>"]
|
||||
build = "build.rs"
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Efficient large, fixed-size big integers and hashes.
|
||||
|
||||
#![cfg_attr(asm_available, feature(asm))]
|
||||
|
||||
extern crate rand;
|
||||
|
||||
@@ -30,11 +30,12 @@
|
||||
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
//
|
||||
|
||||
//! Big unsigned integer types
|
||||
//! Big unsigned integer types.
|
||||
//!
|
||||
//! Implementation of a various large-but-fixed sized unsigned integer types.
|
||||
//! The functions here are designed to be fast.
|
||||
//!
|
||||
//! The functions here are designed to be fast. There are optional `x86_64`
|
||||
//! implementations for even more speed, hidden behind the `x64_arithmetic`
|
||||
//! feature flag.
|
||||
|
||||
use std::{mem, fmt};
|
||||
use std::str::{FromStr};
|
||||
|
||||
@@ -14,7 +14,7 @@ time = "0.1.34"
|
||||
tiny-keccak = "1.0"
|
||||
rust-crypto = "0.2.34"
|
||||
slab = "0.2"
|
||||
clippy = { version = "0.0.85", optional = true}
|
||||
clippy = { version = "0.0.90", optional = true}
|
||||
igd = "0.5.0"
|
||||
libc = "0.2.7"
|
||||
parking_lot = "0.2.6"
|
||||
|
||||
@@ -7,6 +7,6 @@ authors = ["Ethcore <admin@ethcore.io>"]
|
||||
|
||||
[dependencies]
|
||||
elastic-array = "0.5"
|
||||
bigint = { path = "../bigint" }
|
||||
ethcore-bigint = { path = "../bigint" }
|
||||
lazy_static = "0.2"
|
||||
rustc-serialize = "0.3"
|
||||
@@ -174,6 +174,8 @@ pub enum FromBytesError {
|
||||
DataIsTooLong,
|
||||
/// Integer-representation is non-canonically prefixed with zero byte(s).
|
||||
ZeroPrefixedInt,
|
||||
/// String representation is not utf-8
|
||||
InvalidUtf8,
|
||||
}
|
||||
|
||||
impl StdError for FromBytesError {
|
||||
@@ -199,7 +201,7 @@ pub trait FromBytes: Sized {
|
||||
|
||||
impl FromBytes for String {
|
||||
fn from_bytes(bytes: &[u8]) -> FromBytesResult<String> {
|
||||
Ok(::std::str::from_utf8(bytes).unwrap().to_owned())
|
||||
::std::str::from_utf8(bytes).map(|s| s.to_owned()).map_err(|_| FromBytesError::InvalidUtf8)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ pub use self::rlpin::{Rlp, RlpIterator};
|
||||
pub use self::rlpstream::RlpStream;
|
||||
pub use self::rlpcompression::RlpType;
|
||||
|
||||
extern crate bigint;
|
||||
extern crate ethcore_bigint as bigint;
|
||||
extern crate elastic_array;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
//! as
|
||||
|
||||
use std::fmt;
|
||||
use std::cmp::min;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// Slice pretty print helper
|
||||
@@ -71,6 +72,32 @@ pub enum BytesRef<'a> {
|
||||
Fixed(&'a mut [u8])
|
||||
}
|
||||
|
||||
impl<'a> BytesRef<'a> {
|
||||
/// Writes given `input` to this `BytesRef` starting at `offset`.
|
||||
/// Returns number of bytes written to the ref.
|
||||
/// NOTE can return number greater then `input.len()` in case flexible vector had to be extended.
|
||||
pub fn write(&mut self, offset: usize, input: &[u8]) -> usize {
|
||||
match *self {
|
||||
BytesRef::Flexible(ref mut data) => {
|
||||
let data_len = data.len();
|
||||
let wrote = input.len() + if data_len > offset { 0 } else { offset - data_len };
|
||||
|
||||
data.resize(offset, 0);
|
||||
data.extend_from_slice(input);
|
||||
wrote
|
||||
},
|
||||
BytesRef::Fixed(ref mut data) if offset < data.len() => {
|
||||
let max = min(data.len() - offset, input.len());
|
||||
for i in 0..max {
|
||||
data[offset + i] = input[i];
|
||||
}
|
||||
max
|
||||
},
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for BytesRef<'a> {
|
||||
type Target = [u8];
|
||||
|
||||
@@ -92,4 +119,61 @@ impl <'a> DerefMut for BytesRef<'a> {
|
||||
}
|
||||
|
||||
/// Vector of bytes.
|
||||
pub type Bytes = Vec<u8>;
|
||||
pub type Bytes = Vec<u8>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::BytesRef;
|
||||
|
||||
#[test]
|
||||
fn should_write_bytes_to_fixed_bytesref() {
|
||||
// given
|
||||
let mut data1 = vec![0, 0, 0];
|
||||
let mut data2 = vec![0, 0, 0];
|
||||
let (res1, res2) = {
|
||||
let mut bytes1 = BytesRef::Fixed(&mut data1[..]);
|
||||
let mut bytes2 = BytesRef::Fixed(&mut data2[1..2]);
|
||||
|
||||
// when
|
||||
let res1 = bytes1.write(1, &[1, 1, 1]);
|
||||
let res2 = bytes2.write(3, &[1, 1, 1]);
|
||||
(res1, res2)
|
||||
};
|
||||
|
||||
// then
|
||||
assert_eq!(&data1, &[0, 1, 1]);
|
||||
assert_eq!(res1, 2);
|
||||
|
||||
assert_eq!(&data2, &[0, 0, 0]);
|
||||
assert_eq!(res2, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_write_bytes_to_flexible_bytesref() {
|
||||
// given
|
||||
let mut data1 = vec![0, 0, 0];
|
||||
let mut data2 = vec![0, 0, 0];
|
||||
let mut data3 = vec![0, 0, 0];
|
||||
let (res1, res2, res3) = {
|
||||
let mut bytes1 = BytesRef::Flexible(&mut data1);
|
||||
let mut bytes2 = BytesRef::Flexible(&mut data2);
|
||||
let mut bytes3 = BytesRef::Flexible(&mut data3);
|
||||
|
||||
// when
|
||||
let res1 = bytes1.write(1, &[1, 1, 1]);
|
||||
let res2 = bytes2.write(3, &[1, 1, 1]);
|
||||
let res3 = bytes3.write(5, &[1, 1, 1]);
|
||||
(res1, res2, res3)
|
||||
};
|
||||
|
||||
// then
|
||||
assert_eq!(&data1, &[0, 1, 1, 1]);
|
||||
assert_eq!(res1, 3);
|
||||
|
||||
assert_eq!(&data2, &[0, 0, 0, 1, 1, 1]);
|
||||
assert_eq!(res2, 3);
|
||||
|
||||
assert_eq!(&data3, &[0, 0, 0, 0, 0, 1, 1, 1]);
|
||||
assert_eq!(res3, 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,8 +330,8 @@ impl Database {
|
||||
|
||||
/// Commit buffered changes to database.
|
||||
pub fn flush(&self) -> Result<(), String> {
|
||||
match &*self.db.read() {
|
||||
&Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
match *self.db.read() {
|
||||
Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
let batch = WriteBatch::new();
|
||||
let mut overlay = self.overlay.write();
|
||||
|
||||
@@ -366,15 +366,15 @@ impl Database {
|
||||
}
|
||||
db.write_opt(batch, &self.write_opts)
|
||||
},
|
||||
&None => Err("Database is closed".to_owned())
|
||||
None => Err("Database is closed".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Commit transaction to database.
|
||||
pub fn write(&self, tr: DBTransaction) -> Result<(), String> {
|
||||
match &*self.db.read() {
|
||||
&Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
match *self.db.read() {
|
||||
Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
let batch = WriteBatch::new();
|
||||
let ops = tr.ops;
|
||||
for op in ops {
|
||||
@@ -393,14 +393,14 @@ impl Database {
|
||||
}
|
||||
db.write_opt(batch, &self.write_opts)
|
||||
},
|
||||
&None => Err("Database is closed".to_owned())
|
||||
None => Err("Database is closed".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get value by key.
|
||||
pub fn get(&self, col: Option<u32>, key: &[u8]) -> Result<Option<Bytes>, String> {
|
||||
match &*self.db.read() {
|
||||
&Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
match *self.db.read() {
|
||||
Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
let overlay = &self.overlay.read()[Self::to_overlay_column(col)];
|
||||
match overlay.get(key) {
|
||||
Some(&KeyState::Insert(ref value)) | Some(&KeyState::InsertCompressed(ref value)) => Ok(Some(value.clone())),
|
||||
@@ -412,15 +412,15 @@ impl Database {
|
||||
},
|
||||
}
|
||||
},
|
||||
&None => Ok(None),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get value by partial key. Prefix size should match configured prefix size. Only searches flushed values.
|
||||
// TODO: support prefix seek for unflushed data
|
||||
pub fn get_by_prefix(&self, col: Option<u32>, prefix: &[u8]) -> Option<Box<[u8]>> {
|
||||
match &*self.db.read() {
|
||||
&Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
match *self.db.read() {
|
||||
Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
let mut iter = col.map_or_else(|| db.iterator(IteratorMode::From(prefix, Direction::Forward)),
|
||||
|c| db.iterator_cf(cfs[c as usize], IteratorMode::From(prefix, Direction::Forward)).unwrap());
|
||||
match iter.next() {
|
||||
@@ -429,19 +429,19 @@ impl Database {
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
&None => None,
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get database iterator for flushed data.
|
||||
pub fn iter(&self, col: Option<u32>) -> DatabaseIterator {
|
||||
//TODO: iterate over overlay
|
||||
match &*self.db.read() {
|
||||
&Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
match *self.db.read() {
|
||||
Some(DBAndColumns { ref db, ref cfs }) => {
|
||||
col.map_or_else(|| DatabaseIterator { iter: db.iterator(IteratorMode::Start) },
|
||||
|c| DatabaseIterator { iter: db.iterator_cf(cfs[c as usize], IteratorMode::Start).unwrap() })
|
||||
},
|
||||
&None => panic!("Not supported yet") //TODO: return an empty iterator or change return type
|
||||
None => panic!("Not supported yet") //TODO: return an empty iterator or change return type
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,8 +458,6 @@ impl Database {
|
||||
let mut backup_db = PathBuf::from(&self.path);
|
||||
backup_db.pop();
|
||||
backup_db.push("backup_db");
|
||||
println!("Path at {:?}", self.path);
|
||||
println!("Backup at {:?}", backup_db);
|
||||
|
||||
let existed = match fs::rename(&self.path, &backup_db) {
|
||||
Ok(_) => true,
|
||||
|
||||
@@ -99,7 +99,7 @@ extern crate time;
|
||||
extern crate ethcore_devtools as devtools;
|
||||
extern crate libc;
|
||||
extern crate target_info;
|
||||
extern crate bigint;
|
||||
extern crate ethcore_bigint as bigint;
|
||||
extern crate parking_lot;
|
||||
extern crate ansi_term;
|
||||
extern crate tiny_keccak;
|
||||
|
||||
@@ -46,8 +46,8 @@ impl<'db> FatDB<'db> {
|
||||
}
|
||||
|
||||
impl<'db> Trie for FatDB<'db> {
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
||||
Box::new(FatDBIterator::new(&self.raw))
|
||||
fn iter<'a>(&'a self) -> super::Result<Box<Iterator<Item = TrieItem> + 'a>> {
|
||||
FatDBIterator::new(&self.raw).map(|iter| Box::new(iter) as Box<_>)
|
||||
}
|
||||
|
||||
fn root(&self) -> &H256 {
|
||||
@@ -73,22 +73,24 @@ pub struct FatDBIterator<'db> {
|
||||
|
||||
impl<'db> FatDBIterator<'db> {
|
||||
/// Creates new iterator.
|
||||
pub fn new(trie: &'db TrieDB) -> Self {
|
||||
FatDBIterator {
|
||||
trie_iterator: TrieDBIterator::new(trie),
|
||||
pub fn new(trie: &'db TrieDB) -> super::Result<Self> {
|
||||
Ok(FatDBIterator {
|
||||
trie_iterator: try!(TrieDBIterator::new(trie)),
|
||||
trie: trie,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Iterator for FatDBIterator<'db> {
|
||||
type Item = (Vec<u8>, &'db [u8]);
|
||||
type Item = TrieItem<'db>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.trie_iterator.next()
|
||||
.map(|(hash, value)| {
|
||||
(self.trie.db().get_aux(&hash).expect("Missing fatdb hash"), value)
|
||||
})
|
||||
.map(|res|
|
||||
res.map(|(hash, value)| {
|
||||
(self.trie.db().get_aux(&hash).expect("Missing fatdb hash"), value)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,5 +107,5 @@ fn fatdb_to_trie() {
|
||||
}
|
||||
let t = FatDB::new(&memdb, &root).unwrap();
|
||||
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), &[0x01u8, 0x23]);
|
||||
assert_eq!(t.iter().collect::<Vec<_>>(), vec![(vec![0x01u8, 0x23], &[0x01u8, 0x23] as &[u8])]);
|
||||
assert_eq!(t.iter().unwrap().map(Result::unwrap).collect::<Vec<_>>(), vec![(vec![0x01u8, 0x23], &[0x01u8, 0x23] as &[u8])]);
|
||||
}
|
||||
|
||||
@@ -72,12 +72,12 @@ impl fmt::Display for TrieError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Trie-Item type.
|
||||
pub type TrieItem<'a> = (Vec<u8>, &'a [u8]);
|
||||
|
||||
/// Trie result type. Boxed to avoid copying around extra space for `H256`s on successful queries.
|
||||
pub type Result<T> = ::std::result::Result<T, Box<TrieError>>;
|
||||
|
||||
/// Trie-Item type.
|
||||
pub type TrieItem<'a> = Result<(Vec<u8>, &'a [u8])>;
|
||||
|
||||
/// A key-value datastore implemented as a database-backed modified Merkle tree.
|
||||
pub trait Trie {
|
||||
/// Return the root of the trie.
|
||||
@@ -102,7 +102,7 @@ pub trait Trie {
|
||||
where 'a: 'b, R: Recorder;
|
||||
|
||||
/// Returns an iterator over elements of trie.
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a>;
|
||||
fn iter<'a>(&'a self) -> Result<Box<Iterator<Item = TrieItem> + 'a>>;
|
||||
}
|
||||
|
||||
/// A key-value datastore implemented as a database-backed modified Merkle tree.
|
||||
@@ -193,7 +193,7 @@ impl<'db> Trie for TrieKinds<'db> {
|
||||
wrapper!(self, get_recorded, key, r)
|
||||
}
|
||||
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
||||
fn iter<'a>(&'a self) -> Result<Box<Iterator<Item = TrieItem> + 'a>> {
|
||||
wrapper!(self, iter,)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,12 @@ pub struct BasicRecorder {
|
||||
min_depth: u32,
|
||||
}
|
||||
|
||||
impl Default for BasicRecorder {
|
||||
fn default() -> Self {
|
||||
BasicRecorder::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl BasicRecorder {
|
||||
/// Create a new `BasicRecorder` which records all given nodes.
|
||||
#[inline]
|
||||
@@ -233,4 +239,4 @@ mod tests {
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ impl<'db> SecTrieDB<'db> {
|
||||
}
|
||||
|
||||
impl<'db> Trie for SecTrieDB<'db> {
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
||||
Box::new(TrieDB::iter(&self.raw))
|
||||
fn iter<'a>(&'a self) -> super::Result<Box<Iterator<Item = TrieItem> + 'a>> {
|
||||
TrieDB::iter(&self.raw)
|
||||
}
|
||||
|
||||
fn root(&self) -> &H256 { self.raw.root() }
|
||||
|
||||
@@ -128,7 +128,7 @@ impl<'db> TrieDB<'db> {
|
||||
}
|
||||
|
||||
/// Get the root node's RLP.
|
||||
fn root_node<'a, R: 'a + Recorder>(&self, r: &'a mut R) -> super::Result<Node> {
|
||||
fn root_node<R: Recorder>(&self, r: &mut R) -> super::Result<Node> {
|
||||
self.root_data(r).map(Node::decoded)
|
||||
}
|
||||
|
||||
@@ -279,30 +279,38 @@ pub struct TrieDBIterator<'a> {
|
||||
|
||||
impl<'a> TrieDBIterator<'a> {
|
||||
/// Create a new iterator.
|
||||
pub fn new(db: &'a TrieDB) -> TrieDBIterator<'a> {
|
||||
pub fn new(db: &'a TrieDB) -> super::Result<TrieDBIterator<'a>> {
|
||||
let mut r = TrieDBIterator {
|
||||
db: db,
|
||||
trail: vec![],
|
||||
key_nibbles: Vec::new(),
|
||||
};
|
||||
r.descend(db.root_data(&mut NoOp).unwrap());
|
||||
r
|
||||
|
||||
try!(db.root_data(&mut NoOp).and_then(|root| r.descend(root)));
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
/// Descend into a payload.
|
||||
fn descend(&mut self, d: &'a [u8]) {
|
||||
fn descend(&mut self, d: &'a [u8]) -> super::Result<()> {
|
||||
self.trail.push(Crumb {
|
||||
status: Status::Entering,
|
||||
node: self.db.get_node(d, &mut NoOp, 0).unwrap(),
|
||||
node: try!(self.db.get_node(d, &mut NoOp, 0)),
|
||||
});
|
||||
match self.trail.last().unwrap().node {
|
||||
Node::Leaf(n, _) | Node::Extension(n, _) => { self.key_nibbles.extend(n.iter()); },
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Descend into a payload and get the next item.
|
||||
fn descend_next(&mut self, d: &'a [u8]) -> Option<(Bytes, &'a [u8])> { self.descend(d); self.next() }
|
||||
fn descend_next(&mut self, d: &'a [u8]) -> Option<TrieItem<'a>> {
|
||||
match self.descend(d) {
|
||||
Ok(()) => self.next(),
|
||||
Err(e) => Some(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// The present key.
|
||||
fn key(&self) -> Bytes {
|
||||
@@ -312,12 +320,12 @@ impl<'a> TrieDBIterator<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Iterator for TrieDBIterator<'a> {
|
||||
type Item = (Bytes, &'a [u8]);
|
||||
type Item = TrieItem<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let b = match self.trail.last_mut() {
|
||||
Some(mut b) => { b.increment(); b.clone() },
|
||||
None => return None
|
||||
None => return None,
|
||||
};
|
||||
match (b.status, b.node) {
|
||||
(Status::Exiting, n) => {
|
||||
@@ -332,7 +340,7 @@ impl<'a> Iterator for TrieDBIterator<'a> {
|
||||
self.trail.pop();
|
||||
self.next()
|
||||
},
|
||||
(Status::At, Node::Leaf(_, v)) | (Status::At, Node::Branch(_, Some(v))) => Some((self.key(), v)),
|
||||
(Status::At, Node::Leaf(_, v)) | (Status::At, Node::Branch(_, Some(v))) => Some(Ok((self.key(), v))),
|
||||
(Status::At, Node::Extension(_, d)) => self.descend_next(d),
|
||||
(Status::At, Node::Branch(_, _)) => self.next(),
|
||||
(Status::AtChild(i), Node::Branch(children, _)) if children[i].len() > 0 => {
|
||||
@@ -352,8 +360,8 @@ impl<'a> Iterator for TrieDBIterator<'a> {
|
||||
}
|
||||
|
||||
impl<'db> Trie for TrieDB<'db> {
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
||||
Box::new(TrieDBIterator::new(self))
|
||||
fn iter<'a>(&'a self) -> super::Result<Box<Iterator<Item = TrieItem> + 'a>> {
|
||||
TrieDBIterator::new(self).map(|iter| Box::new(iter) as Box<_>)
|
||||
}
|
||||
|
||||
fn root(&self) -> &H256 { self.root }
|
||||
@@ -392,6 +400,6 @@ fn iterator() {
|
||||
}
|
||||
|
||||
let t = TrieDB::new(&memdb, &root).unwrap();
|
||||
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), t.iter().map(|x|x.0).collect::<Vec<_>>());
|
||||
assert_eq!(d, t.iter().map(|x|x.1).collect::<Vec<_>>());
|
||||
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), t.iter().unwrap().map(|x| x.unwrap().0).collect::<Vec<_>>());
|
||||
assert_eq!(d, t.iter().unwrap().map(|x| x.unwrap().1).collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
@@ -40,7 +40,9 @@ use vector::SharedPrefix;
|
||||
/// assert_eq!(ordered_trie_root(v), H256::from_str(root).unwrap());
|
||||
/// }
|
||||
/// ```
|
||||
pub fn ordered_trie_root(input: Vec<Vec<u8>>) -> H256 {
|
||||
pub fn ordered_trie_root<I>(input: I) -> H256
|
||||
where I: IntoIterator<Item=Vec<u8>>
|
||||
{
|
||||
let gen_input = input
|
||||
// first put elements into btree to sort them by nibbles
|
||||
// optimize it later
|
||||
|
||||
Reference in New Issue
Block a user