triehash optimisations (#7920)
This commit is contained in:
		
							parent
							
								
									ff0c44c060
								
							
						
					
					
						commit
						f905a1676f
					
				@ -778,7 +778,7 @@ impl Body {
 | 
			
		||||
	pub fn check_response(&self, cache: &Mutex<::cache::Cache>, body: &encoded::Body) -> Result<encoded::Block, Error> {
 | 
			
		||||
		// check the integrity of the the body against the header
 | 
			
		||||
		let header = self.0.as_ref()?;
 | 
			
		||||
		let tx_root = ::triehash::ordered_trie_root(body.rlp().at(0).iter().map(|r| r.as_raw().to_vec()));
 | 
			
		||||
		let tx_root = ::triehash::ordered_trie_root(body.rlp().at(0).iter().map(|r| r.as_raw()));
 | 
			
		||||
		if tx_root != header.transactions_root() {
 | 
			
		||||
			return Err(Error::WrongTrieRoot(header.transactions_root(), tx_root));
 | 
			
		||||
		}
 | 
			
		||||
@ -808,7 +808,7 @@ impl BlockReceipts {
 | 
			
		||||
	/// Check a response with receipts against the stored header.
 | 
			
		||||
	pub fn check_response(&self, cache: &Mutex<::cache::Cache>, receipts: &[Receipt]) -> Result<Vec<Receipt>, Error> {
 | 
			
		||||
		let receipts_root = self.0.as_ref()?.receipts_root();
 | 
			
		||||
		let found_root = ::triehash::ordered_trie_root(receipts.iter().map(|r| ::rlp::encode(r).into_vec()));
 | 
			
		||||
		let found_root = ::triehash::ordered_trie_root(receipts.iter().map(|r| ::rlp::encode(r)));
 | 
			
		||||
 | 
			
		||||
		match receipts_root == found_root {
 | 
			
		||||
			true => {
 | 
			
		||||
@ -1028,7 +1028,7 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
		let mut header = Header::new();
 | 
			
		||||
		let receipts_root = ::triehash::ordered_trie_root(
 | 
			
		||||
			receipts.iter().map(|x| ::rlp::encode(x).into_vec())
 | 
			
		||||
			receipts.iter().map(|x| ::rlp::encode(x))
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		header.set_receipts_root(receipts_root);
 | 
			
		||||
 | 
			
		||||
@ -447,11 +447,11 @@ impl<'x> OpenBlock<'x> {
 | 
			
		||||
		if let Err(e) = s.block.state.commit() {
 | 
			
		||||
			warn!("Encountered error on state commit: {}", e);
 | 
			
		||||
		}
 | 
			
		||||
		s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes().into_vec())));
 | 
			
		||||
		s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
 | 
			
		||||
		let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
 | 
			
		||||
		s.block.header.set_uncles_hash(keccak(&uncle_bytes));
 | 
			
		||||
		s.block.header.set_state_root(s.block.state.root().clone());
 | 
			
		||||
		s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes().into_vec())));
 | 
			
		||||
		s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes())));
 | 
			
		||||
		s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator
 | 
			
		||||
		s.block.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
 | 
			
		||||
 | 
			
		||||
@ -474,14 +474,14 @@ impl<'x> OpenBlock<'x> {
 | 
			
		||||
			warn!("Encountered error on state commit: {}", e);
 | 
			
		||||
		}
 | 
			
		||||
		if s.block.header.transactions_root().is_zero() || s.block.header.transactions_root() == &KECCAK_NULL_RLP {
 | 
			
		||||
			s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes().into_vec())));
 | 
			
		||||
			s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
 | 
			
		||||
		}
 | 
			
		||||
		let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
 | 
			
		||||
		if s.block.header.uncles_hash().is_zero() || s.block.header.uncles_hash() == &KECCAK_EMPTY_LIST_RLP {
 | 
			
		||||
			s.block.header.set_uncles_hash(keccak(&uncle_bytes));
 | 
			
		||||
		}
 | 
			
		||||
		if s.block.header.receipts_root().is_zero() || s.block.header.receipts_root() == &KECCAK_NULL_RLP {
 | 
			
		||||
			s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes().into_vec())));
 | 
			
		||||
			s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes())));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		s.block.header.set_state_root(s.block.state.root().clone());
 | 
			
		||||
@ -577,7 +577,7 @@ impl LockedBlock {
 | 
			
		||||
		for receipt in &mut block.block.receipts {
 | 
			
		||||
			receipt.outcome = TransactionOutcome::Unknown;
 | 
			
		||||
		}
 | 
			
		||||
		block.block.header.set_receipts_root(ordered_trie_root(block.block.receipts.iter().map(|r| r.rlp_bytes().into_vec())));
 | 
			
		||||
		block.block.header.set_receipts_root(ordered_trie_root(block.block.receipts.iter().map(|r| r.rlp_bytes())));
 | 
			
		||||
		block
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -378,7 +378,7 @@ impl ValidatorSet for ValidatorSafeContract {
 | 
			
		||||
			// ensure receipts match header.
 | 
			
		||||
			// TODO: optimize? these were just decoded.
 | 
			
		||||
			let found_root = ::triehash::ordered_trie_root(
 | 
			
		||||
				receipts.iter().map(::rlp::encode).map(|x| x.to_vec())
 | 
			
		||||
				receipts.iter().map(::rlp::encode)
 | 
			
		||||
			);
 | 
			
		||||
			if found_root != *old_header.receipts_root() {
 | 
			
		||||
				return Err(::error::BlockError::InvalidReceiptsRoot(
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,7 @@ impl PodAccount {
 | 
			
		||||
		let mut stream = RlpStream::new_list(4);
 | 
			
		||||
		stream.append(&self.nonce);
 | 
			
		||||
		stream.append(&self.balance);
 | 
			
		||||
		stream.append(&sec_trie_root(self.storage.iter().map(|(k, v)| (k.to_vec(), rlp::encode(&U256::from(&**v)).to_vec())).collect()));
 | 
			
		||||
		stream.append(&sec_trie_root(self.storage.iter().map(|(k, v)| (k, rlp::encode(&U256::from(&**v))))));
 | 
			
		||||
		stream.append(&keccak(&self.code.as_ref().unwrap_or(&vec![])));
 | 
			
		||||
		stream.out()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ impl PodState {
 | 
			
		||||
 | 
			
		||||
	/// Get the root hash of the trie of the RLP of this.
 | 
			
		||||
	pub fn root(&self) -> H256 {
 | 
			
		||||
		sec_trie_root(self.0.iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect())
 | 
			
		||||
		sec_trie_root(self.0.iter().map(|(k, v)| (k, v.rlp())))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Drain object to get the underlying map.
 | 
			
		||||
 | 
			
		||||
@ -107,7 +107,7 @@ impl AbridgedBlock {
 | 
			
		||||
		let uncles: Vec<Header> = rlp.list_at(9)?;
 | 
			
		||||
 | 
			
		||||
		header.set_transactions_root(ordered_trie_root(
 | 
			
		||||
			rlp.at(8)?.iter().map(|r| r.as_raw().to_owned())
 | 
			
		||||
			rlp.at(8)?.iter().map(|r| r.as_raw())
 | 
			
		||||
		));
 | 
			
		||||
		header.set_receipts_root(receipts_root);
 | 
			
		||||
 | 
			
		||||
@ -194,7 +194,7 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
		let receipts_root = b.header.receipts_root().clone();
 | 
			
		||||
		b.header.set_transactions_root(::triehash::ordered_trie_root(
 | 
			
		||||
			b.transactions.iter().map(::rlp::encode).map(|out| out.into_vec())
 | 
			
		||||
			b.transactions.iter().map(::rlp::encode)
 | 
			
		||||
		));
 | 
			
		||||
 | 
			
		||||
		let encoded = encode_block(&b);
 | 
			
		||||
 | 
			
		||||
@ -249,7 +249,7 @@ impl Rebuilder for PowRebuilder {
 | 
			
		||||
			let abridged_block = AbridgedBlock::from_raw(abridged_rlp);
 | 
			
		||||
			let receipts: Vec<::receipt::Receipt> = pair.list_at(1)?;
 | 
			
		||||
			let receipts_root = ordered_trie_root(
 | 
			
		||||
				pair.at(1)?.iter().map(|r| r.as_raw().to_owned())
 | 
			
		||||
				pair.at(1)?.iter().map(|r| r.as_raw())
 | 
			
		||||
			);
 | 
			
		||||
 | 
			
		||||
			let block = abridged_block.to_block(parent_hash, cur_number, receipts_root)?;
 | 
			
		||||
 | 
			
		||||
@ -320,7 +320,7 @@ fn verify_parent(header: &Header, parent: &Header, gas_limit_divisor: U256) -> R
 | 
			
		||||
fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: &H256) -> Result<(), Error> {
 | 
			
		||||
	let block = UntrustedRlp::new(block);
 | 
			
		||||
	let tx = block.at(1)?;
 | 
			
		||||
	let expected_root = &ordered_trie_root(tx.iter().map(|r| r.as_raw().to_vec())); //TODO: get rid of vectors here
 | 
			
		||||
	let expected_root = &ordered_trie_root(tx.iter().map(|r| r.as_raw()));
 | 
			
		||||
	if expected_root != transactions_root {
 | 
			
		||||
		return Err(From::from(BlockError::InvalidTransactionsRoot(Mismatch { expected: expected_root.clone(), found: transactions_root.clone() })))
 | 
			
		||||
	}
 | 
			
		||||
@ -570,7 +570,7 @@ mod tests {
 | 
			
		||||
		let mut uncles_rlp = RlpStream::new();
 | 
			
		||||
		uncles_rlp.append_list(&good_uncles);
 | 
			
		||||
		let good_uncles_hash = keccak(uncles_rlp.as_raw());
 | 
			
		||||
		let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| ::rlp::encode::<UnverifiedTransaction>(t).into_vec()));
 | 
			
		||||
		let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| ::rlp::encode::<UnverifiedTransaction>(t)));
 | 
			
		||||
 | 
			
		||||
		let mut parent = good.clone();
 | 
			
		||||
		parent.set_number(9);
 | 
			
		||||
 | 
			
		||||
@ -345,7 +345,7 @@ impl BlockCollection {
 | 
			
		||||
		let header_id = {
 | 
			
		||||
			let body = UntrustedRlp::new(&b);
 | 
			
		||||
			let tx = body.at(0)?;
 | 
			
		||||
			let tx_root = ordered_trie_root(tx.iter().map(|r| r.as_raw().to_vec())); //TODO: get rid of vectors here
 | 
			
		||||
			let tx_root = ordered_trie_root(tx.iter().map(|r| r.as_raw()));
 | 
			
		||||
			let uncles = keccak(body.at(1)?.as_raw());
 | 
			
		||||
			HeaderId {
 | 
			
		||||
				transactions_root: tx_root,
 | 
			
		||||
@ -379,7 +379,7 @@ impl BlockCollection {
 | 
			
		||||
	fn insert_receipt(&mut self, r: Bytes) -> Result<(), network::Error> {
 | 
			
		||||
		let receipt_root = {
 | 
			
		||||
			let receipts = UntrustedRlp::new(&r);
 | 
			
		||||
			ordered_trie_root(receipts.iter().map(|r| r.as_raw().to_vec())) //TODO: get rid of vectors here
 | 
			
		||||
			ordered_trie_root(receipts.iter().map(|r| r.as_raw()))
 | 
			
		||||
		};
 | 
			
		||||
		self.downloading_receipts.remove(&receipt_root);
 | 
			
		||||
		match self.receipt_ids.entry(receipt_root) {
 | 
			
		||||
 | 
			
		||||
@ -40,27 +40,28 @@ fn shared_prefix_len<T: Eq>(first: &[T], second: &[T]) -> usize {
 | 
			
		||||
/// use triehash::ordered_trie_root;
 | 
			
		||||
///
 | 
			
		||||
/// fn main() {
 | 
			
		||||
/// 	let v = vec![From::from("doe"), From::from("reindeer")];
 | 
			
		||||
/// 	let v = &["doe", "reindeer"];
 | 
			
		||||
/// 	let root = "e766d5d51b89dc39d981b41bda63248d7abce4f0225eefd023792a540bcffee3";
 | 
			
		||||
/// 	assert_eq!(ordered_trie_root(v), root.parse().unwrap());
 | 
			
		||||
/// 	assert_eq!(ordered_trie_root(v), root.into());
 | 
			
		||||
/// }
 | 
			
		||||
/// ```
 | 
			
		||||
pub fn ordered_trie_root<I>(input: I) -> H256
 | 
			
		||||
	where I: IntoIterator<Item=Vec<u8>>
 | 
			
		||||
pub fn ordered_trie_root<I, A>(input: I) -> H256
 | 
			
		||||
	where I: IntoIterator<Item = A>,
 | 
			
		||||
		  A: AsRef<[u8]>,
 | 
			
		||||
{
 | 
			
		||||
	let gen_input = input
 | 
			
		||||
	let gen_input: Vec<_> = input
 | 
			
		||||
		// first put elements into btree to sort them by nibbles
 | 
			
		||||
		// optimize it later
 | 
			
		||||
		.into_iter()
 | 
			
		||||
		.enumerate()
 | 
			
		||||
		.map(|(i, vec)| (rlp::encode(&i).into_vec(), vec))
 | 
			
		||||
		.map(|(i, slice)| (rlp::encode(&i), slice))
 | 
			
		||||
		.collect::<BTreeMap<_, _>>()
 | 
			
		||||
		// then move them to a vector
 | 
			
		||||
		.into_iter()
 | 
			
		||||
		.map(|(k, v)| (as_nibbles(&k), v) )
 | 
			
		||||
		.collect();
 | 
			
		||||
 | 
			
		||||
	gen_trie_root(gen_input)
 | 
			
		||||
	gen_trie_root(&gen_input)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Generates a trie root hash for a vector of key-values
 | 
			
		||||
@ -71,28 +72,30 @@ pub fn ordered_trie_root<I>(input: I) -> H256
 | 
			
		||||
///
 | 
			
		||||
/// fn main() {
 | 
			
		||||
/// 	let v = vec![
 | 
			
		||||
/// 		(From::from("doe"), From::from("reindeer")),
 | 
			
		||||
/// 		(From::from("dog"), From::from("puppy")),
 | 
			
		||||
/// 		(From::from("dogglesworth"), From::from("cat")),
 | 
			
		||||
/// 		("doe", "reindeer"),
 | 
			
		||||
/// 		("dog", "puppy"),
 | 
			
		||||
/// 		("dogglesworth", "cat"),
 | 
			
		||||
/// 	];
 | 
			
		||||
///
 | 
			
		||||
/// 	let root = "8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3";
 | 
			
		||||
/// 	assert_eq!(trie_root(v), root.parse().unwrap());
 | 
			
		||||
/// 	assert_eq!(trie_root(v), root.into());
 | 
			
		||||
/// }
 | 
			
		||||
/// ```
 | 
			
		||||
pub fn trie_root<I>(input: I) -> H256
 | 
			
		||||
	where I: IntoIterator<Item=(Vec<u8>, Vec<u8>)>
 | 
			
		||||
pub fn trie_root<I, A, B>(input: I) -> H256
 | 
			
		||||
	where I: IntoIterator<Item = (A, B)>,
 | 
			
		||||
		  A: AsRef<[u8]> + Ord,
 | 
			
		||||
		  B: AsRef<[u8]>,
 | 
			
		||||
{
 | 
			
		||||
	let gen_input = input
 | 
			
		||||
	let gen_input: Vec<_> = input
 | 
			
		||||
		// first put elements into btree to sort them and to remove duplicates
 | 
			
		||||
		.into_iter()
 | 
			
		||||
		.collect::<BTreeMap<_, _>>()
 | 
			
		||||
		// then move them to a vector
 | 
			
		||||
		.into_iter()
 | 
			
		||||
		.map(|(k, v)| (as_nibbles(&k), v) )
 | 
			
		||||
		.map(|(k, v)| (as_nibbles(k.as_ref()), v) )
 | 
			
		||||
		.collect();
 | 
			
		||||
 | 
			
		||||
	gen_trie_root(gen_input)
 | 
			
		||||
	gen_trie_root(&gen_input)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Generates a key-hashed (secure) trie root hash for a vector of key-values.
 | 
			
		||||
@ -103,17 +106,21 @@ pub fn trie_root<I>(input: I) -> H256
 | 
			
		||||
///
 | 
			
		||||
/// fn main() {
 | 
			
		||||
/// 	let v = vec![
 | 
			
		||||
/// 		(From::from("doe"), From::from("reindeer")),
 | 
			
		||||
/// 		(From::from("dog"), From::from("puppy")),
 | 
			
		||||
/// 		(From::from("dogglesworth"), From::from("cat")),
 | 
			
		||||
/// 		("doe", "reindeer"),
 | 
			
		||||
/// 		("dog", "puppy"),
 | 
			
		||||
/// 		("dogglesworth", "cat"),
 | 
			
		||||
/// 	];
 | 
			
		||||
///
 | 
			
		||||
/// 	let root = "d4cd937e4a4368d7931a9cf51686b7e10abb3dce38a39000fd7902a092b64585";
 | 
			
		||||
/// 	assert_eq!(sec_trie_root(v), root.parse().unwrap());
 | 
			
		||||
/// 	assert_eq!(sec_trie_root(v), root.into());
 | 
			
		||||
/// }
 | 
			
		||||
/// ```
 | 
			
		||||
pub fn sec_trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
 | 
			
		||||
	let gen_input = input
 | 
			
		||||
pub fn sec_trie_root<I, A, B>(input: I) -> H256
 | 
			
		||||
	where I: IntoIterator<Item = (A, B)>,
 | 
			
		||||
		  A: AsRef<[u8]>,
 | 
			
		||||
		  B: AsRef<[u8]>,
 | 
			
		||||
{
 | 
			
		||||
	let gen_input: Vec<_> = input
 | 
			
		||||
		// first put elements into btree to sort them and to remove duplicates
 | 
			
		||||
		.into_iter()
 | 
			
		||||
		.map(|(k, v)| (keccak(k), v))
 | 
			
		||||
@ -123,12 +130,12 @@ pub fn sec_trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
 | 
			
		||||
		.map(|(k, v)| (as_nibbles(&k), v) )
 | 
			
		||||
		.collect();
 | 
			
		||||
 | 
			
		||||
	gen_trie_root(gen_input)
 | 
			
		||||
	gen_trie_root(&gen_input)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn gen_trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
 | 
			
		||||
fn gen_trie_root<A: AsRef<[u8]>, B: AsRef<[u8]>>(input: &[(A, B)]) -> H256 {
 | 
			
		||||
	let mut stream = RlpStream::new();
 | 
			
		||||
	hash256rlp(&input, 0, &mut stream);
 | 
			
		||||
	hash256rlp(input, 0, &mut stream);
 | 
			
		||||
	keccak(stream.out())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -189,7 +196,7 @@ fn as_nibbles(bytes: &[u8]) -> Vec<u8> {
 | 
			
		||||
	res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn hash256rlp(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStream) {
 | 
			
		||||
fn hash256rlp<A: AsRef<[u8]>, B: AsRef<[u8]>>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream) {
 | 
			
		||||
	let inlen = input.len();
 | 
			
		||||
 | 
			
		||||
	// in case of empty slice, just append empty data
 | 
			
		||||
@ -199,8 +206,8 @@ fn hash256rlp(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStre
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// take slices
 | 
			
		||||
	let key: &[u8] = &input[0].0;
 | 
			
		||||
	let value: &[u8] = &input[0].1;
 | 
			
		||||
	let key: &[u8] = &input[0].0.as_ref();
 | 
			
		||||
	let value: &[u8] = &input[0].1.as_ref();
 | 
			
		||||
 | 
			
		||||
	// if the slice contains just one item, append the suffix of the key
 | 
			
		||||
	// and then append value
 | 
			
		||||
@ -217,7 +224,7 @@ fn hash256rlp(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStre
 | 
			
		||||
		.skip(1)
 | 
			
		||||
		// get minimum number of shared nibbles between first and each successive
 | 
			
		||||
		.fold(key.len(), | acc, &(ref k, _) | {
 | 
			
		||||
			cmp::min(shared_prefix_len(key, k), acc)
 | 
			
		||||
			cmp::min(shared_prefix_len(key, k.as_ref()), acc)
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
	// if shared prefix is higher than current prefix append its
 | 
			
		||||
@ -245,7 +252,7 @@ fn hash256rlp(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStre
 | 
			
		||||
		// cout how many successive elements have same next nibble
 | 
			
		||||
		let len = match begin < input.len() {
 | 
			
		||||
			true => input[begin..].iter()
 | 
			
		||||
				.take_while(| pair | pair.0[pre_len] == i )
 | 
			
		||||
				.take_while(| pair | pair.0.as_ref()[pre_len] == i )
 | 
			
		||||
				.count(),
 | 
			
		||||
			false => 0
 | 
			
		||||
		};
 | 
			
		||||
@ -266,7 +273,7 @@ fn hash256rlp(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStre
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn hash256aux(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStream) {
 | 
			
		||||
fn hash256aux<A: AsRef<[u8]>, B: AsRef<[u8]>>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream) {
 | 
			
		||||
	let mut s = RlpStream::new();
 | 
			
		||||
	hash256rlp(input, pre_len, &mut s);
 | 
			
		||||
	let out = s.out();
 | 
			
		||||
@ -330,8 +337,8 @@ mod tests {
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn simple_test() {
 | 
			
		||||
		assert_eq!(trie_root(vec![
 | 
			
		||||
			(b"A".to_vec(), b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_vec())
 | 
			
		||||
		]), "d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab".parse().unwrap());
 | 
			
		||||
			(b"A", b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8])
 | 
			
		||||
		]), "d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab".into());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user