Merge pull request #171 from gavofyork/gav
Iterator for NibbleSlice and TrieDB.
This commit is contained in:
commit
8776ac2f64
@ -171,7 +171,7 @@ impl<'a> Executive<'a> {
|
|||||||
|
|
||||||
// at first, transfer value to destination
|
// at first, transfer value to destination
|
||||||
self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value);
|
self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value);
|
||||||
debug!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
|
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
|
||||||
|
|
||||||
if self.engine.is_builtin(¶ms.code_address) {
|
if self.engine.is_builtin(¶ms.code_address) {
|
||||||
// if destination is builtin, try to execute it
|
// if destination is builtin, try to execute it
|
||||||
|
@ -150,10 +150,10 @@ impl State {
|
|||||||
let e = try!(Executive::new(self, env_info, engine).transact(t));
|
let e = try!(Executive::new(self, env_info, engine).transact(t));
|
||||||
//println!("Executed: {:?}", e);
|
//println!("Executed: {:?}", e);
|
||||||
|
|
||||||
debug!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));
|
trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));
|
||||||
self.commit();
|
self.commit();
|
||||||
let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs);
|
let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs);
|
||||||
debug!("Transaction receipt: {:?}", receipt);
|
trace!("Transaction receipt: {:?}", receipt);
|
||||||
Ok(receipt)
|
Ok(receipt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
src/views.rs
51
src/views.rs
@ -61,6 +61,44 @@ impl<'a> Hashable for TransactionView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// View onto transaction rlp.
|
||||||
|
pub struct AccountView<'a> {
|
||||||
|
rlp: Rlp<'a>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AccountView<'a> {
|
||||||
|
/// Creates new view onto block from raw bytes.
|
||||||
|
pub fn new(bytes: &'a [u8]) -> AccountView<'a> {
|
||||||
|
AccountView {
|
||||||
|
rlp: Rlp::new(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates new view onto block from rlp.
|
||||||
|
pub fn new_from_rlp(rlp: Rlp<'a>) -> AccountView<'a> {
|
||||||
|
AccountView {
|
||||||
|
rlp: rlp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return reference to underlaying rlp.
|
||||||
|
pub fn rlp(&self) -> &Rlp<'a> {
|
||||||
|
&self.rlp
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the nonce field of the transaction.
|
||||||
|
pub fn nonce(&self) -> U256 { self.rlp.val_at(0) }
|
||||||
|
|
||||||
|
/// Get the gas_price field of the transaction.
|
||||||
|
pub fn balance(&self) -> U256 { self.rlp.val_at(1) }
|
||||||
|
|
||||||
|
/// Get the gas field of the transaction.
|
||||||
|
pub fn storage_root(&self) -> H256 { self.rlp.val_at(2) }
|
||||||
|
|
||||||
|
/// Get the value field of the transaction.
|
||||||
|
pub fn code_hash(&self) -> H256 { self.rlp.val_at(3) }
|
||||||
|
}
|
||||||
|
|
||||||
/// View onto block rlp.
|
/// View onto block rlp.
|
||||||
pub struct BlockView<'a> {
|
pub struct BlockView<'a> {
|
||||||
rlp: Rlp<'a>
|
rlp: Rlp<'a>
|
||||||
@ -97,13 +135,13 @@ impl<'a> BlockView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn transaction_views(&self) -> Vec<TransactionView> {
|
pub fn transactions(&self) -> Vec<Transaction> {
|
||||||
self.rlp.at(1).iter().map(|rlp| TransactionView::new_from_rlp(rlp)).collect()
|
self.rlp.val_at(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn transactions(&self) -> Vec<Transaction> {
|
pub fn transaction_views(&self) -> Vec<TransactionView> {
|
||||||
self.rlp.val_at(1)
|
self.rlp.at(1).iter().map(|rlp| TransactionView::new_from_rlp(rlp)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return transaction hashes.
|
/// Return transaction hashes.
|
||||||
@ -116,6 +154,11 @@ impl<'a> BlockView<'a> {
|
|||||||
self.rlp.val_at(2)
|
self.rlp.val_at(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return List of transactions in given block.
|
||||||
|
pub fn uncle_views(&self) -> Vec<HeaderView> {
|
||||||
|
self.rlp.at(2).iter().map(|rlp| HeaderView::new_from_rlp(rlp)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return list of uncle hashes of given block.
|
/// Return list of uncle hashes of given block.
|
||||||
pub fn uncle_hashes(&self) -> Vec<H256> {
|
pub fn uncle_hashes(&self) -> Vec<H256> {
|
||||||
self.rlp.at(2).iter().map(|rlp| rlp.as_raw().sha3()).collect()
|
self.rlp.at(2).iter().map(|rlp| rlp.as_raw().sha3()).collect()
|
||||||
|
@ -215,10 +215,14 @@ macro_rules! impl_hash {
|
|||||||
}
|
}
|
||||||
impl fmt::Display for $from {
|
impl fmt::Display for $from {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
for i in self.0[0..3].iter() {
|
for i in self.0[0..2].iter() {
|
||||||
try!(write!(f, "{:02x}", i));
|
try!(write!(f, "{:02x}", i));
|
||||||
}
|
}
|
||||||
write!(f, "…{:02x}", self.0.last().unwrap())
|
try!(write!(f, "…"));
|
||||||
|
for i in self.0[$size - 4..$size].iter() {
|
||||||
|
try!(write!(f, "{:02x}", i));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,7 +548,7 @@ mod tests {
|
|||||||
fn hash() {
|
fn hash() {
|
||||||
let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
|
let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
|
||||||
assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h);
|
assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h);
|
||||||
assert_eq!(format!("{}", h), "012345…ef");
|
assert_eq!(format!("{}", h), "0123…89abcdef");
|
||||||
assert_eq!(format!("{:?}", h), "0123456789abcdef");
|
assert_eq!(format!("{:?}", h), "0123456789abcdef");
|
||||||
assert_eq!(h.hex(), "0123456789abcdef");
|
assert_eq!(h.hex(), "0123456789abcdef");
|
||||||
assert!(h == h);
|
assert!(h == h);
|
||||||
|
@ -561,13 +561,13 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
|
|||||||
let port = self.info.config.listen_address.port();
|
let port = self.info.config.listen_address.port();
|
||||||
self.info.listen_port = port;
|
self.info.listen_port = port;
|
||||||
|
|
||||||
// self.add_node("enode://a9a921de2ff09a9a4d38b623c67b2d6b477a8e654ae95d874750cbbcb31b33296496a7b4421934e2629269e180823e52c15c2b19fc59592ec51ffe4f2de76ed7@127.0.0.1:30303");
|
self.add_node("enode://a9a921de2ff09a9a4d38b623c67b2d6b477a8e654ae95d874750cbbcb31b33296496a7b4421934e2629269e180823e52c15c2b19fc59592ec51ffe4f2de76ed7@127.0.0.1:30303");
|
||||||
// GO bootnodes
|
/* // GO bootnodes
|
||||||
self.add_node("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"); // IE
|
self.add_node("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"); // IE
|
||||||
self.add_node("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"); // BR
|
self.add_node("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"); // BR
|
||||||
self.add_node("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"); // SG
|
self.add_node("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"); // SG
|
||||||
// ETH/DEV cpp-ethereum (poc-9.ethdev.com)
|
// ETH/DEV cpp-ethereum (poc-9.ethdev.com)
|
||||||
self.add_node("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303");
|
self.add_node("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303");*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stream_hup<'s>(&'s mut self, io: &mut IoContext<'s, NetworkIoMessage<Message>>, stream: StreamToken) {
|
fn stream_hup<'s>(&'s mut self, io: &mut IoContext<'s, NetworkIoMessage<Message>>, stream: StreamToken) {
|
||||||
|
@ -34,6 +34,22 @@ pub struct NibbleSlice<'a> {
|
|||||||
offset_encode_suffix: usize,
|
offset_encode_suffix: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct NibbleSliceIterator<'a> {
|
||||||
|
p: &'a NibbleSlice<'a>,
|
||||||
|
i: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for NibbleSliceIterator<'a> {
|
||||||
|
type Item = u8;
|
||||||
|
fn next(&mut self) -> Option<u8> {
|
||||||
|
self.i += 1;
|
||||||
|
match self.i <= self.p.len() {
|
||||||
|
true => Some(self.p.at(self.i - 1)),
|
||||||
|
false => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'view> NibbleSlice<'a> where 'a: 'view {
|
impl<'a, 'view> NibbleSlice<'a> where 'a: 'view {
|
||||||
/// Create a new nibble slice with the given byte-slice.
|
/// Create a new nibble slice with the given byte-slice.
|
||||||
pub fn new(data: &[u8]) -> NibbleSlice { NibbleSlice::new_offset(data, 0) }
|
pub fn new(data: &[u8]) -> NibbleSlice { NibbleSlice::new_offset(data, 0) }
|
||||||
@ -41,7 +57,7 @@ impl<'a, 'view> NibbleSlice<'a> where 'a: 'view {
|
|||||||
/// Create a new nibble slice with the given byte-slice with a nibble offset.
|
/// Create a new nibble slice with the given byte-slice with a nibble offset.
|
||||||
pub fn new_offset(data: &'a [u8], offset: usize) -> NibbleSlice { NibbleSlice{data: data, offset: offset, data_encode_suffix: &b""[..], offset_encode_suffix: 0} }
|
pub fn new_offset(data: &'a [u8], offset: usize) -> NibbleSlice { NibbleSlice{data: data, offset: offset, data_encode_suffix: &b""[..], offset_encode_suffix: 0} }
|
||||||
|
|
||||||
///
|
/// Create a composed nibble slice; one followed by the other.
|
||||||
pub fn new_composed(a: &'a NibbleSlice, b: &'a NibbleSlice) -> NibbleSlice<'a> { NibbleSlice{data: a.data, offset: a.offset, data_encode_suffix: b.data, offset_encode_suffix: b.offset} }
|
pub fn new_composed(a: &'a NibbleSlice, b: &'a NibbleSlice) -> NibbleSlice<'a> { NibbleSlice{data: a.data, offset: a.offset, data_encode_suffix: b.data, offset_encode_suffix: b.offset} }
|
||||||
|
|
||||||
/*pub fn new_composed_bytes_offset(a: &NibbleSlice, b: &NibbleSlice) -> (Bytes, usize) {
|
/*pub fn new_composed_bytes_offset(a: &NibbleSlice, b: &NibbleSlice) -> (Bytes, usize) {
|
||||||
@ -60,6 +76,10 @@ impl<'a, 'view> NibbleSlice<'a> where 'a: 'view {
|
|||||||
(r, a.len() + b.len())
|
(r, a.len() + b.len())
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
pub fn iter(&'a self) -> NibbleSliceIterator<'a> {
|
||||||
|
NibbleSliceIterator { p: self, i: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new nibble slice from the given HPE encoded data (e.g. output of `encoded()`).
|
/// Create a new nibble slice from the given HPE encoded data (e.g. output of `encoded()`).
|
||||||
pub fn from_encoded(data: &'a [u8]) -> (NibbleSlice, bool) {
|
pub fn from_encoded(data: &'a [u8]) -> (NibbleSlice, bool) {
|
||||||
(Self::new_offset(data, if data[0] & 16 == 16 {1} else {2}), data[0] & 32 == 32)
|
(Self::new_offset(data, if data[0] & 16 == 16 {1} else {2}), data[0] & 32 == 32)
|
||||||
@ -189,6 +209,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn iterator() {
|
||||||
|
let n = NibbleSlice::new(D);
|
||||||
|
let mut nibbles: Vec<u8> = vec![];
|
||||||
|
nibbles.extend(n.iter());
|
||||||
|
assert_eq!(nibbles, (0u8..6).collect::<Vec<_>>())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mid() {
|
fn mid() {
|
||||||
let n = NibbleSlice::new(D);
|
let n = NibbleSlice::new(D);
|
||||||
|
@ -70,7 +70,9 @@ impl OverlayDB {
|
|||||||
let mut ret = 0u32;
|
let mut ret = 0u32;
|
||||||
for i in self.overlay.drain().into_iter() {
|
for i in self.overlay.drain().into_iter() {
|
||||||
let (key, (value, rc)) = i;
|
let (key, (value, rc)) = i;
|
||||||
if rc != 0 {
|
// until we figure out state trie pruning, only commit stuff when it has a strictly positive delkta of RCs -
|
||||||
|
// this prevents RCs being reduced to 0 where the DB would pretent that the node had been removed.
|
||||||
|
if rc > 0 {
|
||||||
match self.payload(&key) {
|
match self.payload(&key) {
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
let (back_value, back_rc) = x;
|
let (back_value, back_rc) = x;
|
||||||
|
@ -5,7 +5,7 @@ use rlp::*;
|
|||||||
use super::journal::*;
|
use super::journal::*;
|
||||||
|
|
||||||
/// Type of node in the trie and essential information thereof.
|
/// Type of node in the trie and essential information thereof.
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
pub enum Node<'a> {
|
pub enum Node<'a> {
|
||||||
Empty,
|
Empty,
|
||||||
Leaf(NibbleSlice<'a>, &'a[u8]),
|
Leaf(NibbleSlice<'a>, &'a[u8]),
|
||||||
|
@ -42,7 +42,7 @@ impl<'db> TrieDB<'db> {
|
|||||||
/// Panics, if `root` does not exist
|
/// Panics, if `root` does not exist
|
||||||
pub fn new(db: &'db HashDB, root: &'db H256) -> Self {
|
pub fn new(db: &'db HashDB, root: &'db H256) -> Self {
|
||||||
if !db.exists(root) {
|
if !db.exists(root) {
|
||||||
flush(format!("Trie root not found {}", root));
|
flushln!("TrieDB::new({}): Trie root not found!", root);
|
||||||
panic!("Trie root not found!");
|
panic!("Trie root not found!");
|
||||||
}
|
}
|
||||||
TrieDB {
|
TrieDB {
|
||||||
@ -109,7 +109,12 @@ impl<'db> TrieDB<'db> {
|
|||||||
|
|
||||||
/// Get the root node's RLP.
|
/// Get the root node's RLP.
|
||||||
fn root_node(&self) -> Node {
|
fn root_node(&self) -> Node {
|
||||||
Node::decoded(self.db.lookup(&self.root).expect("Trie root not found!"))
|
Node::decoded(self.root_data())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the data of the root node.
|
||||||
|
fn root_data(&self) -> &[u8] {
|
||||||
|
self.db.lookup(&self.root).expect("Trie root not found!")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the root node as a `Node`.
|
/// Get the root node as a `Node`.
|
||||||
@ -198,6 +203,122 @@ impl<'db> TrieDB<'db> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
|
enum Status {
|
||||||
|
Entering,
|
||||||
|
At,
|
||||||
|
AtChild(usize),
|
||||||
|
Exiting,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
|
struct Crumb<'a> {
|
||||||
|
node: Node<'a>,
|
||||||
|
// key: &'a[u8],
|
||||||
|
status: Status,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Crumb<'a> {
|
||||||
|
/// Move on to next status in the node's sequence.
|
||||||
|
fn increment(&mut self) {
|
||||||
|
self.status = match (&self.status, &self.node) {
|
||||||
|
(_, &Node::Empty) => Status::Exiting,
|
||||||
|
(&Status::Entering, _) => Status::At,
|
||||||
|
(&Status::At, &Node::Branch(_, _)) => Status::AtChild(0),
|
||||||
|
(&Status::AtChild(x), &Node::Branch(_, _)) if x < 15 => Status::AtChild(x + 1),
|
||||||
|
_ => Status::Exiting,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterator for going through all values in the trie.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TrieDBIterator<'a> {
|
||||||
|
db: &'a TrieDB<'a>,
|
||||||
|
trail: Vec<Crumb<'a>>,
|
||||||
|
key_nibbles: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TrieDBIterator<'a> {
|
||||||
|
/// Create a new iterator.
|
||||||
|
fn new(db: &'a TrieDB) -> TrieDBIterator<'a> {
|
||||||
|
let mut r = TrieDBIterator {
|
||||||
|
db: db,
|
||||||
|
trail: vec![],
|
||||||
|
key_nibbles: Vec::new(),
|
||||||
|
};
|
||||||
|
r.descend(db.root_data());
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Descend into a payload.
|
||||||
|
fn descend(&mut self, d: &'a [u8]) {
|
||||||
|
self.trail.push(Crumb {
|
||||||
|
status: Status::Entering,
|
||||||
|
node: self.db.get_node(d)
|
||||||
|
});
|
||||||
|
match self.trail.last().unwrap().node {
|
||||||
|
Node::Leaf(n, _) | Node::Extension(n, _) => { self.key_nibbles.extend(n.iter()); },
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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() }
|
||||||
|
|
||||||
|
/// The present key.
|
||||||
|
fn key(&self) -> Bytes {
|
||||||
|
// collapse the key_nibbles down to bytes.
|
||||||
|
self.key_nibbles.iter().step(2).zip(self.key_nibbles.iter().skip(1).step(2)).map(|(h, l)| h * 16 + l).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for TrieDBIterator<'a> {
|
||||||
|
type Item = (Bytes, &'a [u8]);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let b = match self.trail.last_mut() {
|
||||||
|
Some(ref mut b) => { b.increment(); b.clone() },
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
|
match (b.status, b.node) {
|
||||||
|
(Status::Exiting, n) => {
|
||||||
|
match n {
|
||||||
|
Node::Leaf(n, _) | Node::Extension(n, _) => {
|
||||||
|
let l = self.key_nibbles.len();
|
||||||
|
self.key_nibbles.truncate(l - n.len());
|
||||||
|
},
|
||||||
|
Node::Branch(_, _) => { self.key_nibbles.pop(); },
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.trail.pop();
|
||||||
|
self.next()
|
||||||
|
},
|
||||||
|
(Status::At, Node::Leaf(_, v)) => Some((self.key(), v)),
|
||||||
|
(Status::At, Node::Extension(_, d)) => self.descend_next(d),
|
||||||
|
(Status::At, Node::Branch(_, Some(v))) => Some((self.key(), v)),
|
||||||
|
(Status::At, Node::Branch(_, _)) => self.next(),
|
||||||
|
(Status::AtChild(i), Node::Branch(children, _)) if children[i].len() > 0 => {
|
||||||
|
match i {
|
||||||
|
0 => self.key_nibbles.push(0),
|
||||||
|
i => *self.key_nibbles.last_mut().unwrap() = i as u8,
|
||||||
|
}
|
||||||
|
self.descend_next(children[i])
|
||||||
|
},
|
||||||
|
(Status::AtChild(i), Node::Branch(_, _)) => {
|
||||||
|
if i == 0 { self.key_nibbles.push(0); }
|
||||||
|
self.next()
|
||||||
|
},
|
||||||
|
_ => panic!() // Should never see Entering or AtChild without a Branch here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'db> TrieDB<'db> {
|
||||||
|
/// Get all keys/values stored in the trie.
|
||||||
|
pub fn iter(&self) -> TrieDBIterator { TrieDBIterator::new(self) }
|
||||||
|
}
|
||||||
|
|
||||||
impl<'db> Trie for TrieDB<'db> {
|
impl<'db> Trie for TrieDB<'db> {
|
||||||
fn root(&self) -> &H256 { &self.root }
|
fn root(&self) -> &H256 { &self.root }
|
||||||
|
|
||||||
@ -218,3 +339,22 @@ impl<'db> fmt::Debug for TrieDB<'db> {
|
|||||||
writeln!(f, "]")
|
writeln!(f, "]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn iterator() {
|
||||||
|
use memorydb::*;
|
||||||
|
use super::triedbmut::*;
|
||||||
|
|
||||||
|
let d = vec![ &b"A"[..], &b"AA"[..], &b"AB"[..], &b"B"[..] ];
|
||||||
|
|
||||||
|
let mut memdb = MemoryDB::new();
|
||||||
|
let mut root = H256::new();
|
||||||
|
{
|
||||||
|
let mut t = TrieDBMut::new(&mut memdb, &mut root);
|
||||||
|
for x in &d {
|
||||||
|
t.insert(&x, &x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), TrieDB::new(&memdb, &root).iter().map(|x|x.0).collect::<Vec<_>>());
|
||||||
|
assert_eq!(d, TrieDB::new(&memdb, &root).iter().map(|x|x.1).collect::<Vec<_>>());
|
||||||
|
}
|
||||||
|
@ -65,8 +65,9 @@ impl<'db> TrieDBMut<'db> {
|
|||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new trie with the backing database `db` and `root`
|
/// Create a new trie with the backing database `db` and `root`.
|
||||||
/// Panics, if `root` does not exist
|
/// Panics, if `root` does not exist.
|
||||||
|
// TODO: return Result<Self, TrieError>
|
||||||
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self {
|
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self {
|
||||||
if !db.exists(root) {
|
if !db.exists(root) {
|
||||||
flush(format!("Trie root not found {}", root));
|
flush(format!("Trie root not found {}", root));
|
||||||
|
Loading…
Reference in New Issue
Block a user