Move ethcore files back into root.

This commit is contained in:
Gav Wood
2016-01-17 13:11:25 +01:00
parent 9b87bae322
commit 6ea8eaa3b5
159 changed files with 511 additions and 511 deletions

336
src/account.rs Normal file
View File

@@ -0,0 +1,336 @@
use util::*;
use pod_account::*;
/// Single account in the system.
#[derive(Clone)]
pub struct Account {
// Balance of the account.
balance: U256,
// Nonce of the account.
nonce: U256,
// Trie-backed storage.
storage_root: H256,
// Overlay on trie-backed storage - tuple is (<clean>, <value>).
storage_overlay: RefCell<HashMap<H256, (Filth, H256)>>,
// Code hash of the account. If None, means that it's a contract whose code has not yet been set.
code_hash: Option<H256>,
// Code cache of the account.
code_cache: Bytes,
}
impl Account {
/// General constructor.
pub fn new(balance: U256, nonce: U256, storage: HashMap<H256, H256>, code: Bytes) -> Account {
Account {
balance: balance,
nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
code_hash: Some(code.sha3()),
code_cache: code
}
}
/// General constructor.
pub fn from_pod(pod: PodAccount) -> Account {
Account {
balance: pod.balance,
nonce: pod.nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(pod.storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
code_hash: Some(pod.code.sha3()),
code_cache: pod.code
}
}
/// Create a new account with the given balance.
pub fn new_basic(balance: U256, nonce: U256) -> Account {
Account {
balance: balance,
nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(HashMap::new()),
code_hash: Some(SHA3_EMPTY),
code_cache: vec![],
}
}
/// Create a new account from RLP.
pub fn from_rlp(rlp: &[u8]) -> Account {
let r: Rlp = Rlp::new(rlp);
Account {
nonce: r.val_at(0),
balance: r.val_at(1),
storage_root: r.val_at(2),
storage_overlay: RefCell::new(HashMap::new()),
code_hash: Some(r.val_at(3)),
code_cache: vec![],
}
}
/// Create a new contract account.
/// NOTE: make sure you use `init_code` on this before `commit`ing.
pub fn new_contract(balance: U256) -> Account {
Account {
balance: balance,
nonce: U256::from(0u8),
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(HashMap::new()),
code_hash: None,
code_cache: vec![],
}
}
/// Reset this account to the status of a not-yet-initialised contract.
/// NOTE: Account should have `init_code()` called on it later.
pub fn reset_code(&mut self) {
self.code_hash = None;
self.code_cache = vec![];
}
/// Set this account's code to the given code.
/// NOTE: Account should have been created with `new_contract()` or have `reset_code()` called on it.
pub fn init_code(&mut self, code: Bytes) {
assert!(self.code_hash.is_none());
self.code_cache = code;
}
/// Set (and cache) the contents of the trie's storage at `key` to `value`.
pub fn set_storage(&mut self, key: H256, value: H256) {
self.storage_overlay.borrow_mut().insert(key, (Filth::Dirty, value));
}
/// Get (and cache) the contents of the trie's storage at `key`.
pub fn storage_at(&self, db: &HashDB, key: &H256) -> H256 {
self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
(Filth::Clean, H256::from(SecTrieDB::new(db, &self.storage_root).get(key.bytes()).map(|v| -> U256 {decode(v)}).unwrap_or(U256::zero())))
}).1.clone()
}
/// return the balance associated with this account.
pub fn balance(&self) -> &U256 { &self.balance }
/// return the nonce associated with this account.
pub fn nonce(&self) -> &U256 { &self.nonce }
/// return the code hash associated with this account.
pub fn code_hash(&self) -> H256 {
self.code_hash.clone().unwrap_or(SHA3_EMPTY)
}
/// returns the account's code. If `None` then the code cache isn't available -
/// get someone who knows to call `note_code`.
pub fn code(&self) -> Option<&[u8]> {
match self.code_hash {
Some(SHA3_EMPTY) | None if self.code_cache.is_empty() => Some(&self.code_cache),
Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache),
None => Some(&self.code_cache),
_ => None,
}
}
/// Provide a byte array which hashes to the `code_hash`. returns the hash as a result.
pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> {
let h = code.sha3();
match self.code_hash {
Some(ref i) if h == *i => {
self.code_cache = code;
Ok(())
},
_ => Err(h)
}
}
/// Is `code_cache` valid; such that code is going to return Some?
pub fn is_cached(&self) -> bool {
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == Some(SHA3_EMPTY))
}
/// Provide a database to lookup `code_hash`. Should not be called if it is a contract without code.
pub fn cache_code(&mut self, db: &HashDB) -> bool {
// TODO: fill out self.code_cache;
return self.is_cached() ||
match self.code_hash {
Some(ref h) => match db.lookup(h) {
Some(x) => { self.code_cache = x.to_vec(); true },
_ => false,
},
_ => false,
}
}
/// return the storage root associated with this account.
pub fn base_root(&self) -> &H256 { &self.storage_root }
/// Determine whether there are any un-`commit()`-ed storage-setting operations.
pub fn storage_is_clean(&self) -> bool { self.storage_overlay.borrow().iter().find(|&(_, &(f, _))| f == Filth::Dirty).is_none() }
/// return the storage root associated with this account or None if it has been altered via the overlay.
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
/// return the storage root associated with this account or None if it has been altered via the overlay.
pub fn recent_storage_root(&self) -> &H256 { &self.storage_root }
/// return the storage overlay.
pub fn storage_overlay(&self) -> Ref<HashMap<H256, (Filth, H256)>> { self.storage_overlay.borrow() }
/// Increment the nonce of the account by one.
pub fn inc_nonce(&mut self) { self.nonce = self.nonce + U256::from(1u8); }
/// Increment the nonce of the account by one.
pub fn add_balance(&mut self, x: &U256) { self.balance = self.balance + *x; }
/// Increment the nonce of the account by one.
pub fn sub_balance(&mut self, x: &U256) { self.balance = self.balance - *x; }
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, db: &mut HashDB) {
let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root);
for (k, &mut (ref mut f, ref mut v)) in self.storage_overlay.borrow_mut().iter_mut() {
if f == &Filth::Dirty {
// cast key and value to trait type,
// so we can call overloaded `to_bytes` method
match v.is_zero() {
true => { t.remove(k); },
false => { t.insert(k, &encode(&U256::from(v.as_slice()))); },
}
*f = Filth::Clean;
}
}
}
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
pub fn commit_code(&mut self, db: &mut HashDB) {
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty());
match (self.code_hash.is_none(), self.code_cache.is_empty()) {
(true, true) => self.code_hash = Some(SHA3_EMPTY),
(true, false) => {
self.code_hash = Some(db.insert(&self.code_cache));
},
(false, _) => {},
}
}
/// Export to RLP.
pub fn rlp(&self) -> Bytes {
let mut stream = RlpStream::new_list(4);
stream.append(&self.nonce);
stream.append(&self.balance);
stream.append(&self.storage_root);
stream.append(self.code_hash.as_ref().expect("Cannot form RLP of contract account without code."));
stream.out()
}
}
impl fmt::Debug for Account {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", PodAccount::from_account(self))
}
}
#[cfg(test)]
mod tests {
use util::*;
use super::*;
#[test]
fn storage_at() {
let mut db = OverlayDB::new_temp();
let rlp = {
let mut a = Account::new_contract(U256::from(69u8));
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
a.commit_storage(&mut db);
a.init_code(vec![]);
a.commit_code(&mut db);
a.rlp()
};
let a = Account::from_rlp(&rlp);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
assert_eq!(a.storage_at(&mut db, &H256::from(&U256::from(0x00u64))), H256::from(&U256::from(0x1234u64)));
assert_eq!(a.storage_at(&mut db, &H256::from(&U256::from(0x01u64))), H256::new());
}
#[test]
fn note_code() {
let mut db = OverlayDB::new_temp();
let rlp = {
let mut a = Account::new_contract(U256::from(69u8));
a.init_code(vec![0x55, 0x44, 0xffu8]);
a.commit_code(&mut db);
a.rlp()
};
let mut a = Account::from_rlp(&rlp);
assert!(a.cache_code(&db));
let mut a = Account::from_rlp(&rlp);
assert_eq!(a.note_code(vec![0x55, 0x44, 0xffu8]), Ok(()));
}
#[test]
fn commit_storage() {
let mut a = Account::new_contract(U256::from(69u8));
let mut db = OverlayDB::new_temp();
a.set_storage(x!(0), x!(0x1234));
assert_eq!(a.storage_root(), None);
a.commit_storage(&mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
}
#[test]
fn commit_remove_commit_storage() {
let mut a = Account::new_contract(U256::from(69u8));
let mut db = OverlayDB::new_temp();
a.set_storage(x!(0), x!(0x1234));
a.commit_storage(&mut db);
a.set_storage(x!(1), x!(0x1234));
a.commit_storage(&mut db);
a.set_storage(x!(1), x!(0));
a.commit_storage(&mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
}
#[test]
fn commit_code() {
let mut a = Account::new_contract(U256::from(69u8));
let mut db = OverlayDB::new_temp();
a.init_code(vec![0x55, 0x44, 0xffu8]);
assert_eq!(a.code_hash(), SHA3_EMPTY);
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
}
#[test]
fn rlpio() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
let b = Account::from_rlp(&a.rlp());
assert_eq!(a.balance(), b.balance());
assert_eq!(a.nonce(), b.nonce());
assert_eq!(a.code_hash(), b.code_hash());
assert_eq!(a.storage_root(), b.storage_root());
}
#[test]
fn new_account() {
use rustc_serialize::hex::ToHex;
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
assert_eq!(a.balance(), &U256::from(69u8));
assert_eq!(a.nonce(), &U256::from(0u8));
assert_eq!(a.code_hash(), SHA3_EMPTY);
assert_eq!(a.storage_root().unwrap(), &SHA3_NULL_RLP);
}
#[test]
fn create_account() {
use rustc_serialize::hex::ToHex;
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
}
}

121
src/account_diff.rs Normal file
View File

@@ -0,0 +1,121 @@
use util::*;
use pod_account::*;
#[derive(Debug,Clone,PartialEq,Eq)]
/// Change in existance type.
// TODO: include other types of change.
pub enum Existance {
Born,
Alive,
Died,
}
impl fmt::Display for Existance {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Existance::Born => try!(write!(f, "+++")),
&Existance::Alive => try!(write!(f, "***")),
&Existance::Died => try!(write!(f, "XXX")),
}
Ok(())
}
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct AccountDiff {
pub balance: Diff<U256>, // Allowed to be Same
pub nonce: Diff<U256>, // Allowed to be Same
pub code: Diff<Bytes>, // Allowed to be Same
pub storage: BTreeMap<H256, Diff<H256>>,// Not allowed to be Same
}
impl AccountDiff {
pub fn existance(&self) -> Existance {
match self.balance {
Diff::Born(_) => Existance::Born,
Diff::Died(_) => Existance::Died,
_ => Existance::Alive,
}
}
pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<AccountDiff> {
match (pre, post) {
(None, Some(x)) => Some(AccountDiff {
balance: Diff::Born(x.balance.clone()),
nonce: Diff::Born(x.nonce.clone()),
code: Diff::Born(x.code.clone()),
storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Born(v.clone()))).collect(),
}),
(Some(x), None) => Some(AccountDiff {
balance: Diff::Died(x.balance.clone()),
nonce: Diff::Died(x.nonce.clone()),
code: Diff::Died(x.code.clone()),
storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Died(v.clone()))).collect(),
}),
(Some(pre), Some(post)) => {
let storage: Vec<_> = pre.storage.keys().merge(post.storage.keys())
.filter(|k| pre.storage.get(k).unwrap_or(&H256::new()) != post.storage.get(k).unwrap_or(&H256::new()))
.collect();
let r = AccountDiff {
balance: Diff::new(pre.balance.clone(), post.balance.clone()),
nonce: Diff::new(pre.nonce.clone(), post.nonce.clone()),
code: Diff::new(pre.code.clone(), post.code.clone()),
storage: storage.into_iter().map(|k|
(k.clone(), Diff::new(
pre.storage.get(&k).cloned().unwrap_or(H256::new()),
post.storage.get(&k).cloned().unwrap_or(H256::new())
))).collect(),
};
if r.balance.is_same() && r.nonce.is_same() && r.code.is_same() && r.storage.len() == 0 {
None
} else {
Some(r)
}
},
_ => None,
}
}
}
// TODO: refactor into something nicer.
fn interpreted_hash(u: &H256) -> String {
if u <= &H256::from(0xffffffff) {
format!("{} = 0x{:x}", U256::from(u.as_slice()).low_u32(), U256::from(u.as_slice()).low_u32())
} else if u <= &H256::from(u64::max_value()) {
format!("{} = 0x{:x}", U256::from(u.as_slice()).low_u64(), U256::from(u.as_slice()).low_u64())
// } else if u <= &H256::from("0xffffffffffffffffffffffffffffffffffffffff") {
// format!("@{}", Address::from(u))
} else {
format!("#{}", u)
}
}
impl fmt::Display for AccountDiff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.nonce {
Diff::Born(ref x) => try!(write!(f, " non {}", x)),
Diff::Changed(ref pre, ref post) => try!(write!(f, "#{} ({} {} {})", post, pre, if pre > post {"-"} else {"+"}, *max(pre, post) - * min(pre, post))),
_ => {},
}
match self.balance {
Diff::Born(ref x) => try!(write!(f, " bal {}", x)),
Diff::Changed(ref pre, ref post) => try!(write!(f, "${} ({} {} {})", post, pre, if pre > post {"-"} else {"+"}, *max(pre, post) - *min(pre, post))),
_ => {},
}
match self.code {
Diff::Born(ref x) => try!(write!(f, " code {}", x.pretty())),
_ => {},
}
try!(write!(f, "\n"));
for (k, dv) in self.storage.iter() {
match dv {
&Diff::Born(ref v) => try!(write!(f, " + {} => {}\n", interpreted_hash(k), interpreted_hash(v))),
&Diff::Changed(ref pre, ref post) => try!(write!(f, " * {} => {} (was {})\n", interpreted_hash(k), interpreted_hash(post), interpreted_hash(pre))),
&Diff::Died(_) => try!(write!(f, " X {}\n", interpreted_hash(k))),
_ => {},
}
}
Ok(())
}
}

46
src/action_params.rs Normal file
View File

@@ -0,0 +1,46 @@
//! Evm input params.
use util::hash::*;
use util::uint::*;
use util::bytes::*;
// TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View).
/// Action (call/create) input params. Everything else should be specified in Externalities.
#[derive(Clone, Debug)]
pub struct ActionParams {
/// Address of currently executed code.
pub code_address: Address,
/// Receive address. Usually equal to code_address,
/// except when called using CALLCODE.
pub address: Address,
/// Sender of current part of the transaction.
pub sender: Address,
/// Transaction initiator.
pub origin: Address,
/// Gas paid up front for transaction execution
pub gas: U256,
/// Gas price.
pub gas_price: U256,
/// Transaction value.
pub value: U256,
/// Code being executed.
pub code: Option<Bytes>,
/// Input data.
pub data: Option<Bytes>
}
impl ActionParams {
pub fn new() -> ActionParams {
ActionParams {
code_address: Address::new(),
address: Address::new(),
sender: Address::new(),
origin: Address::new(),
gas: U256::zero(),
gas_price: U256::zero(),
value: U256::zero(),
code: None,
data: None
}
}
}

12
src/basic_types.rs Normal file
View File

@@ -0,0 +1,12 @@
use util::*;
/// Type for a 2048-bit log-bloom, as used by our blocks.
pub type LogBloom = H2048;
/// Constant 2048-bit datum for 0. Often used as a default.
pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]);
pub enum Seal {
With,
Without,
}

60
src/bin/client.rs Normal file
View File

@@ -0,0 +1,60 @@
extern crate ethcore_util as util;
extern crate ethcore;
extern crate rustc_serialize;
extern crate log;
extern crate env_logger;
use std::io::stdin;
use std::env;
use log::{LogLevelFilter};
use env_logger::LogBuilder;
use util::*;
use ethcore::client::*;
use ethcore::service::ClientService;
use ethcore::ethereum;
use ethcore::sync::*;
fn setup_log() {
let mut builder = LogBuilder::new();
builder.filter(None, LogLevelFilter::Info);
if env::var("RUST_LOG").is_ok() {
builder.parse(&env::var("RUST_LOG").unwrap());
}
builder.init().unwrap();
}
fn main() {
setup_log();
let spec = ethereum::new_frontier();
let mut service = ClientService::start(spec).unwrap();
let io_handler = Box::new(ClientIoHandler { client: service.client(), timer: 0 });
service.io().register_handler(io_handler).expect("Error registering IO handler");
loop {
let mut cmd = String::new();
stdin().read_line(&mut cmd).unwrap();
if cmd == "quit\n" || cmd == "exit\n" || cmd == "q\n" {
break;
}
}
}
struct ClientIoHandler {
client: Arc<RwLock<Client>>,
timer: TimerToken,
}
impl IoHandler<NetSyncMessage> for ClientIoHandler {
fn initialize<'s>(&'s mut self, io: &mut IoContext<'s, NetSyncMessage>) {
self.timer = io.register_timer(5000).expect("Error registering timer");
}
fn timeout<'s>(&'s mut self, _io: &mut IoContext<'s, NetSyncMessage>, timer: TimerToken) {
if self.timer == timer {
println!("Chain info: {:?}", self.client.read().unwrap().deref().chain_info());
}
}
}

326
src/block.rs Normal file
View File

@@ -0,0 +1,326 @@
use common::*;
use engine::*;
use state::*;
/// A transaction/receipt execution entry.
pub struct Entry {
transaction: Transaction,
receipt: Receipt,
}
/// Internal type for a block's common elements.
pub struct Block {
header: Header,
/// State is the most final state in the block.
state: State,
archive: Vec<Entry>,
archive_set: HashSet<H256>,
uncles: Vec<Header>,
}
/// A set of references to `Block` fields that are publicly accessible.
pub struct BlockRefMut<'a> {
pub header: &'a Header,
pub state: &'a mut State,
pub archive: &'a Vec<Entry>,
pub uncles: &'a Vec<Header>,
}
impl Block {
/// Create a new block from the given `state`.
fn new(state: State) -> Block {
Block {
header: Header::new(),
state: state,
archive: Vec::new(),
archive_set: HashSet::new(),
uncles: Vec::new(),
}
}
/// Get a structure containing individual references to all public fields.
pub fn fields(&mut self) -> BlockRefMut {
BlockRefMut {
header: &self.header,
state: &mut self.state,
archive: &self.archive,
uncles: &self.uncles,
}
}
}
/// Trait for a object that is_a `Block`.
pub trait IsBlock {
/// Get the block associated with this object.
fn block(&self) -> &Block;
/// Get the header associated with this object's block.
fn header(&self) -> &Header { &self.block().header }
/// Get the final state associated with this object's block.
fn state(&self) -> &State { &self.block().state }
/// Get all information on transactions in this block.
fn archive(&self) -> &Vec<Entry> { &self.block().archive }
/// Get all uncles in this block.
fn uncles(&self) -> &Vec<Header> { &self.block().uncles }
}
impl IsBlock for Block {
fn block(&self) -> &Block { self }
}
/// Block that is ready for transactions to be added.
///
/// It's a bit like a Vec<Transaction>, eccept that whenever a transaction is pushed, we execute it and
/// maintain the system `state()`. We also archive execution receipts in preparation for later block creation.
pub struct OpenBlock<'x, 'y> {
block: Block,
engine: &'x Engine,
last_hashes: &'y LastHashes,
}
/// Just like OpenBlock, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
/// and collected the uncles.
///
/// There is no function available to push a transaction. If you want that you'll need to `reopen()` it.
pub struct ClosedBlock<'x, 'y> {
open_block: OpenBlock<'x, 'y>,
uncle_bytes: Bytes,
}
/// A block that has a valid seal.
///
/// The block's header has valid seal arguments. The block cannot be reversed into a ClosedBlock or OpenBlock.
pub struct SealedBlock {
block: Block,
uncle_bytes: Bytes,
}
impl<'x, 'y> OpenBlock<'x, 'y> {
/// Create a new OpenBlock ready for transaction pushing.
pub fn new<'a, 'b>(engine: &'a Engine, db: OverlayDB, parent: &Header, last_hashes: &'b LastHashes, author: Address, extra_data: Bytes) -> OpenBlock<'a, 'b> {
let mut r = OpenBlock {
block: Block::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())),
engine: engine,
last_hashes: last_hashes,
};
r.block.header.set_number(parent.number() + 1);
r.block.header.set_author(author);
r.block.header.set_extra_data(extra_data);
r.block.header.set_timestamp_now();
engine.populate_from_parent(&mut r.block.header, parent);
engine.on_new_block(&mut r.block);
r
}
/// Alter the author for the block.
pub fn set_author(&mut self, author: Address) { self.block.header.set_author(author); }
/// Alter the timestamp of the block.
pub fn set_timestamp(&mut self, timestamp: u64) { self.block.header.set_timestamp(timestamp); }
/// Alter the difficulty for the block.
pub fn set_difficulty(&mut self, a: U256) { self.block.header.set_difficulty(a); }
/// Alter the gas limit for the block.
pub fn set_gas_limit(&mut self, a: U256) { self.block.header.set_gas_limit(a); }
/// Alter the gas limit for the block.
pub fn set_gas_used(&mut self, a: U256) { self.block.header.set_gas_used(a); }
/// Alter the extra_data for the block.
pub fn set_extra_data(&mut self, extra_data: Bytes) -> Result<(), BlockError> {
if extra_data.len() > self.engine.maximum_extra_data_size() {
Err(BlockError::ExtraDataOutOfBounds(OutOfBounds{min: None, max: Some(self.engine.maximum_extra_data_size()), found: extra_data.len()}))
} else {
self.block.header.set_extra_data(extra_data);
Ok(())
}
}
/// Add an uncle to the block, if possible.
///
/// NOTE Will check chain constraints and the uncle number but will NOT check
/// that the header itself is actually valid.
pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> {
if self.block.uncles.len() >= self.engine.maximum_uncle_count() {
return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.uncles.len()}));
}
// TODO: check number
// TODO: check not a direct ancestor (use last_hashes for that)
self.block.uncles.push(valid_uncle_header);
Ok(())
}
/// Get the environment info concerning this block.
pub fn env_info(&self) -> EnvInfo {
// TODO: memoise.
EnvInfo {
number: self.block.header.number,
author: self.block.header.author.clone(),
timestamp: self.block.header.timestamp,
difficulty: self.block.header.difficulty.clone(),
last_hashes: self.last_hashes.clone(), // TODO: should be a reference.
gas_used: self.block.archive.last().map(|t| t.receipt.gas_used).unwrap_or(U256::from(0)),
gas_limit: self.block.header.gas_limit.clone(),
}
}
/// Push a transaction into the block.
///
/// If valid, it will be executed, and archived together with the receipt.
pub fn push_transaction(&mut self, t: Transaction, h: Option<H256>) -> Result<&Receipt, Error> {
let env_info = self.env_info();
// info!("env_info says gas_used={}", env_info.gas_used);
match self.block.state.apply(&env_info, self.engine, &t) {
Ok(receipt) => {
self.block.archive_set.insert(h.unwrap_or_else(||t.hash()));
self.block.archive.push(Entry { transaction: t, receipt: receipt });
Ok(&self.block.archive.last().unwrap().receipt)
}
Err(x) => Err(From::from(x))
}
}
/// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles.
pub fn close(self) -> ClosedBlock<'x, 'y> {
let mut s = self;
s.engine.on_close_block(&mut s.block);
s.block.header.transactions_root = ordered_trie_root(s.block.archive.iter().map(|ref e| e.transaction.rlp_bytes()).collect());
let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append(&u.rlp(Seal::With)); s} ).out();
s.block.header.uncles_hash = uncle_bytes.sha3();
s.block.header.state_root = s.block.state.root().clone();
s.block.header.receipts_root = ordered_trie_root(s.block.archive.iter().map(|ref e| e.receipt.rlp_bytes()).collect());
s.block.header.log_bloom = s.block.archive.iter().fold(LogBloom::zero(), |mut b, e| {b |= &e.receipt.log_bloom; b});
s.block.header.gas_used = s.block.archive.last().map(|t| t.receipt.gas_used).unwrap_or(U256::from(0));
s.block.header.note_dirty();
ClosedBlock::new(s, uncle_bytes)
}
}
impl<'x, 'y> IsBlock for OpenBlock<'x, 'y> {
fn block(&self) -> &Block { &self.block }
}
impl<'x, 'y> IsBlock for ClosedBlock<'x, 'y> {
fn block(&self) -> &Block { &self.open_block.block }
}
impl<'x, 'y> ClosedBlock<'x, 'y> {
fn new<'a, 'b>(open_block: OpenBlock<'a, 'b>, uncle_bytes: Bytes) -> ClosedBlock<'a, 'b> {
ClosedBlock {
open_block: open_block,
uncle_bytes: uncle_bytes,
}
}
/// Get the hash of the header without seal arguments.
pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) }
/// Provide a valid seal in order to turn this into a `SealedBlock`.
///
/// NOTE: This does not check the validity of `seal` with the engine.
pub fn seal(self, seal: Vec<Bytes>) -> Result<SealedBlock, BlockError> {
let mut s = self;
if seal.len() != s.open_block.engine.seal_fields() {
return Err(BlockError::InvalidSealArity(Mismatch{expected: s.open_block.engine.seal_fields(), found: seal.len()}));
}
s.open_block.block.header.set_seal(seal);
Ok(SealedBlock { block: s.open_block.block, uncle_bytes: s.uncle_bytes })
}
/// Turn this back into an `OpenBlock`.
pub fn reopen(self) -> OpenBlock<'x, 'y> { self.open_block }
/// Drop this object and return the underlieing database.
pub fn drain(self) -> OverlayDB { self.open_block.block.state.drop().1 }
}
impl SealedBlock {
/// Get the RLP-encoding of the block.
pub fn rlp_bytes(&self) -> Bytes {
let mut block_rlp = RlpStream::new_list(3);
self.block.header.stream_rlp(&mut block_rlp, Seal::With);
block_rlp.append_list(self.block.archive.len());
for e in self.block.archive.iter() { e.transaction.rlp_append(&mut block_rlp); }
block_rlp.append_raw(&self.uncle_bytes, 1);
block_rlp.out()
}
/// Drop this object and return the underlieing database.
pub fn drain(self) -> OverlayDB { self.block.state.drop().1 }
}
impl IsBlock for SealedBlock {
fn block(&self) -> &Block { &self.block }
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
pub fn enact<'x, 'y>(block_bytes: &[u8], engine: &'x Engine, db: OverlayDB, parent: &Header, last_hashes: &'y LastHashes) -> Result<ClosedBlock<'x, 'y>, Error> {
{
let header = BlockView::new(block_bytes).header_view();
let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce());
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
}
let block = BlockView::new(block_bytes);
let header = block.header_view();
let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author(), header.extra_data());
b.set_difficulty(header.difficulty());
b.set_gas_limit(header.gas_limit());
b.set_timestamp(header.timestamp());
// info!("enact: Enacting #{}. env_info={:?}", header.number(), b.env_info());
for t in block.transactions().into_iter() { try!(b.push_transaction(t, None)); }
for u in block.uncles().into_iter() { try!(b.push_uncle(u)); }
Ok(b.close())
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: OverlayDB, parent: &Header, last_hashes: &LastHashes) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view();
Ok(try!(try!(enact(block_bytes, engine, db, parent, last_hashes)).seal(header.seal())))
}
#[test]
fn open_block() {
use spec::*;
let engine = Spec::new_test().to_engine().unwrap();
let genesis_header = engine.spec().genesis_header();
let mut db = OverlayDB::new_temp();
engine.spec().ensure_db_good(&mut db);
let last_hashes = vec![genesis_header.hash()];
let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
let b = b.close();
let _ = b.seal(vec![]);
}
#[test]
fn enact_block() {
use spec::*;
let engine = Spec::new_test().to_engine().unwrap();
let genesis_header = engine.spec().genesis_header();
let mut db = OverlayDB::new_temp();
engine.spec().ensure_db_good(&mut db);
let b = OpenBlock::new(engine.deref(), db, &genesis_header, &vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
let mut db = OverlayDB::new_temp();
engine.spec().ensure_db_good(&mut db);
let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, &vec![genesis_header.hash()]).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
let db = e.drain();
assert_eq!(orig_db.keys(), db.keys());
assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None);
}

694
src/blockchain.rs Normal file
View File

@@ -0,0 +1,694 @@
//! Fast access to blockchain data.
use util::*;
use rocksdb::{DB, WriteBatch, Writable};
use header::*;
use extras::*;
use transaction::*;
use views::*;
/// Represents a tree route between `from` block and `to` block:
///
/// - `blocks` - a vector of hashes of all blocks, ordered from `from` to `to`.
///
/// - `ancestor` - best common ancestor of these blocks.
///
/// - `index` - an index where best common ancestor would be.
pub struct TreeRoute {
pub blocks: Vec<H256>,
pub ancestor: H256,
pub index: usize
}
/// Represents blockchain's in-memory cache size in bytes.
#[derive(Debug)]
pub struct CacheSize {
pub blocks: usize,
pub block_details: usize,
pub transaction_addresses: usize,
pub block_logs: usize,
pub blocks_blooms: usize
}
/// Information about best block gathered together
struct BestBlock {
pub hash: H256,
pub number: BlockNumber,
pub total_difficulty: U256
}
impl BestBlock {
fn new() -> BestBlock {
BestBlock {
hash: H256::new(),
number: 0,
total_difficulty: U256::from(0)
}
}
}
/// Interface for querying blocks by hash and by number.
pub trait BlockProvider {
/// Returns true if the given block is known
/// (though not necessarily a part of the canon chain).
fn is_known(&self, hash: &H256) -> bool;
/// Get raw block data
fn block(&self, hash: &H256) -> Option<Bytes>;
/// Get the familial details concerning a block.
fn block_details(&self, hash: &H256) -> Option<BlockDetails>;
/// Get the hash of given block's number.
fn block_hash(&self, index: BlockNumber) -> Option<H256>;
/// Get the partial-header of a block.
fn block_header(&self, hash: &H256) -> Option<Header> {
self.block(hash).map(|bytes| BlockView::new(&bytes).header())
}
/// Get a list of uncles for a given block.
/// Returns None if block deos not exist.
fn uncles(&self, hash: &H256) -> Option<Vec<Header>> {
self.block(hash).map(|bytes| BlockView::new(&bytes).uncles())
}
/// Get a list of uncle hashes for a given block.
/// Returns None if block does not exist.
fn uncle_hashes(&self, hash: &H256) -> Option<Vec<H256>> {
self.block(hash).map(|bytes| BlockView::new(&bytes).uncle_hashes())
}
/// Get the number of given block's hash.
fn block_number(&self, hash: &H256) -> Option<BlockNumber> {
self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number())
}
/// Get a list of transactions for a given block.
/// Returns None if block deos not exist.
fn transactions(&self, hash: &H256) -> Option<Vec<Transaction>> {
self.block(hash).map(|bytes| BlockView::new(&bytes).transactions())
}
/// Returns reference to genesis hash.
fn genesis_hash(&self) -> H256 {
self.block_hash(0).expect("Genesis hash should always exist")
}
}
/// Structure providing fast access to blockchain data.
///
/// **Does not do input data verification.**
pub struct BlockChain {
best_block: RwLock<BestBlock>,
// block cache
blocks: RwLock<HashMap<H256, Bytes>>,
// extra caches
block_details: RwLock<HashMap<H256, BlockDetails>>,
block_hashes: RwLock<HashMap<BlockNumber, H256>>,
transaction_addresses: RwLock<HashMap<H256, TransactionAddress>>,
block_logs: RwLock<HashMap<H256, BlockLogBlooms>>,
blocks_blooms: RwLock<HashMap<H256, BlocksBlooms>>,
extras_db: DB,
blocks_db: DB
}
impl BlockProvider for BlockChain {
/// Returns true if the given block is known
/// (though not necessarily a part of the canon chain).
fn is_known(&self, hash: &H256) -> bool {
self.query_extras_exist(hash, &self.block_details)
}
/// Get raw block data
fn block(&self, hash: &H256) -> Option<Bytes> {
{
let read = self.blocks.read().unwrap();
match read.get(hash) {
Some(v) => return Some(v.clone()),
None => ()
}
}
let opt = self.blocks_db.get(hash)
.expect("Low level database error. Some issue with disk?");
match opt {
Some(b) => {
let bytes: Bytes = b.to_vec();
let mut write = self.blocks.write().unwrap();
write.insert(hash.clone(), bytes.clone());
Some(bytes)
},
None => None
}
}
/// Get the familial details concerning a block.
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
self.query_extras(hash, &self.block_details)
}
/// Get the hash of given block's number.
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
self.query_extras(&index, &self.block_hashes)
}
}
impl BlockChain {
/// Create new instance of blockchain from given Genesis
///
/// ```rust
/// extern crate ethcore_util as util;
/// extern crate ethcore;
/// use std::env;
/// use std::str::FromStr;
/// use ethcore::spec::*;
/// use ethcore::blockchain::*;
/// use ethcore::ethereum;
/// use util::hash::*;
/// use util::uint::*;
///
/// fn main() {
/// let spec = ethereum::new_frontier();
///
/// let mut dir = env::temp_dir();
/// dir.push(H32::random().hex());
///
/// let bc = BlockChain::new(&spec.genesis_block(), &dir);
///
/// let genesis_hash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3";
/// assert_eq!(bc.genesis_hash(), H256::from_str(genesis_hash).unwrap());
/// assert!(bc.is_known(&bc.genesis_hash()));
/// assert_eq!(bc.genesis_hash(), bc.block_hash(0).unwrap());
/// }
/// ```
pub fn new(genesis: &[u8], path: &Path) -> BlockChain {
// open extras db
let mut extras_path = path.to_path_buf();
extras_path.push("extras");
let extras_db = DB::open_default(extras_path.to_str().unwrap()).unwrap();
// open blocks db
let mut blocks_path = path.to_path_buf();
blocks_path.push("blocks");
let blocks_db = DB::open_default(blocks_path.to_str().unwrap()).unwrap();
let bc = BlockChain {
best_block: RwLock::new(BestBlock::new()),
blocks: RwLock::new(HashMap::new()),
block_details: RwLock::new(HashMap::new()),
block_hashes: RwLock::new(HashMap::new()),
transaction_addresses: RwLock::new(HashMap::new()),
block_logs: RwLock::new(HashMap::new()),
blocks_blooms: RwLock::new(HashMap::new()),
extras_db: extras_db,
blocks_db: blocks_db
};
// load best block
let best_block_hash = match bc.extras_db.get(b"best").unwrap() {
Some(best) => H256::from_slice(&best),
None => {
// best block does not exist
// we need to insert genesis into the cache
let block = BlockView::new(genesis);
let header = block.header_view();
let hash = block.sha3();
let details = BlockDetails {
number: header.number(),
total_difficulty: header.difficulty(),
parent: header.parent_hash(),
children: vec![]
};
bc.blocks_db.put(&hash, genesis).unwrap();
let batch = WriteBatch::new();
batch.put_extras(&hash, &details);
batch.put_extras(&header.number(), &hash);
batch.put(b"best", &hash).unwrap();
bc.extras_db.write(batch).unwrap();
hash
}
};
{
let mut best_block = bc.best_block.write().unwrap();
best_block.number = bc.block_number(&best_block_hash).unwrap();
best_block.total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
best_block.hash = best_block_hash;
}
bc
}
/// Ensure that the best block does indeed have a state_root in the state DB.
/// If it doesn't, then rewind down until we find one that does and delete data to ensure that
/// later blocks will be reimported.
pub fn ensure_good(&mut self, _state: &OverlayDB) {
unimplemented!();
}
/// Returns a tree route between `from` and `to`, which is a tuple of:
///
/// - a vector of hashes of all blocks, ordered from `from` to `to`.
///
/// - common ancestor of these blocks.
///
/// - an index where best common ancestor would be
///
/// 1.) from newer to older
///
/// - bc: `A1 -> A2 -> A3 -> A4 -> A5`
/// - from: A5, to: A4
/// - route:
///
/// ```json
/// { blocks: [A5], ancestor: A4, index: 1 }
/// ```
///
/// 2.) from older to newer
///
/// - bc: `A1 -> A2 -> A3 -> A4 -> A5`
/// - from: A3, to: A4
/// - route:
///
/// ```json
/// { blocks: [A4], ancestor: A3, index: 0 }
/// ```
///
/// 3.) fork:
///
/// - bc:
///
/// ```text
/// A1 -> A2 -> A3 -> A4
/// -> B3 -> B4
/// ```
/// - from: B4, to: A4
/// - route:
///
/// ```json
/// { blocks: [B4, B3, A3, A4], ancestor: A2, index: 2 }
/// ```
pub fn tree_route(&self, from: H256, to: H256) -> Option<TreeRoute> {
let from_details = match self.block_details(&from) {
Some(h) => h,
None => return None,
};
let to_details = match self.block_details(&to) {
Some(h) => h,
None => return None,
};
Some(self._tree_route((from_details, from), (to_details, to)))
}
/// Similar to `tree_route` function, but can be used to return a route
/// between blocks which may not be in database yet.
fn _tree_route(&self, from: (BlockDetails, H256), to: (BlockDetails, H256)) -> TreeRoute {
let mut from_branch = vec![];
let mut to_branch = vec![];
let mut from_details = from.0;
let mut to_details = to.0;
let mut current_from = from.1;
let mut current_to = to.1;
// reset from && to to the same level
while from_details.number > to_details.number {
from_branch.push(current_from);
current_from = from_details.parent.clone();
from_details = self.block_details(&from_details.parent).unwrap();
}
while to_details.number > from_details.number {
to_branch.push(current_to);
current_to = to_details.parent.clone();
to_details = self.block_details(&to_details.parent).unwrap();
}
assert_eq!(from_details.number, to_details.number);
// move to shared parent
while current_from != current_to {
from_branch.push(current_from);
current_from = from_details.parent.clone();
from_details = self.block_details(&from_details.parent).unwrap();
to_branch.push(current_to);
current_to = to_details.parent.clone();
to_details = self.block_details(&to_details.parent).unwrap();
}
let index = from_branch.len();
from_branch.extend(to_branch.into_iter().rev());
TreeRoute {
blocks: from_branch,
ancestor: current_from,
index: index
}
}
/// Inserts the block into backing cache database.
/// Expects the block to be valid and already verified.
/// If the block is already known, does nothing.
pub fn insert_block(&self, bytes: &[u8]) {
// create views onto rlp
let block = BlockView::new(bytes);
let header = block.header_view();
let hash = header.sha3();
if self.is_known(&hash) {
return;
}
// store block in db
self.blocks_db.put(&hash, &bytes).unwrap();
let (batch, new_best) = self.block_to_extras_insert_batch(bytes);
// update best block
let mut best_block = self.best_block.write().unwrap();
if let Some(b) = new_best {
*best_block = b;
}
// update caches
let mut write = self.block_details.write().unwrap();
write.remove(&header.parent_hash());
// update extras database
self.extras_db.write(batch).unwrap();
}
/// Transforms block into WriteBatch that may be written into database
/// Additionally, if it's new best block it returns new best block object.
fn block_to_extras_insert_batch(&self, bytes: &[u8]) -> (WriteBatch, Option<BestBlock>) {
// create views onto rlp
let block = BlockView::new(bytes);
let header = block.header_view();
// prepare variables
let hash = block.sha3();
let mut parent_details = self.block_details(&header.parent_hash()).expect("Invalid parent hash.");
let total_difficulty = parent_details.total_difficulty + header.difficulty();
let is_new_best = total_difficulty > self.best_block_total_difficulty();
let parent_hash = header.parent_hash();
// create current block details
let details = BlockDetails {
number: header.number(),
total_difficulty: total_difficulty,
parent: parent_hash.clone(),
children: vec![]
};
// prepare the batch
let batch = WriteBatch::new();
// insert new block details
batch.put_extras(&hash, &details);
// update parent details
parent_details.children.push(hash.clone());
batch.put_extras(&parent_hash, &parent_details);
// if it's not new best block, just return
if !is_new_best {
return (batch, None);
}
// if its new best block we need to make sure that all ancestors
// are moved to "canon chain"
// find the route between old best block and the new one
let best_hash = self.best_block_hash();
let best_details = self.block_details(&best_hash).expect("best block hash is invalid!");
let route = self._tree_route((best_details, best_hash), (details, hash.clone()));
match route.blocks.len() {
// its our parent
1 => batch.put_extras(&header.number(), &hash),
// it is a fork
i if i > 1 => {
let ancestor_number = self.block_number(&route.ancestor).unwrap();
let start_number = ancestor_number + 1;
for (index, hash) in route.blocks.iter().skip(route.index).enumerate() {
batch.put_extras(&(start_number + index as BlockNumber), hash);
}
},
// route.blocks.len() could be 0 only if inserted block is best block,
// and this is not possible at this stage
_ => { unreachable!(); }
};
// this is new best block
batch.put(b"best", &hash).unwrap();
let best_block = BestBlock {
hash: hash,
number: header.number(),
total_difficulty: total_difficulty
};
(batch, Some(best_block))
}
/// Returns true if transaction is known.
pub fn is_known_transaction(&self, hash: &H256) -> bool {
self.query_extras_exist(hash, &self.transaction_addresses)
}
/// Get best block hash.
pub fn best_block_hash(&self) -> H256 {
self.best_block.read().unwrap().hash.clone()
}
/// Get best block number.
pub fn best_block_number(&self) -> BlockNumber {
self.best_block.read().unwrap().number
}
/// Get best block total difficulty.
pub fn best_block_total_difficulty(&self) -> U256 {
self.best_block.read().unwrap().total_difficulty
}
/// Get the transactions' log blooms of a block.
pub fn log_blooms(&self, hash: &H256) -> Option<BlockLogBlooms> {
self.query_extras(hash, &self.block_logs)
}
fn query_extras<K, T>(&self, hash: &K, cache: &RwLock<HashMap<K, T>>) -> Option<T> where
T: Clone + Decodable + ExtrasIndexable,
K: ExtrasSliceConvertable + Eq + Hash + Clone {
{
let read = cache.read().unwrap();
match read.get(hash) {
Some(v) => return Some(v.clone()),
None => ()
}
}
self.extras_db.get_extras(hash).map(| t: T | {
let mut write = cache.write().unwrap();
write.insert(hash.clone(), t.clone());
t
})
}
fn query_extras_exist<K, T>(&self, hash: &K, cache: &RwLock<HashMap<K, T>>) -> bool where
K: ExtrasSliceConvertable + Eq + Hash + Clone,
T: ExtrasIndexable {
{
let read = cache.read().unwrap();
match read.get(hash) {
Some(_) => return true,
None => ()
}
}
self.extras_db.extras_exists::<_, T>(hash)
}
/// Get current cache size.
pub fn cache_size(&self) -> CacheSize {
CacheSize {
blocks: self.blocks.read().unwrap().heap_size_of_children(),
block_details: self.block_details.read().unwrap().heap_size_of_children(),
transaction_addresses: self.transaction_addresses.read().unwrap().heap_size_of_children(),
block_logs: self.block_logs.read().unwrap().heap_size_of_children(),
blocks_blooms: self.blocks_blooms.read().unwrap().heap_size_of_children()
}
}
/// Tries to squeeze the cache if its too big.
pub fn squeeze_to_fit(&self, size: CacheSize) {
self.blocks.write().unwrap().squeeze(size.blocks);
self.block_details.write().unwrap().squeeze(size.block_details);
self.transaction_addresses.write().unwrap().squeeze(size.transaction_addresses);
self.block_logs.write().unwrap().squeeze(size.block_logs);
self.blocks_blooms.write().unwrap().squeeze(size.blocks_blooms);
}
}
#[cfg(test)]
mod tests {
use std::env;
use std::str::FromStr;
use rustc_serialize::hex::FromHex;
use util::hash::*;
use blockchain::*;
#[test]
fn valid_tests_extra32() {
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0363659b251bf8b819179874c8cce7b9b983d7f3704cbb58a3b334431f7032871889032d09c281e1236c0c0".from_hex().unwrap();
let mut dir = env::temp_dir();
dir.push(H32::random().hex());
let bc = BlockChain::new(&genesis, &dir);
let genesis_hash = H256::from_str("3caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942").unwrap();
assert_eq!(bc.genesis_hash(), genesis_hash.clone());
assert_eq!(bc.best_block_number(), 0);
assert_eq!(bc.best_block_hash(), genesis_hash.clone());
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
assert_eq!(bc.block_hash(1), None);
let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap();
bc.insert_block(&first);
let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap();
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
assert_eq!(bc.best_block_number(), 1);
assert_eq!(bc.best_block_hash(), first_hash.clone());
assert_eq!(bc.block_hash(1), Some(first_hash.clone()));
assert_eq!(bc.block_details(&first_hash).unwrap().parent, genesis_hash.clone());
assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![first_hash.clone()]);
assert_eq!(bc.block_hash(2), None);
}
#[test]
fn test_small_fork() {
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap();
let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap();
let b2 = "f902ccf901f9a0437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
let b3a = "f90261f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a09dc4b1357c0b7b8108f8a098f4f9a1a274957bc9ebc22a9ae67ae81739e5b19ca007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882524d84562791eb80a074861666bd346c025889745c793b91ab9cd1e2ca19b5cf3c50d04d135b0a4d2b8809fe9587ea4cdc04f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba06fd84874d36d5de9e8e48978c03619b53a96b7ae0a4cd1ac118f103098b44801a00572596974dd7df4f9f69bd7456585618c568d8434ef6453391b89281ce12ae1c0".from_hex().unwrap();
let b3b = "f90265f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ab87dc338bfd6f662b1cd90bc0c9e40a1b2146a095312393c9e13ce3a5008b09a0e609b7a7d4b8a2403ec1268627ecd98783627246e8f1b26addb3ff504f76a054a0592fabf92476512952db3a69a2481a42912e668a1ee28c4c322e703bb665f8beb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882a1f084562791ee80a0fe7098fa7e4ac5d637eea81fb23f8f78346826dbab430068dd9a249d0afa99818853e1a6b201ae3545f866f86402018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d0284c04062261ca06edc9ce8e7da4cc34067beb325dcad59e5655a164a5100a50bc3eb681b12c716a0abf9053d5de65b1be81fe50d327b84de685efbeecea34e7b747180a6c6023e44c0".from_hex().unwrap();
let genesis_hash = H256::from_str("5716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2").unwrap();
let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").unwrap();
let b2_hash = H256::from_str("36fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781a").unwrap();
let b3a_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap();
let b3b_hash = H256::from_str("bf72270ae0d95c9ea39a6adab994793fddb8c10fba7391e26279474124605d54").unwrap();
// b3a is a part of canon chain, whereas b3b is part of sidechain
let best_block_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap();
let mut dir = env::temp_dir();
dir.push(H32::random().hex());
let bc = BlockChain::new(&genesis, &dir);
bc.insert_block(&b1);
bc.insert_block(&b2);
bc.insert_block(&b3a);
bc.insert_block(&b3b);
assert_eq!(bc.best_block_hash(), best_block_hash);
assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0);
assert_eq!(bc.block_number(&b1_hash).unwrap(), 1);
assert_eq!(bc.block_number(&b2_hash).unwrap(), 2);
assert_eq!(bc.block_number(&b3a_hash).unwrap(), 3);
assert_eq!(bc.block_number(&b3b_hash).unwrap(), 3);
assert_eq!(bc.block_hash(0).unwrap(), genesis_hash);
assert_eq!(bc.block_hash(1).unwrap(), b1_hash);
assert_eq!(bc.block_hash(2).unwrap(), b2_hash);
assert_eq!(bc.block_hash(3).unwrap(), b3a_hash);
// test trie route
let r0_1 = bc.tree_route(genesis_hash.clone(), b1_hash.clone()).unwrap();
assert_eq!(r0_1.ancestor, genesis_hash);
assert_eq!(r0_1.blocks, [b1_hash.clone()]);
assert_eq!(r0_1.index, 0);
let r0_2 = bc.tree_route(genesis_hash.clone(), b2_hash.clone()).unwrap();
assert_eq!(r0_2.ancestor, genesis_hash);
assert_eq!(r0_2.blocks, [b1_hash.clone(), b2_hash.clone()]);
assert_eq!(r0_2.index, 0);
let r1_3a = bc.tree_route(b1_hash.clone(), b3a_hash.clone()).unwrap();
assert_eq!(r1_3a.ancestor, b1_hash);
assert_eq!(r1_3a.blocks, [b2_hash.clone(), b3a_hash.clone()]);
assert_eq!(r1_3a.index, 0);
let r1_3b = bc.tree_route(b1_hash.clone(), b3b_hash.clone()).unwrap();
assert_eq!(r1_3b.ancestor, b1_hash);
assert_eq!(r1_3b.blocks, [b2_hash.clone(), b3b_hash.clone()]);
assert_eq!(r1_3b.index, 0);
let r3a_3b = bc.tree_route(b3a_hash.clone(), b3b_hash.clone()).unwrap();
assert_eq!(r3a_3b.ancestor, b2_hash);
assert_eq!(r3a_3b.blocks, [b3a_hash.clone(), b3b_hash.clone()]);
assert_eq!(r3a_3b.index, 1);
let r1_0 = bc.tree_route(b1_hash.clone(), genesis_hash.clone()).unwrap();
assert_eq!(r1_0.ancestor, genesis_hash);
assert_eq!(r1_0.blocks, [b1_hash.clone()]);
assert_eq!(r1_0.index, 1);
let r2_0 = bc.tree_route(b2_hash.clone(), genesis_hash.clone()).unwrap();
assert_eq!(r2_0.ancestor, genesis_hash);
assert_eq!(r2_0.blocks, [b2_hash.clone(), b1_hash.clone()]);
assert_eq!(r2_0.index, 2);
let r3a_1 = bc.tree_route(b3a_hash.clone(), b1_hash.clone()).unwrap();
assert_eq!(r3a_1.ancestor, b1_hash);
assert_eq!(r3a_1.blocks, [b3a_hash.clone(), b2_hash.clone()]);
assert_eq!(r3a_1.index, 2);
let r3b_1 = bc.tree_route(b3b_hash.clone(), b1_hash.clone()).unwrap();
assert_eq!(r3b_1.ancestor, b1_hash);
assert_eq!(r3b_1.blocks, [b3b_hash.clone(), b2_hash.clone()]);
assert_eq!(r3b_1.index, 2);
let r3b_3a = bc.tree_route(b3b_hash.clone(), b3a_hash.clone()).unwrap();
assert_eq!(r3b_3a.ancestor, b2_hash);
assert_eq!(r3b_3a.blocks, [b3b_hash.clone(), b3a_hash.clone()]);
assert_eq!(r3b_3a.index, 1);
}
#[test]
fn test_reopen_blockchain_db() {
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap();
let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap();
let genesis_hash = H256::from_str("5716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2").unwrap();
let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").unwrap();
let mut dir = env::temp_dir();
dir.push(H32::random().hex());
{
let bc = BlockChain::new(&genesis, &dir);
assert_eq!(bc.best_block_hash(), genesis_hash);
bc.insert_block(&b1);
assert_eq!(bc.best_block_hash(), b1_hash);
}
{
let bc = BlockChain::new(&genesis, &dir);
assert_eq!(bc.best_block_hash(), b1_hash);
}
}
}

274
src/builtin.rs Normal file
View File

@@ -0,0 +1,274 @@
use util::*;
use crypto::sha2::Sha256;
use crypto::ripemd160::Ripemd160;
use crypto::digest::Digest;
/// Definition of a contract whose implementation is built-in.
pub struct Builtin {
/// The gas cost of running this built-in for the given size of input data.
pub cost: Box<Fn(usize) -> U256>, // TODO: U256 should be bignum.
/// Run this built-in function with the input being the first argument and the output
/// being placed into the second.
pub execute: Box<Fn(&[u8], &mut [u8])>,
}
// Rust does not mark closurer that do not capture as Sync
// We promise that all builtins are thread safe since they only operate on given input.
unsafe impl Sync for Builtin {}
unsafe impl Send for Builtin {}
impl fmt::Debug for Builtin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Builtin>")
}
}
impl Builtin {
/// Create a new object from components.
pub fn new(cost: Box<Fn(usize) -> U256>, execute: Box<Fn(&[u8], &mut [u8])>) -> Builtin {
Builtin {cost: cost, execute: execute}
}
/// Create a new object from a builtin-function name with a linear cost associated with input size.
pub fn from_named_linear(name: &str, base_cost: usize, word_cost: usize) -> Option<Builtin> {
new_builtin_exec(name).map(|b| {
let cost = Box::new(move|s: usize| -> U256 {
U256::from(base_cost) + U256::from(word_cost) * U256::from((s + 31) / 32)
});
Self::new(cost, b)
})
}
/// Simple forwarder for cost.
pub fn cost(&self, s: usize) -> U256 { (*self.cost)(s) }
/// Simple forwarder for execute.
pub fn execute(&self, input: &[u8], output: &mut[u8]) { (*self.execute)(input, output); }
/// Create a builtin from JSON.
///
/// JSON must be of the form `{ "name": "identity", "linear": {"base": 10, "word": 20} }`.
pub fn from_json(json: &Json) -> Option<Builtin> {
// NICE: figure out a more convenient means of handing errors here.
if let Json::String(ref name) = json["name"] {
if let Json::Object(ref o) = json["linear"] {
if let Json::U64(ref word) = o["word"] {
if let Json::U64(ref base) = o["base"] {
return Self::from_named_linear(&name[..], *base as usize, *word as usize);
}
}
}
}
None
}
}
pub fn copy_to(src: &[u8], dest: &mut[u8]) {
// NICE: optimise
for i in 0..min(src.len(), dest.len()) {
dest[i] = src[i];
}
}
/// Create a new builtin executor according to `name`.
/// TODO: turn in to a factory with dynamic registration.
pub fn new_builtin_exec(name: &str) -> Option<Box<Fn(&[u8], &mut [u8])>> {
match name {
"identity" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
for i in 0..min(input.len(), output.len()) {
output[i] = input[i];
}
})),
"ecrecover" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
#[repr(packed)]
#[derive(Debug)]
struct InType {
hash: H256,
v: H256,
r: H256,
s: H256,
}
let mut it: InType = InType { hash: H256::new(), v: H256::new(), r: H256::new(), s: H256::new() };
it.copy_raw(input);
if it.v == H256::from(&U256::from(27)) || it.v == H256::from(&U256::from(28)) {
let s = Signature::from_rsv(&it.r, &it.s, it.v[31] - 27);
if ec::is_valid(&s) {
match ec::recover(&s, &it.hash) {
Ok(p) => {
let r = p.as_slice().sha3();
// NICE: optimise and separate out into populate-like function
for i in 0..min(32, output.len()) {
output[i] = if i < 12 {0} else {r[i]};
}
}
_ => {}
};
}
}
})),
"sha256" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
let mut sha = Sha256::new();
sha.input(input);
if output.len() >= 32 {
sha.result(output);
} else {
let mut ret = H256::new();
sha.result(ret.as_slice_mut());
copy_to(&ret, output);
}
})),
"ripemd160" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
let mut sha = Ripemd160::new();
sha.input(input);
let mut ret = H256::new();
sha.result(&mut ret.as_slice_mut()[12..32]);
copy_to(&ret, output);
})),
_ => None
}
}
#[test]
fn identity() {
let f = new_builtin_exec("identity").unwrap();
let i = [0u8, 1, 2, 3];
let mut o2 = [255u8; 2];
f(&i[..], &mut o2[..]);
assert_eq!(i[0..2], o2);
let mut o4 = [255u8; 4];
f(&i[..], &mut o4[..]);
assert_eq!(i, o4);
let mut o8 = [255u8; 8];
f(&i[..], &mut o8[..]);
assert_eq!(i, o8[..4]);
assert_eq!([255u8; 4], o8[4..]);
}
#[test]
fn sha256() {
use rustc_serialize::hex::FromHex;
let f = new_builtin_exec("sha256").unwrap();
let i = [0u8; 0];
let mut o = [255u8; 32];
f(&i[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").unwrap())[..]);
let mut o8 = [255u8; 8];
f(&i[..], &mut o8[..]);
assert_eq!(&o8[..], &(FromHex::from_hex("e3b0c44298fc1c14").unwrap())[..]);
let mut o34 = [255u8; 34];
f(&i[..], &mut o34[..]);
assert_eq!(&o34[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff").unwrap())[..]);
}
#[test]
fn ripemd160() {
use rustc_serialize::hex::FromHex;
let f = new_builtin_exec("ripemd160").unwrap();
let i = [0u8; 0];
let mut o = [255u8; 32];
f(&i[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31").unwrap())[..]);
let mut o8 = [255u8; 8];
f(&i[..], &mut o8[..]);
assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
let mut o34 = [255u8; 34];
f(&i[..], &mut o34[..]);
assert_eq!(&o34[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff").unwrap())[..]);
}
#[test]
fn ecrecover() {
use rustc_serialize::hex::FromHex;
/*let k = KeyPair::from_secret(b"test".sha3()).unwrap();
let a: Address = From::from(k.public().sha3());
println!("Address: {}", a);
let m = b"hello world".sha3();
println!("Message: {}", m);
let s = k.sign(&m).unwrap();
println!("Signed: {}", s);*/
let f = new_builtin_exec("ecrecover").unwrap();
let i = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
let mut o = [255u8; 32];
f(&i[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb").unwrap())[..]);
let mut o8 = [255u8; 8];
f(&i[..], &mut o8[..]);
assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
let mut o34 = [255u8; 34];
f(&i[..], &mut o34[..]);
assert_eq!(&o34[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddbffff").unwrap())[..]);
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001a650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001b").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
// TODO: Should this (corrupted version of the above) fail rather than returning some address?
/* let i_bad = FromHex::from_hex("48173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);*/
}
#[test]
fn from_named_linear() {
let b = Builtin::from_named_linear("identity", 10, 20).unwrap();
assert_eq!((*b.cost)(0), U256::from(10));
assert_eq!((*b.cost)(1), U256::from(30));
assert_eq!((*b.cost)(32), U256::from(30));
assert_eq!((*b.cost)(33), U256::from(50));
let i = [0u8, 1, 2, 3];
let mut o = [255u8; 4];
(*b.execute)(&i[..], &mut o[..]);
assert_eq!(i, o);
}
#[test]
fn from_json() {
let text = "{ \"name\": \"identity\", \"linear\": {\"base\": 10, \"word\": 20} }";
let json = Json::from_str(text).unwrap();
let b = Builtin::from_json(&json).unwrap();
assert_eq!((*b.cost)(0), U256::from(10));
assert_eq!((*b.cost)(1), U256::from(30));
assert_eq!((*b.cost)(32), U256::from(30));
assert_eq!((*b.cost)(33), U256::from(50));
let i = [0u8, 1, 2, 3];
let mut o = [255u8; 4];
(*b.execute)(&i[..], &mut o[..]);
assert_eq!(i, o);
}

View File

@@ -1,465 +0,0 @@
//! Unified interfaces for bytes operations on basic types
//!
//! # Examples
//! ```rust
//! extern crate ethcore_util as util;
//!
//! fn bytes_convertable() {
//! use util::bytes::BytesConvertable;
//!
//! let arr = [0; 5];
//! let slice: &[u8] = arr.bytes();
//! }
//!
//! fn to_bytes() {
//! use util::bytes::ToBytes;
//!
//! let a: Vec<u8> = "hello_world".to_bytes();
//! let b: Vec<u8> = 400u32.to_bytes();
//! let c: Vec<u8> = 0xffffffffffffffffu64.to_bytes();
//! }
//!
//! fn from_bytes() {
//! use util::bytes::FromBytes;
//!
//! let a = String::from_bytes(&[b'd', b'o', b'g']);
//! let b = u16::from_bytes(&[0xfa]);
//! let c = u64::from_bytes(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
//! }
//!
//! fn main() {
//! bytes_convertable();
//! to_bytes();
//! from_bytes();
//! }
//! ```
use std::mem;
use std::fmt;
use std::slice;
use std::cmp::Ordering;
use std::error::Error as StdError;
use std::ops::{Deref, DerefMut};
use uint::{Uint, U128, U256};
use hash::FixedHash;
pub struct PrettySlice<'a> (&'a [u8]);
impl<'a> fmt::Debug for PrettySlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.0.len() {
match i > 0 {
true => { try!(write!(f, "·{:02x}", self.0[i])); },
false => { try!(write!(f, "{:02x}", self.0[i])); },
}
}
Ok(())
}
}
impl<'a> fmt::Display for PrettySlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.0.len() {
try!(write!(f, "{:02x}", self.0[i]));
}
Ok(())
}
}
pub trait ToPretty {
fn pretty(&self) -> PrettySlice;
fn to_hex(&self) -> String {
format!("{}", self.pretty())
}
}
impl<'a> ToPretty for &'a [u8] {
fn pretty(&self) -> PrettySlice {
PrettySlice(self)
}
}
impl<'a> ToPretty for &'a Bytes {
fn pretty(&self) -> PrettySlice {
PrettySlice(self.bytes())
}
}
impl ToPretty for Bytes {
fn pretty(&self) -> PrettySlice {
PrettySlice(self.bytes())
}
}
pub enum BytesRef<'a> {
Flexible(&'a mut Bytes),
Fixed(&'a mut [u8])
}
impl<'a> Deref for BytesRef<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] {
match self {
&BytesRef::Flexible(ref bytes) => bytes,
&BytesRef::Fixed(ref bytes) => bytes
}
}
}
impl <'a> DerefMut for BytesRef<'a> {
fn deref_mut(&mut self) -> &mut [u8] {
match self {
&mut BytesRef::Flexible(ref mut bytes) => bytes,
&mut BytesRef::Fixed(ref mut bytes) => bytes
}
}
}
/// Vector of bytes
pub type Bytes = Vec<u8>;
/// Slice of bytes to underlying memory
pub trait BytesConvertable {
// TODO: rename to as_slice
fn bytes(&self) -> &[u8];
fn as_slice(&self) -> &[u8] { self.bytes() }
fn to_bytes(&self) -> Bytes { self.as_slice().to_vec() }
}
impl<'a> BytesConvertable for &'a [u8] {
fn bytes(&self) -> &[u8] { self }
}
impl BytesConvertable for Vec<u8> {
fn bytes(&self) -> &[u8] { self }
}
macro_rules! impl_bytes_convertable_for_array {
($zero: expr) => ();
($len: expr, $($idx: expr),*) => {
impl BytesConvertable for [u8; $len] {
fn bytes(&self) -> &[u8] { self }
}
impl_bytes_convertable_for_array! { $($idx),* }
}
}
// -1 at the end is not expanded
impl_bytes_convertable_for_array! {
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1
}
#[test]
fn bytes_convertable() {
assert_eq!(vec![0x12u8, 0x34].bytes(), &[0x12u8, 0x34]);
assert_eq!([0u8; 0].bytes(), &[]);
}
/// Converts given type to its shortest representation in bytes
///
/// TODO: optimise some conversations
pub trait ToBytes {
fn to_bytes(&self) -> Vec<u8>;
fn to_bytes_len(&self) -> usize { self.to_bytes().len() }
fn first_byte(&self) -> Option<u8> { self.to_bytes().first().map(|&x| { x })}
}
impl <'a> ToBytes for &'a str {
fn to_bytes(&self) -> Vec<u8> {
From::from(*self)
}
fn to_bytes_len(&self) -> usize { self.len() }
}
impl ToBytes for String {
fn to_bytes(&self) -> Vec<u8> {
let s: &str = self.as_ref();
From::from(s)
}
fn to_bytes_len(&self) -> usize { self.len() }
}
impl ToBytes for u64 {
fn to_bytes(&self) -> Vec<u8> {
let mut res= vec![];
let count = self.to_bytes_len();
res.reserve(count);
for i in 0..count {
let j = count - 1 - i;
res.push((*self >> (j * 8)) as u8);
}
res
}
fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 }
}
impl ToBytes for bool {
fn to_bytes(&self) -> Vec<u8> {
vec![ if *self { 1u8 } else { 0u8 } ]
}
fn to_bytes_len(&self) -> usize { 1 }
}
macro_rules! impl_map_to_bytes {
($from: ident, $to: ty) => {
impl ToBytes for $from {
fn to_bytes(&self) -> Vec<u8> { (*self as $to).to_bytes() }
fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() }
}
}
}
impl_map_to_bytes!(usize, u64);
impl_map_to_bytes!(u16, u64);
impl_map_to_bytes!(u32, u64);
macro_rules! impl_uint_to_bytes {
($name: ident) => {
impl ToBytes for $name {
fn to_bytes(&self) -> Vec<u8> {
let mut res= vec![];
let count = self.to_bytes_len();
res.reserve(count);
for i in 0..count {
let j = count - 1 - i;
res.push(self.byte(j));
}
res
}
fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 }
}
}
}
impl_uint_to_bytes!(U256);
impl_uint_to_bytes!(U128);
impl <T>ToBytes for T where T: FixedHash {
fn to_bytes(&self) -> Vec<u8> {
let mut res: Vec<u8> = vec![];
res.reserve(T::size());
unsafe {
use std::ptr;
ptr::copy(self.bytes().as_ptr(), res.as_mut_ptr(), T::size());
res.set_len(T::size());
}
res
}
}
/// Error returned when FromBytes conversation goes wrong
#[derive(Debug, PartialEq, Eq)]
pub enum FromBytesError {
DataIsTooShort,
DataIsTooLong
}
impl StdError for FromBytesError {
fn description(&self) -> &str { "from_bytes error" }
}
impl fmt::Display for FromBytesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self, f)
}
}
/// Alias for the result of FromBytes trait
pub type FromBytesResult<T> = Result<T, FromBytesError>;
/// Converts to given type from its bytes representation
///
/// TODO: check size of bytes before conversation and return appropriate error
pub trait FromBytes: Sized {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<Self>;
}
impl FromBytes for String {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<String> {
Ok(::std::str::from_utf8(bytes).unwrap().to_string())
}
}
macro_rules! impl_uint_from_bytes {
($to: ident) => {
impl FromBytes for $to {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<$to> {
match bytes.len() {
0 => Ok(0),
l if l <= mem::size_of::<$to>() => {
let mut res = 0 as $to;
for i in 0..l {
let shift = (l - 1 - i) * 8;
res = res + ((bytes[i] as $to) << shift);
}
Ok(res)
}
_ => Err(FromBytesError::DataIsTooLong)
}
}
}
}
}
impl FromBytes for bool {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<bool> {
match bytes.len() {
0 => Ok(false),
1 => Ok(bytes[0] != 0),
_ => Err(FromBytesError::DataIsTooLong),
}
}
}
//impl_uint_from_bytes!(u8);
impl_uint_from_bytes!(u16);
impl_uint_from_bytes!(u32);
impl_uint_from_bytes!(u64);
impl_uint_from_bytes!(usize);
macro_rules! impl_uint_from_bytes {
($name: ident) => {
impl FromBytes for $name {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> {
if bytes.len() <= $name::SIZE {
Ok($name::from(bytes))
} else {
Err(FromBytesError::DataIsTooLong)
}
}
}
}
}
impl_uint_from_bytes!(U256);
impl_uint_from_bytes!(U128);
impl <T>FromBytes for T where T: FixedHash {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<T> {
match bytes.len().cmp(&T::size()) {
Ordering::Less => return Err(FromBytesError::DataIsTooShort),
Ordering::Greater => return Err(FromBytesError::DataIsTooLong),
Ordering::Equal => ()
};
unsafe {
use std::{mem, ptr};
let mut res: T = mem::uninitialized();
ptr::copy(bytes.as_ptr(), res.as_slice_mut().as_mut_ptr(), T::size());
Ok(res)
}
}
}
/// Simple trait to allow for raw population of a Sized object from a byte slice.
pub trait Populatable {
/// Copies a bunch of bytes `d` to `self`, overwriting as necessary.
///
/// If `d` is smaller, zero-out the remaining bytes.
fn populate_raw(&mut self, d: &[u8]) {
let mut s = self.as_slice_mut();
for i in 0..s.len() {
s[i] = if i < d.len() {d[i]} else {0};
}
}
/// Copies a bunch of bytes `d` to `self`, overwriting as necessary.
///
/// If `d` is smaller, will leave some bytes untouched.
fn copy_raw(&mut self, d: &[u8]) {
use std::io::Write;
self.as_slice_mut().write(&d).unwrap();
}
/// Copies the raw representation of an object `d` to `self`, overwriting as necessary.
///
/// If `d` is smaller, zero-out the remaining bytes.
fn populate_raw_from(&mut self, d: &BytesConvertable) { self.populate_raw(d.as_slice()); }
/// Copies the raw representation of an object `d` to `self`, overwriting as necessary.
///
/// If `d` is smaller, will leave some bytes untouched.
fn copy_raw_from(&mut self, d: &BytesConvertable) { self.copy_raw(d.as_slice()); }
/// Get the raw slice for this object.
fn as_slice_mut(&mut self) -> &mut [u8];
}
impl<T> Populatable for T where T: Sized {
fn as_slice_mut(&mut self) -> &mut [u8] {
use std::mem;
unsafe {
slice::from_raw_parts_mut(self as *mut T as *mut u8, mem::size_of::<T>())
}
}
}
impl<T> Populatable for [T] where T: Sized {
fn as_slice_mut(&mut self) -> &mut [u8] {
use std::mem;
unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, mem::size_of::<T>() * self.len())
}
}
}
#[test]
fn fax_raw() {
let mut x = [255u8; 4];
x.copy_raw(&[1u8; 2][..]);
assert_eq!(x, [1u8, 1, 255, 255]);
let mut x = [255u8; 4];
x.copy_raw(&[1u8; 6][..]);
assert_eq!(x, [1u8, 1, 1, 1]);
}
#[test]
fn populate_raw() {
let mut x = [255u8; 4];
x.populate_raw(&[1u8; 2][..]);
assert_eq!(x, [1u8, 1, 0, 0]);
let mut x = [255u8; 4];
x.populate_raw(&[1u8; 6][..]);
assert_eq!(x, [1u8, 1, 1, 1]);
}
#[test]
fn populate_raw_dyn() {
let mut x = [255u8; 4];
x.populate_raw(&[1u8; 2][..]);
assert_eq!(&x[..], [1u8, 1, 0, 0]);
let mut x = [255u8; 4];
x.populate_raw(&[1u8; 6][..]);
assert_eq!(&x[..], [1u8, 1, 1, 1]);
}
#[test]
fn fax_raw_dyn() {
let mut x = [255u8; 4];
x.copy_raw(&[1u8; 2][..]);
assert_eq!(&x[..], [1u8, 1, 255, 255]);
let mut x = [255u8; 4];
x.copy_raw(&[1u8; 6][..]);
assert_eq!(&x[..], [1u8, 1, 1, 1]);
}
#[test]
fn populate_big_types() {
use hash::*;
let a = address_from_hex("ffffffffffffffffffffffffffffffffffffffff");
let mut h = h256_from_u64(0x69);
h.populate_raw_from(&a);
assert_eq!(h, h256_from_hex("ffffffffffffffffffffffffffffffffffffffff000000000000000000000000"));
let mut h = h256_from_u64(0x69);
h.copy_raw_from(&a);
assert_eq!(h, h256_from_hex("ffffffffffffffffffffffffffffffffffffffff000000000000000000000069"));
}

View File

@@ -1,452 +0,0 @@
//! Multilevel blockchain bloom filter.
//!
//! ```
//! extern crate ethcore_util as util;
//! use std::str::FromStr;
//! use util::chainfilter::*;
//! use util::sha3::*;
//! use util::hash::*;
//!
//! fn main() {
//! let (index_size, bloom_levels) = (16, 3);
//! let mut cache = MemoryCache::new();
//!
//! let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap();
//!
//! // borrow cache for reading inside the scope
//! let modified_blooms = {
//! let filter = ChainFilter::new(&cache, index_size, bloom_levels);
//! let block_number = 39;
//! let mut bloom = H2048::new();
//! bloom.shift_bloomed(&address.sha3());
//! filter.add_bloom(&bloom, block_number)
//! };
//!
//! // number of updated blooms is equal number of levels
//! assert_eq!(modified_blooms.len(), bloom_levels as usize);
//!
//! // lets inserts modified blooms into the cache
//! cache.insert_blooms(modified_blooms);
//!
//! // borrow cache for another reading operations
//! {
//! let filter = ChainFilter::new(&cache, index_size, bloom_levels);
//! let blocks = filter.blocks_with_address(&address, 10, 40);
//! assert_eq!(blocks.len(), 1);
//! assert_eq!(blocks[0], 39);
//! }
//! }
//! ```
//!
use std::collections::{HashMap};
use hash::*;
use sha3::*;
/// Represents bloom index in cache
///
/// On cache level 0, every block bloom is represented by different index.
/// On higher cache levels, multiple block blooms are represented by one
/// index. Their `BloomIndex` can be created from block number and given level.
#[derive(Eq, PartialEq, Hash, Clone, Debug)]
pub struct BloomIndex {
pub level: u8,
pub index: usize,
}
impl BloomIndex {
/// Default constructor for `BloomIndex`
pub fn new(level: u8, index: usize) -> BloomIndex {
BloomIndex {
level: level,
index: index,
}
}
}
/// Types implementing this trait should provide read access for bloom filters database.
pub trait FilterDataSource {
/// returns reference to log at given position if it exists
fn bloom_at_index(&self, index: &BloomIndex) -> Option<&H2048>;
}
/// In memory cache for blooms.
///
/// Stores all blooms in HashMap, which indexes them by `BloomIndex`.
pub struct MemoryCache {
blooms: HashMap<BloomIndex, H2048>,
}
impl MemoryCache {
/// Default constructor for MemoryCache
pub fn new() -> MemoryCache {
MemoryCache { blooms: HashMap::new() }
}
/// inserts all blooms into cache
///
/// if bloom at given index already exists, overwrites it
pub fn insert_blooms(&mut self, blooms: HashMap<BloomIndex, H2048>) {
self.blooms.extend(blooms);
}
}
impl FilterDataSource for MemoryCache {
fn bloom_at_index(&self, index: &BloomIndex) -> Option<&H2048> {
self.blooms.get(index)
}
}
/// Should be used for search operations on blockchain.
pub struct ChainFilter<'a, D>
where D: FilterDataSource + 'a
{
data_source: &'a D,
index_size: usize,
level_sizes: Vec<usize>,
}
impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource
{
/// Creates new filter instance.
///
/// Borrows `FilterDataSource` for reading.
pub fn new(data_source: &'a D, index_size: usize, levels: u8) -> Self {
if levels == 0 {
panic!("ChainFilter requires at least 1 level");
}
let mut filter = ChainFilter {
data_source: data_source,
index_size: index_size,
// 0 level has always a size of 1
level_sizes: vec![1]
};
// cache level sizes, so we do not have to calculate them all the time
// eg. if levels == 3, index_size = 16
// level_sizes = [1, 16, 256]
let additional: Vec<usize> = (1..).into_iter()
.scan(1, |acc, _| {
*acc = *acc * index_size;
Some(*acc)
})
.take(levels as usize - 1)
.collect();
filter.level_sizes.extend(additional);
filter
}
/// unsafely get level size
fn level_size(&self, level: u8) -> usize {
self.level_sizes[level as usize]
}
/// converts block number and level to `BloomIndex`
fn bloom_index(&self, block_number: usize, level: u8) -> BloomIndex {
BloomIndex {
level: level,
index: block_number / self.level_size(level),
}
}
/// return bloom which are dependencies for given index
///
/// bloom indexes are ordered from lowest to highest
fn lower_level_bloom_indexes(&self, index: &BloomIndex) -> Vec<BloomIndex> {
// this is the lowest level
if index.level == 0 {
return vec![];
}
let new_level = index.level - 1;
let offset = self.index_size * index.index;
(0..self.index_size).map(|i| BloomIndex::new(new_level, offset + i)).collect()
}
/// return number of levels
fn levels(&self) -> u8 {
self.level_sizes.len() as u8
}
/// returns max filter level
fn max_level(&self) -> u8 {
self.level_sizes.len() as u8 - 1
}
/// internal function which does bloom search recursively
fn blocks(&self, bloom: &H2048, from_block: usize, to_block: usize, level: u8, offset: usize) -> Option<Vec<usize>> {
let index = self.bloom_index(offset, level);
match self.data_source.bloom_at_index(&index) {
None => return None,
Some(level_bloom) => match level {
// if we are on the lowest level
// take the value, exclude to_block
0 if offset < to_block => return Some(vec![offset]),
// return None if it is is equal to to_block
0 => return None,
// return None if current level doesnt contain given bloom
_ if !level_bloom.contains(bloom) => return None,
// continue processing && go down
_ => ()
}
};
let level_size = self.level_size(level - 1);
let from_index = self.bloom_index(from_block, level - 1);
let to_index = self.bloom_index(to_block, level - 1);
let res: Vec<usize> = self.lower_level_bloom_indexes(&index).into_iter()
// chose only blooms in range
.filter(|li| li.index >= from_index.index && li.index <= to_index.index)
// map them to offsets
.map(|li| li.index * level_size)
// get all blocks that may contain our bloom
.map(|off| self.blocks(bloom, from_block, to_block, level - 1, off))
// filter existing ones
.filter_map(|x| x)
// flatten nested structures
.flat_map(|v| v)
.collect();
Some(res)
}
/// Adds new bloom to all filter levels
pub fn add_bloom(&self, bloom: &H2048, block_number: usize) -> HashMap<BloomIndex, H2048> {
let mut result: HashMap<BloomIndex, H2048> = HashMap::new();
for level in 0..self.levels() {
let bloom_index = self.bloom_index(block_number, level);
let new_bloom = match self.data_source.bloom_at_index(&bloom_index) {
Some(old_bloom) => old_bloom | bloom,
None => bloom.clone(),
};
result.insert(bloom_index, new_bloom);
}
result
}
/// Adds new blooms starting from block number.
pub fn add_blooms(&self, blooms: &[H2048], block_number: usize) -> HashMap<BloomIndex, H2048> {
let mut result: HashMap<BloomIndex, H2048> = HashMap::new();
for level in 0..self.levels() {
for i in 0..blooms.len() {
let bloom_index = self.bloom_index(block_number + i, level);
let is_new_bloom = match result.get_mut(&bloom_index) {
// it was already modified
Some(to_shift) => {
*to_shift = &blooms[i] | to_shift;
false
}
None => true,
};
// it hasn't been modified yet
if is_new_bloom {
let new_bloom = match self.data_source.bloom_at_index(&bloom_index) {
Some(old_bloom) => old_bloom | &blooms[i],
None => blooms[i].clone(),
};
result.insert(bloom_index, new_bloom);
}
}
}
result
}
/// Resets bloom at level 0 and forces rebuild on higher levels.
pub fn reset_bloom(&self, bloom: &H2048, block_number: usize) -> HashMap<BloomIndex, H2048> {
let mut result: HashMap<BloomIndex, H2048> = HashMap::new();
let mut reset_index = self.bloom_index(block_number, 0);
result.insert(reset_index.clone(), bloom.clone());
for level in 1..self.levels() {
let index = self.bloom_index(block_number, level);
// get all bloom indexes that were used to construct this bloom
let lower_indexes = self.lower_level_bloom_indexes(&index);
let new_bloom = lower_indexes.into_iter()
// skip reseted one
.filter(|li| li != &reset_index)
// get blooms for these indexes
.map(|li| self.data_source.bloom_at_index(&li))
// filter existing ones
.filter_map(|b| b)
// BitOr all of them
.fold(H2048::new(), |acc, bloom| &acc | bloom);
reset_index = index.clone();
result.insert(index, &new_bloom | bloom);
}
result
}
/// Sets lowest level bloom to 0 and forces rebuild on higher levels.
pub fn clear_bloom(&self, block_number: usize) -> HashMap<BloomIndex, H2048> {
self.reset_bloom(&H2048::new(), block_number)
}
/// Returns numbers of blocks that may contain Address.
pub fn blocks_with_address(&self, address: &Address, from_block: usize, to_block: usize) -> Vec<usize> {
let mut bloom = H2048::new();
bloom.shift_bloomed(&address.sha3());
self.blocks_with_bloom(&bloom, from_block, to_block)
}
/// Returns numbers of blocks that may contain Topic.
pub fn blocks_with_topic(&self, topic: &H256, from_block: usize, to_block: usize) -> Vec<usize> {
let mut bloom = H2048::new();
bloom.shift_bloomed(&topic.sha3());
self.blocks_with_bloom(&bloom, from_block, to_block)
}
/// Returns numbers of blocks that may log bloom.
pub fn blocks_with_bloom(&self, bloom: &H2048, from_block: usize, to_block: usize) -> Vec<usize> {
let mut result = vec![];
// lets start from highest level
let max_level = self.max_level();
let level_size = self.level_size(max_level);
let from_index = self.bloom_index(from_block, max_level);
let to_index = self.bloom_index(to_block, max_level);
for index in from_index.index..to_index.index + 1 {
// offset will be used to calculate where we are right now
let offset = level_size * index;
// go doooown!
match self.blocks(bloom, from_block, to_block, max_level, offset) {
Some(blocks) => result.extend(blocks),
None => ()
};
}
result
}
}
#[cfg(test)]
mod tests {
use hash::*;
use chainfilter::*;
use sha3::*;
use std::str::FromStr;
#[test]
fn test_level_size() {
let cache = MemoryCache::new();
let filter = ChainFilter::new(&cache, 16, 3);
assert_eq!(filter.level_size(0), 1);
assert_eq!(filter.level_size(1), 16);
assert_eq!(filter.level_size(2), 256);
}
#[test]
fn test_bloom_index() {
let cache = MemoryCache::new();
let filter = ChainFilter::new(&cache, 16, 3);
let bi0 = filter.bloom_index(0, 0);
assert_eq!(bi0.level, 0);
assert_eq!(bi0.index, 0);
let bi1 = filter.bloom_index(1, 0);
assert_eq!(bi1.level, 0);
assert_eq!(bi1.index, 1);
let bi2 = filter.bloom_index(2, 0);
assert_eq!(bi2.level, 0);
assert_eq!(bi2.index, 2);
let bi3 = filter.bloom_index(3, 1);
assert_eq!(bi3.level, 1);
assert_eq!(bi3.index, 0);
let bi4 = filter.bloom_index(15, 1);
assert_eq!(bi4.level, 1);
assert_eq!(bi4.index, 0);
let bi5 = filter.bloom_index(16, 1);
assert_eq!(bi5.level, 1);
assert_eq!(bi5.index, 1);
let bi6 = filter.bloom_index(255, 2);
assert_eq!(bi6.level, 2);
assert_eq!(bi6.index, 0);
let bi7 = filter.bloom_index(256, 2);
assert_eq!(bi7.level, 2);
assert_eq!(bi7.index, 1);
}
#[test]
fn test_lower_level_bloom_indexes() {
let cache = MemoryCache::new();
let filter = ChainFilter::new(&cache, 16, 3);
let bi = filter.bloom_index(256, 2);
assert_eq!(bi.level, 2);
assert_eq!(bi.index, 1);
let mut ebis = vec![];
for i in 16..32 {
ebis.push(BloomIndex::new(1, i));
}
let bis = filter.lower_level_bloom_indexes(&bi);
assert_eq!(ebis, bis);
}
#[test]
fn test_topic_basic_search() {
let index_size = 16;
let bloom_levels = 3;
let mut cache = MemoryCache::new();
let topic = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba").unwrap();
let modified_blooms = {
let filter = ChainFilter::new(&cache, index_size, bloom_levels);
let block_number = 23;
let mut bloom = H2048::new();
bloom.shift_bloomed(&topic.sha3());
filter.add_bloom(&bloom, block_number)
};
// number of modified blooms should always be equal number of levels
assert_eq!(modified_blooms.len(), bloom_levels as usize);
cache.insert_blooms(modified_blooms);
{
let filter = ChainFilter::new(&cache, index_size, bloom_levels);
let blocks = filter.blocks_with_topic(&topic, 0, 100);
assert_eq!(blocks.len(), 1);
assert_eq!(blocks[0], 23);
}
{
let filter = ChainFilter::new(&cache, index_size, bloom_levels);
let blocks = filter.blocks_with_topic(&topic, 0, 23);
assert_eq!(blocks.len(), 0);
}
{
let filter = ChainFilter::new(&cache, index_size, bloom_levels);
let blocks = filter.blocks_with_topic(&topic, 23, 24);
assert_eq!(blocks.len(), 1);
assert_eq!(blocks[0], 23);
}
{
let filter = ChainFilter::new(&cache, index_size, bloom_levels);
let blocks = filter.blocks_with_topic(&topic, 24, 100);
assert_eq!(blocks.len(), 0);
}
}
}

291
src/client.rs Normal file
View File

@@ -0,0 +1,291 @@
use util::*;
use rocksdb::{Options, DB};
use rocksdb::DBCompactionStyle::DBUniversalCompaction;
use blockchain::{BlockChain, BlockProvider};
use views::BlockView;
use error::*;
use header::BlockNumber;
use spec::Spec;
use engine::Engine;
use queue::BlockQueue;
use sync::NetSyncMessage;
use env_info::LastHashes;
use verification::*;
use block::*;
/// General block status
#[derive(Debug)]
pub enum BlockStatus {
/// Part of the blockchain.
InChain,
/// Queued for import.
Queued,
/// Known as bad.
Bad,
/// Unknown.
Unknown,
}
/// Information about the blockchain gthered together.
#[derive(Debug)]
pub struct BlockChainInfo {
/// Blockchain difficulty.
pub total_difficulty: U256,
/// Block queue difficulty.
pub pending_total_difficulty: U256,
/// Genesis block hash.
pub genesis_hash: H256,
/// Best blockchain block hash.
pub best_block_hash: H256,
/// Best blockchain block number.
pub best_block_number: BlockNumber
}
/// Block queue status
#[derive(Debug)]
pub struct BlockQueueStatus {
pub full: bool,
}
pub type TreeRoute = ::blockchain::TreeRoute;
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send {
/// Get raw block header data by block header hash.
fn block_header(&self, hash: &H256) -> Option<Bytes>;
/// Get raw block body data by block header hash.
/// Block body is an RLP list of two items: uncles and transactions.
fn block_body(&self, hash: &H256) -> Option<Bytes>;
/// Get raw block data by block header hash.
fn block(&self, hash: &H256) -> Option<Bytes>;
/// Get block status by block header hash.
fn block_status(&self, hash: &H256) -> BlockStatus;
/// Get raw block header data by block number.
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes>;
/// Get raw block body data by block number.
/// Block body is an RLP list of two items: uncles and transactions.
fn block_body_at(&self, n: BlockNumber) -> Option<Bytes>;
/// Get raw block data by block number.
fn block_at(&self, n: BlockNumber) -> Option<Bytes>;
/// Get block status by block number.
fn block_status_at(&self, n: BlockNumber) -> BlockStatus;
/// Get a tree route between `from` and `to`.
/// See `BlockChain::tree_route`.
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute>;
/// Get latest state node
fn state_data(&self, hash: &H256) -> Option<Bytes>;
/// Get raw block receipts data by block header hash.
fn block_receipts(&self, hash: &H256) -> Option<Bytes>;
/// Import a block into the blockchain.
fn import_block(&mut self, byte: &[u8]) -> ImportResult;
/// Get block queue information.
fn queue_status(&self) -> BlockQueueStatus;
/// Clear block queue and abort all import activity.
fn clear_queue(&mut self);
/// Get blockchain information.
fn chain_info(&self) -> BlockChainInfo;
}
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
pub struct Client {
chain: Arc<RwLock<BlockChain>>,
engine: Arc<Box<Engine>>,
state_db: OverlayDB,
queue: BlockQueue,
}
impl Client {
/// Create a new client with given spec and DB path.
pub fn new(spec: Spec, path: &Path, message_channel: IoChannel<NetSyncMessage> ) -> Result<Client, Error> {
let chain = Arc::new(RwLock::new(BlockChain::new(&spec.genesis_block(), path)));
let mut opts = Options::new();
opts.create_if_missing(true);
opts.set_max_open_files(256);
opts.set_use_fsync(false);
opts.set_bytes_per_sync(8388608);
opts.set_disable_data_sync(false);
opts.set_block_cache_size_mb(1024);
opts.set_table_cache_num_shard_bits(6);
opts.set_max_write_buffer_number(32);
opts.set_write_buffer_size(536870912);
opts.set_target_file_size_base(1073741824);
opts.set_min_write_buffer_number_to_merge(4);
opts.set_level_zero_stop_writes_trigger(2000);
opts.set_level_zero_slowdown_writes_trigger(0);
opts.set_compaction_style(DBUniversalCompaction);
opts.set_max_background_compactions(4);
opts.set_max_background_flushes(4);
opts.set_filter_deletes(false);
opts.set_disable_auto_compactions(true);
let mut state_path = path.to_path_buf();
state_path.push("state");
let db = DB::open(&opts, state_path.to_str().unwrap()).unwrap();
let mut state_db = OverlayDB::new(db);
let engine = Arc::new(try!(spec.to_engine()));
engine.spec().ensure_db_good(&mut state_db);
state_db.commit().expect("Error commiting genesis state to state DB");
// chain.write().unwrap().ensure_good(&state_db);
Ok(Client {
chain: chain,
engine: engine.clone(),
state_db: state_db,
queue: BlockQueue::new(engine, message_channel),
})
}
/// This is triggered by a message coming from a block queue when the block is ready for insertion
pub fn import_verified_block(&mut self, bytes: Bytes) {
let block = BlockView::new(&bytes);
let header = block.header();
if let Err(e) = verify_block_family(&header, &bytes, self.engine.deref().deref(), self.chain.read().unwrap().deref()) {
warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
self.queue.mark_as_bad(&header.hash());
return;
};
let parent = match self.chain.read().unwrap().block_header(&header.parent_hash) {
Some(p) => p,
None => {
warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash);
self.queue.mark_as_bad(&header.hash());
return;
},
};
// build last hashes
let mut last_hashes = LastHashes::new();
last_hashes.resize(256, H256::new());
last_hashes[0] = header.parent_hash.clone();
for i in 0..255 {
match self.chain.read().unwrap().block_details(&last_hashes[i]) {
Some(details) => {
last_hashes[i + 1] = details.parent.clone();
},
None => break,
}
}
let result = match enact(&bytes, self.engine.deref().deref(), self.state_db.clone(), &parent, &last_hashes) {
Ok(b) => b,
Err(e) => {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
self.queue.mark_as_bad(&header.hash());
return;
}
};
if let Err(e) = verify_block_final(&header, result.block().header()) {
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
self.queue.mark_as_bad(&header.hash());
return;
}
self.chain.write().unwrap().insert_block(&bytes); //TODO: err here?
match result.drain().commit() {
Ok(_) => (),
Err(e) => {
warn!(target: "client", "State DB commit failed: {:?}", e);
return;
}
}
info!(target: "client", "Imported #{} ({})", header.number(), header.hash());
}
}
impl BlockChainClient for Client {
fn block_header(&self, hash: &H256) -> Option<Bytes> {
self.chain.read().unwrap().block(hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())
}
fn block_body(&self, hash: &H256) -> Option<Bytes> {
self.chain.read().unwrap().block(hash).map(|bytes| {
let rlp = Rlp::new(&bytes);
let mut body = RlpStream::new();
body.append_raw(rlp.at(1).as_raw(), 1);
body.append_raw(rlp.at(2).as_raw(), 1);
body.out()
})
}
fn block(&self, hash: &H256) -> Option<Bytes> {
self.chain.read().unwrap().block(hash)
}
fn block_status(&self, hash: &H256) -> BlockStatus {
if self.chain.read().unwrap().is_known(&hash) { BlockStatus::InChain } else { BlockStatus::Unknown }
}
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes> {
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h))
}
fn block_body_at(&self, n: BlockNumber) -> Option<Bytes> {
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_body(&h))
}
fn block_at(&self, n: BlockNumber) -> Option<Bytes> {
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block(&h))
}
fn block_status_at(&self, n: BlockNumber) -> BlockStatus {
match self.chain.read().unwrap().block_hash(n) {
Some(h) => self.block_status(&h),
None => BlockStatus::Unknown
}
}
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
self.chain.read().unwrap().tree_route(from.clone(), to.clone())
}
fn state_data(&self, _hash: &H256) -> Option<Bytes> {
unimplemented!();
}
fn block_receipts(&self, _hash: &H256) -> Option<Bytes> {
unimplemented!();
}
fn import_block(&mut self, bytes: &[u8]) -> ImportResult {
let header = BlockView::new(bytes).header();
if self.chain.read().unwrap().is_known(&header.hash()) {
return Err(ImportError::AlreadyInChain);
}
self.queue.import_block(bytes)
}
fn queue_status(&self) -> BlockQueueStatus {
BlockQueueStatus {
full: false
}
}
fn clear_queue(&mut self) {
}
fn chain_info(&self) -> BlockChainInfo {
let chain = self.chain.read().unwrap();
BlockChainInfo {
total_difficulty: chain.best_block_total_difficulty(),
pending_total_difficulty: chain.best_block_total_difficulty(),
genesis_hash: chain.genesis_hash(),
best_block_hash: chain.best_block_hash(),
best_block_number: From::from(chain.best_block_number())
}
}
}

View File

@@ -1,57 +1,12 @@
pub use standard::*;
pub use from_json::*;
pub use util::*;
pub use basic_types::*;
pub use error::*;
pub use hash::*;
pub use uint::*;
pub use bytes::*;
pub use vector::*;
pub use sha3::*;
#[macro_export]
macro_rules! map {
( $( $x:expr => $y:expr ),* ) => {
vec![ $( ($x, $y) ),* ].into_iter().collect::<BTreeMap<_, _>>()
}
}
#[macro_export]
macro_rules! mapx {
( $( $x:expr => $y:expr ),* ) => {
vec![ $( ( From::from($x), From::from($y) ) ),* ].into_iter().collect::<BTreeMap<_, _>>()
}
}
#[macro_export]
macro_rules! x {
( $x:expr ) => {
From::from($x)
}
}
#[macro_export]
macro_rules! xx {
( $x:expr ) => {
From::from(From::from($x))
}
}
#[macro_export]
macro_rules! flush {
($($arg:tt)*) => ($crate::flush(format!("{}", format_args!($($arg)*))));
}
#[macro_export]
macro_rules! flushln {
($fmt:expr) => (flush!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (flush!(concat!($fmt, "\n"), $($arg)*));
}
pub fn flush(s: String) {
::std::io::stdout().write(s.as_bytes()).unwrap();
::std::io::stdout().flush().unwrap();
}
#[test]
fn test_flush() {
flushln!("hello_world {:?}", 1);
}
pub use env_info::*;
pub use views::*;
pub use builtin::*;
pub use header::*;
pub use account::*;
pub use transaction::*;
pub use log_entry::*;
pub use receipt::*;
pub use action_params::*;

View File

@@ -1,361 +0,0 @@
use hash::*;
use bytes::*;
use uint::*;
use secp256k1::{key, Secp256k1};
use rand::os::OsRng;
pub type Secret = H256;
pub type Public = H512;
pub type Signature = H520;
impl Signature {
/// Create a new signature from the R, S and V componenets.
pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Signature {
use std::ptr;
let mut ret: Signature = Signature::new();
unsafe {
let retslice: &mut [u8] = &mut ret;
ptr::copy(r.as_ptr(), retslice.as_mut_ptr(), 32);
ptr::copy(s.as_ptr(), retslice.as_mut_ptr().offset(32), 32);
}
ret[64] = v;
ret
}
/// Convert transaction to R, S and V components.
pub fn to_rsv(&self) -> (U256, U256, u8) {
(U256::from(&self.as_slice()[0..32]), U256::from(&self.as_slice()[32..64]), self[64])
}
}
#[derive(Debug)]
pub enum CryptoError {
InvalidSecret,
InvalidPublic,
InvalidSignature,
InvalidMessage,
Io(::std::io::Error),
}
impl From<::secp256k1::Error> for CryptoError {
fn from(e: ::secp256k1::Error) -> CryptoError {
match e {
::secp256k1::Error::InvalidMessage => CryptoError::InvalidMessage,
::secp256k1::Error::InvalidPublicKey => CryptoError::InvalidPublic,
::secp256k1::Error::InvalidSignature => CryptoError::InvalidSignature,
::secp256k1::Error::InvalidSecretKey => CryptoError::InvalidSecret,
_ => CryptoError::InvalidSignature,
}
}
}
impl From<::std::io::Error> for CryptoError {
fn from(err: ::std::io::Error) -> CryptoError {
CryptoError::Io(err)
}
}
#[derive(Debug, PartialEq, Eq)]
/// secp256k1 Key pair
///
/// Use `create()` to create a new random key pair.
///
/// # Example
/// ```rust
/// extern crate ethcore_util;
/// use ethcore_util::crypto::*;
/// use ethcore_util::hash::*;
/// fn main() {
/// let pair = KeyPair::create().unwrap();
/// let message = H256::random();
/// let signature = ec::sign(pair.secret(), &message).unwrap();
///
/// assert!(ec::verify(pair.public(), &signature, &message).unwrap());
/// assert_eq!(ec::recover(&signature, &message).unwrap(), *pair.public());
/// }
/// ```
pub struct KeyPair {
secret: Secret,
public: Public,
}
impl KeyPair {
/// Create a pair from secret key
pub fn from_secret(secret: Secret) -> Result<KeyPair, CryptoError> {
let context = Secp256k1::new();
let s: key::SecretKey = try!(key::SecretKey::from_slice(&context, &secret));
let pub_key = try!(key::PublicKey::from_secret_key(&context, &s));
let serialized = pub_key.serialize_vec(&context, false);
let p: Public = Public::from_slice(&serialized[1..65]);
Ok(KeyPair {
secret: secret,
public: p,
})
}
/// Create a new random key pair
pub fn create() -> Result<KeyPair, CryptoError> {
let context = Secp256k1::new();
let mut rng = try!(OsRng::new());
let (sec, publ) = try!(context.generate_keypair(&mut rng));
let serialized = publ.serialize_vec(&context, false);
let p: Public = Public::from_slice(&serialized[1..65]);
let s: Secret = unsafe { ::std::mem::transmute(sec) };
Ok(KeyPair {
secret: s,
public: p,
})
}
/// Returns public key
pub fn public(&self) -> &Public {
&self.public
}
/// Returns private key
pub fn secret(&self) -> &Secret {
&self.secret
}
/// Sign a message with our secret key.
pub fn sign(&self, message: &H256) -> Result<Signature, CryptoError> { ec::sign(&self.secret, message) }
}
pub mod ec {
use hash::*;
use uint::*;
use standard::*;
use crypto::*;
use crypto::{self};
/// Recovers Public key from signed message hash.
pub fn recover(signature: &Signature, message: &H256) -> Result<Public, CryptoError> {
use secp256k1::*;
let context = Secp256k1::new();
let rsig = try!(RecoverableSignature::from_compact(&context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
let publ = try!(context.recover(&try!(Message::from_slice(&message)), &rsig));
let serialized = publ.serialize_vec(&context, false);
let p: Public = Public::from_slice(&serialized[1..65]);
//TODO: check if it's the zero key and fail if so.
Ok(p)
}
/// Returns siganture of message hash.
pub fn sign(secret: &Secret, message: &H256) -> Result<Signature, CryptoError> {
// TODO: allow creation of only low-s signatures.
use secp256k1::*;
let context = Secp256k1::new();
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec));
let (rec_id, data) = s.serialize_compact(&context);
let mut signature: crypto::Signature = unsafe { ::std::mem::uninitialized() };
signature.clone_from_slice(&data);
signature[64] = rec_id.to_i32() as u8;
Ok(signature)
}
/// Verify signature.
pub fn verify(public: &Public, signature: &Signature, message: &H256) -> Result<bool, CryptoError> {
use secp256k1::*;
let context = Secp256k1::new();
let rsig = try!(RecoverableSignature::from_compact(&context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
let sig = rsig.to_standard(&context);
let mut pdata: [u8; 65] = [4u8; 65];
let ptr = pdata[1..].as_mut_ptr();
let src = public.as_ptr();
unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) };
let publ = try!(key::PublicKey::from_slice(&context, &pdata));
match context.verify(&try!(Message::from_slice(&message)), &sig, &publ) {
Ok(_) => Ok(true),
Err(Error::IncorrectSignature) => Ok(false),
Err(x) => Err(<CryptoError as From<Error>>::from(x))
}
}
/// Check if this is a "low" signature.
pub fn is_low(sig: &Signature) -> bool {
H256::from_slice(&sig[32..64]) <= h256_from_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0")
}
/// Check if this is a "low" signature.
pub fn is_low_s(s: &U256) -> bool {
s <= &U256::from_str("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0").unwrap()
}
/// Check if each component of the signature is in range.
pub fn is_valid(sig: &Signature) -> bool {
sig[64] <= 1 &&
H256::from_slice(&sig[0..32]) < h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") &&
H256::from_slice(&sig[32..64]) < h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") &&
H256::from_slice(&sig[32..64]) >= h256_from_u64(1) &&
H256::from_slice(&sig[0..32]) >= h256_from_u64(1)
}
}
pub mod ecdh {
use crypto::*;
pub fn agree(secret: &Secret, public: &Public, ) -> Result<Secret, CryptoError> {
use secp256k1::*;
let context = Secp256k1::new();
let mut pdata: [u8; 65] = [4u8; 65];
let ptr = pdata[1..].as_mut_ptr();
let src = public.as_ptr();
unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) };
let publ = try!(key::PublicKey::from_slice(&context, &pdata));
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
let shared = ecdh::SharedSecret::new_raw(&context, &publ, &sec);
let s: Secret = unsafe { ::std::mem::transmute(shared) };
Ok(s)
}
}
pub mod ecies {
use hash::*;
use bytes::*;
use crypto::*;
pub fn encrypt(public: &Public, plain: &[u8]) -> Result<Bytes, CryptoError> {
use ::rcrypto::digest::Digest;
use ::rcrypto::sha2::Sha256;
use ::rcrypto::hmac::Hmac;
use ::rcrypto::mac::Mac;
let r = try!(KeyPair::create());
let z = try!(ecdh::agree(r.secret(), public));
let mut key = [0u8; 32];
let mut mkey = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let mut hasher = Sha256::new();
let mkey_material = &key[16..32];
hasher.input(mkey_material);
hasher.result(&mut mkey);
let ekey = &key[0..16];
let mut msg = vec![0u8; (1 + 64 + 16 + plain.len() + 32)];
msg[0] = 0x04u8;
{
let msgd = &mut msg[1..];
r.public().copy_to(&mut msgd[0..64]);
{
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
aes::encrypt(ekey, &H128::new(), plain, cipher);
}
let mut hmac = Hmac::new(Sha256::new(), &mkey);
{
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
hmac.input(cipher_iv);
}
hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]);
}
Ok(msg)
}
pub fn decrypt(secret: &Secret, encrypted: &[u8]) -> Result<Bytes, CryptoError> {
use ::rcrypto::digest::Digest;
use ::rcrypto::sha2::Sha256;
use ::rcrypto::hmac::Hmac;
use ::rcrypto::mac::Mac;
let meta_len = 1 + 64 + 16 + 32;
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
return Err(CryptoError::InvalidMessage); //invalid message: publickey
}
let e = &encrypted[1..];
let p = Public::from_slice(&e[0..64]);
let z = try!(ecdh::agree(secret, &p));
let mut key = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let ekey = &key[0..16];
let mkey_material = &key[16..32];
let mut hasher = Sha256::new();
let mut mkey = [0u8; 32];
hasher.input(mkey_material);
hasher.result(&mut mkey);
let clen = encrypted.len() - meta_len;
let cipher_with_iv = &e[64..(64+16+clen)];
let cipher_iv = &cipher_with_iv[0..16];
let cipher_no_iv = &cipher_with_iv[16..];
let msg_mac = &e[(64+16+clen)..];
// Verify tag
let mut hmac = Hmac::new(Sha256::new(), &mkey);
hmac.input(cipher_with_iv);
let mut mac = H256::new();
hmac.raw_result(&mut mac);
if &mac[..] != msg_mac {
return Err(CryptoError::InvalidMessage);
}
let mut msg = vec![0u8; clen];
aes::decrypt(ekey, cipher_iv, cipher_no_iv, &mut msg[..]);
Ok(msg)
}
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
use ::rcrypto::digest::Digest;
use ::rcrypto::sha2::Sha256;
let mut hasher = Sha256::new();
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
// to size of hash output, however, it also notes that
// the 4 bytes is okay. NIST specifies 4 bytes.
let mut ctr = 1u32;
let mut written = 0usize;
while written < dest.len() {
let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8];
hasher.input(&ctrs);
hasher.input(secret);
hasher.input(s1);
hasher.result(&mut dest[written..(written + 32)]);
hasher.reset();
written += 32;
ctr += 1;
}
}
}
pub mod aes {
use ::rcrypto::blockmodes::*;
use ::rcrypto::aessafe::*;
use ::rcrypto::symmetriccipher::*;
use ::rcrypto::buffer::*;
pub fn encrypt(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) {
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding");
}
pub fn decrypt(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) {
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding");
}
}
#[cfg(test)]
mod tests {
use hash::*;
use crypto::*;
// TODO: tests for sign/recover roundtrip, at least.
#[test]
fn test_signature() {
let pair = KeyPair::create().unwrap();
let message = H256::random();
let signature = ec::sign(pair.secret(), &message).unwrap();
assert!(ec::verify(pair.public(), &signature, &message).unwrap());
assert_eq!(ec::recover(&signature, &message).unwrap(), *pair.public());
}
#[test]
fn test_invalid_key() {
assert!(KeyPair::from_secret(h256_from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")).is_err());
assert!(KeyPair::from_secret(h256_from_hex("0000000000000000000000000000000000000000000000000000000000000000")).is_err());
assert!(KeyPair::from_secret(h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141")).is_err());
}
#[test]
fn test_key() {
let pair = KeyPair::from_secret(h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2")).unwrap();
assert_eq!(pair.public().hex(), "101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c");
}
}

71
src/engine.rs Normal file
View File

@@ -0,0 +1,71 @@
use common::*;
use block::Block;
use spec::Spec;
use evm::Schedule;
use evm::Factory;
/// A consensus mechanism for the chain. Generally either proof-of-work or proof-of-stake-based.
/// Provides hooks into each of the major parts of block import.
pub trait Engine : Sync + Send {
/// The name of this engine.
fn name(&self) -> &str;
/// The version of this engine. Should be of the form
fn version(&self) -> SemanticVersion { SemanticVersion::new(0, 0, 0) }
/// The number of additional header fields required for this engine.
fn seal_fields(&self) -> usize { 0 }
/// Default values of the additional fields RLP-encoded in a raw (non-list) harness.
fn seal_rlp(&self) -> Bytes { vec![] }
/// Additional engine-specific information for the user/developer concerning `header`.
fn extra_info(&self, _header: &Header) -> HashMap<String, String> { HashMap::new() }
/// Get the general parameters of the chain.
fn spec(&self) -> &Spec;
/// Get current EVM factory
fn vm_factory(&self) -> &Factory;
/// Get the EVM schedule for the given `env_info`.
fn schedule(&self, env_info: &EnvInfo) -> Schedule;
/// Some intrinsic operation parameters; by default they take their value from the `spec()`'s `engine_params`.
fn maximum_extra_data_size(&self) -> usize { decode(&self.spec().engine_params.get("maximumExtraDataSize").unwrap()) }
fn maximum_uncle_count(&self) -> usize { 2 }
fn account_start_nonce(&self) -> U256 { decode(&self.spec().engine_params.get("accountStartNonce").unwrap()) }
/// Block transformation functions, before and after the transactions.
fn on_new_block(&self, _block: &mut Block) {}
fn on_close_block(&self, _block: &mut Block) {}
// TODO: consider including State in the params for verification functions.
/// Phase 1 quick block verification. Only does checks that are cheap. `block` (the header's full block)
/// may be provided for additional checks. Returns either a null `Ok` or a general error detailing the problem with import.
fn verify_block_basic(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { Ok(()) }
/// Phase 2 verification. Perform costly checks such as transaction signatures. `block` (the header's full block)
/// may be provided for additional checks. Returns either a null `Ok` or a general error detailing the problem with import.
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { Ok(()) }
/// Phase 3 verification. Check block information against parent and uncles. `block` (the header's full block)
/// may be provided for additional checks. Returns either a null `Ok` or a general error detailing the problem with import.
fn verify_block_family(&self, _header: &Header, _parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> { Ok(()) }
/// Additional verification for transactions in blocks.
// TODO: Add flags for which bits of the transaction to check.
// TODO: consider including State in the params.
fn verify_transaction_basic(&self, _t: &Transaction, _header: &Header) -> Result<(), Error> { Ok(()) }
fn verify_transaction(&self, _t: &Transaction, _header: &Header) -> Result<(), Error> { Ok(()) }
/// Don't forget to call Super::populateFromParent when subclassing & overriding.
// TODO: consider including State in the params.
fn populate_from_parent(&self, _header: &mut Header, _parent: &Header) {}
// TODO: builtin contract routing - to do this properly, it will require removing the built-in configuration-reading logic
// from Spec into here and removing the Spec::builtins field.
fn is_builtin(&self, a: &Address) -> bool { self.spec().builtins.contains_key(a) }
fn cost_of_builtin(&self, a: &Address, input: &[u8]) -> U256 { self.spec().builtins.get(a).unwrap().cost(input.len()) }
fn execute_builtin(&self, a: &Address, input: &[u8], output: &mut [u8]) { self.spec().builtins.get(a).unwrap().execute(input, output); }
// TODO: sealing stuff - though might want to leave this for later.
}

62
src/env_info.rs Normal file
View File

@@ -0,0 +1,62 @@
use util::*;
use header::BlockNumber;
/// Simple vector of hashes, should be at most 256 items large, can be smaller if being used
/// for a block whose number is less than 257.
pub type LastHashes = Vec<H256>;
/// Information concerning the execution environment for a message-call/contract-creation.
#[derive(Debug)]
pub struct EnvInfo {
/// The block number.
pub number: BlockNumber,
/// The block author.
pub author: Address,
/// The block timestamp.
pub timestamp: u64,
/// The block difficulty.
pub difficulty: U256,
/// The block gas limit.
pub gas_limit: U256,
/// The last 256 block hashes.
pub last_hashes: LastHashes,
/// The gas used.
pub gas_used: U256,
}
impl EnvInfo {
pub fn new() -> EnvInfo {
EnvInfo {
number: 0,
author: Address::new(),
timestamp: 0,
difficulty: x!(0),
gas_limit: x!(0),
last_hashes: vec![],
gas_used: x!(0),
}
}
}
impl FromJson for EnvInfo {
fn from_json(json: &Json) -> EnvInfo {
let current_number: u64 = xjson!(&json["currentNumber"]);
EnvInfo {
number: current_number,
author: xjson!(&json["currentCoinbase"]),
difficulty: xjson!(&json["currentDifficulty"]),
gas_limit: xjson!(&json["currentGasLimit"]),
timestamp: xjson!(&json["currentTimestamp"]),
last_hashes: (1..cmp::min(current_number + 1, 257)).map(|i| format!("{}", current_number - i).as_bytes().sha3()).collect(),
gas_used: x!(0),
}
}
}
/// TODO: it should be the other way around.
/// `new` should call `default`.
impl Default for EnvInfo {
fn default() -> Self {
EnvInfo::new()
}
}

View File

@@ -1,75 +1,139 @@
//! General error types for use in ethcore.
use rustc_serialize::hex::FromHexError;
use network::NetworkError;
use rlp::DecoderError;
use io;
use util::*;
use header::BlockNumber;
use basic_types::LogBloom;
#[derive(Debug, PartialEq, Eq)]
pub struct Mismatch<T: fmt::Debug> {
pub expected: T,
pub found: T,
}
#[derive(Debug, PartialEq, Eq)]
pub struct OutOfBounds<T: fmt::Debug> {
pub min: Option<T>,
pub max: Option<T>,
pub found: T,
}
/// Result of executing the transaction.
#[derive(PartialEq, Debug)]
pub enum ExecutionError {
/// Returned when there gas paid for transaction execution is
/// lower than base gas required.
NotEnoughBaseGas { required: U256, got: U256 },
/// Returned when block (gas_used + gas) > gas_limit.
///
/// If gas =< gas_limit, upstream may try to execute the transaction
/// in next block.
BlockGasLimitReached { gas_limit: U256, gas_used: U256, gas: U256 },
/// Returned when transaction nonce does not match state nonce.
InvalidNonce { expected: U256, got: U256 },
/// Returned when cost of transaction (value + gas_price * gas) exceeds
/// current sender balance.
NotEnoughCash { required: U512, got: U512 },
/// Returned when internal evm error occurs.
Internal
}
#[derive(Debug)]
pub enum BaseDataError {
NegativelyReferencedHash,
pub enum TransactionError {
InvalidGasLimit(OutOfBounds<U256>),
}
#[derive(Debug, PartialEq, Eq)]
pub enum BlockError {
TooManyUncles(OutOfBounds<usize>),
UncleWrongGeneration,
ExtraDataOutOfBounds(OutOfBounds<usize>),
InvalidSealArity(Mismatch<usize>),
TooMuchGasUsed(OutOfBounds<U256>),
InvalidUnclesHash(Mismatch<H256>),
UncleTooOld(OutOfBounds<BlockNumber>),
UncleIsBrother(OutOfBounds<BlockNumber>),
UncleInChain(H256),
UncleParentNotInChain(H256),
InvalidStateRoot(Mismatch<H256>),
InvalidGasUsed(Mismatch<U256>),
InvalidTransactionsRoot(Mismatch<H256>),
InvalidDifficulty(Mismatch<U256>),
InvalidGasLimit(OutOfBounds<U256>),
InvalidReceiptsStateRoot(Mismatch<H256>),
InvalidTimestamp(OutOfBounds<u64>),
InvalidLogBloom(Mismatch<LogBloom>),
InvalidBlockNonce(Mismatch<H256>),
InvalidParentHash(Mismatch<H256>),
InvalidNumber(OutOfBounds<BlockNumber>),
UnknownParent(H256),
UnknownUncleParent(H256),
}
#[derive(Debug)]
pub enum ImportError {
Bad(Option<Error>),
AlreadyInChain,
AlreadyQueued,
}
impl From<Error> for ImportError {
fn from(err: Error) -> ImportError {
ImportError::Bad(Some(err))
}
}
/// Result of import block operation.
pub type ImportResult = Result<(), ImportError>;
#[derive(Debug)]
/// General error type which should be capable of representing all errors in ethcore.
pub enum UtilError {
Crypto(::crypto::CryptoError),
StdIo(::std::io::Error),
Io(io::IoError),
AddressParse(::std::net::AddrParseError),
AddressResolve(Option<::std::io::Error>),
FromHex(FromHexError),
BaseData(BaseDataError),
Network(NetworkError),
Decoder(DecoderError),
BadSize,
pub enum Error {
Util(UtilError),
Block(BlockError),
UnknownEngineName(String),
Execution(ExecutionError),
Transaction(TransactionError),
}
impl From<FromHexError> for UtilError {
fn from(err: FromHexError) -> UtilError {
UtilError::FromHex(err)
impl From<TransactionError> for Error {
fn from(err: TransactionError) -> Error {
Error::Transaction(err)
}
}
impl From<BaseDataError> for UtilError {
fn from(err: BaseDataError) -> UtilError {
UtilError::BaseData(err)
impl From<BlockError> for Error {
fn from(err: BlockError) -> Error {
Error::Block(err)
}
}
impl From<NetworkError> for UtilError {
fn from(err: NetworkError) -> UtilError {
UtilError::Network(err)
impl From<ExecutionError> for Error {
fn from(err: ExecutionError) -> Error {
Error::Execution(err)
}
}
impl From<::std::io::Error> for UtilError {
fn from(err: ::std::io::Error) -> UtilError {
UtilError::StdIo(err)
impl From<CryptoError> for Error {
fn from(err: CryptoError) -> Error {
Error::Util(UtilError::Crypto(err))
}
}
impl From<io::IoError> for UtilError {
fn from(err: io::IoError) -> UtilError {
UtilError::Io(err)
impl From<DecoderError> for Error {
fn from(err: DecoderError) -> Error {
Error::Util(UtilError::Decoder(err))
}
}
impl From<::crypto::CryptoError> for UtilError {
fn from(err: ::crypto::CryptoError) -> UtilError {
UtilError::Crypto(err)
impl From<UtilError> for Error {
fn from(err: UtilError) -> Error {
Error::Util(err)
}
}
impl From<::std::net::AddrParseError> for UtilError {
fn from(err: ::std::net::AddrParseError) -> UtilError {
UtilError::AddressParse(err)
}
}
impl From<::rlp::DecoderError> for UtilError {
fn from(err: ::rlp::DecoderError) -> UtilError {
UtilError::Decoder(err)
impl From<IoError> for Error {
fn from(err: IoError) -> Error {
Error::Util(From::from(err))
}
}

View File

@@ -0,0 +1,17 @@
use util::*;
#[inline]
pub fn ether() -> U256 { U256::exp10(18) }
#[inline]
pub fn finney() -> U256 { U256::exp10(15) }
#[inline]
pub fn szabo() -> U256 { U256::exp10(12) }
#[inline]
pub fn shannon() -> U256 { U256::exp10(9) }
#[inline]
pub fn wei() -> U256 { U256::exp10(0) }

202
src/ethereum/ethash.rs Normal file
View File

@@ -0,0 +1,202 @@
use common::*;
use block::*;
use spec::*;
use engine::*;
use evm::Schedule;
use evm::Factory;
/// Engine using Ethash proof-of-work consensus algorithm, suitable for Ethereum
/// mainnet chains in the Olympic, Frontier and Homestead eras.
pub struct Ethash {
spec: Spec,
factory: Factory,
u64_params: RwLock<HashMap<String, u64>>,
u256_params: RwLock<HashMap<String, U256>>,
}
impl Ethash {
pub fn new_boxed(spec: Spec) -> Box<Engine> {
Box::new(Ethash{
spec: spec,
// TODO [todr] should this return any specific factory?
factory: Factory::default(),
u64_params: RwLock::new(HashMap::new()),
u256_params: RwLock::new(HashMap::new())
})
}
fn u64_param(&self, name: &str) -> u64 {
*self.u64_params.write().unwrap().entry(name.to_string()).or_insert_with(||
self.spec().engine_params.get(name).map(|a| decode(&a)).unwrap_or(0u64))
}
fn u256_param(&self, name: &str) -> U256 {
*self.u256_params.write().unwrap().entry(name.to_string()).or_insert_with(||
self.spec().engine_params.get(name).map(|a| decode(&a)).unwrap_or(x!(0)))
}
}
impl Engine for Ethash {
fn name(&self) -> &str { "Ethash" }
fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) }
// Two fields - mix
fn seal_fields(&self) -> usize { 2 }
// Two empty data items in RLP.
fn seal_rlp(&self) -> Bytes { encode(&H64::new()) }
/// Additional engine-specific information for the user/developer concerning `header`.
fn extra_info(&self, _header: &Header) -> HashMap<String, String> { HashMap::new() }
fn spec(&self) -> &Spec { &self.spec }
fn vm_factory(&self) -> &Factory {
&self.factory
}
fn schedule(&self, env_info: &EnvInfo) -> Schedule {
match env_info.number < self.u64_param("frontierCompatibilityModeLimit") {
true => Schedule::new_frontier(),
_ => Schedule::new_homestead(),
}
}
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
header.difficulty = self.calculate_difficuty(header, parent);
header.gas_limit = {
let gas_floor_target: U256 = x!(3141562);
let gas_limit = parent.gas_limit;
let bound_divisor = self.u256_param("gasLimitBoundDivisor");
if gas_limit < gas_floor_target {
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - x!(1))
} else {
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + x!(1) + (header.gas_used * x!(6) / x!(5)) / bound_divisor)
}
};
// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit);
}
/// Apply the block reward on finalisation of the block.
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
fn on_close_block(&self, block: &mut Block) {
let reward = self.spec().engine_params.get("blockReward").map(|a| decode(&a)).unwrap_or(U256::from(0u64));
let fields = block.fields();
// Bestow block reward
fields.state.add_balance(&fields.header.author, &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())));
// Bestow uncle rewards
let current_number = fields.header.number();
for u in fields.uncles.iter() {
fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)));
}
fields.state.commit();
}
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
let min_difficulty = decode(self.spec().engine_params.get("minimumDifficulty").unwrap());
if header.difficulty < min_difficulty {
return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: min_difficulty, found: header.difficulty })))
}
// TODO: Verify seal (quick)
Ok(())
}
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
// TODO: Verify seal (full)
Ok(())
}
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
// Check difficulty is correct given the two timestamps.
let expected_difficulty = self.calculate_difficuty(header, parent);
if header.difficulty != expected_difficulty {
return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: expected_difficulty, found: header.difficulty })))
}
let gas_limit_divisor = decode(self.spec().engine_params.get("gasLimitBoundDivisor").unwrap());
let min_gas = parent.gas_limit - parent.gas_limit / gas_limit_divisor;
let max_gas = parent.gas_limit + parent.gas_limit / gas_limit_divisor;
if header.gas_limit <= min_gas || header.gas_limit >= max_gas {
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit })));
}
Ok(())
}
fn verify_transaction_basic(&self, t: &Transaction, header: &Header) -> result::Result<(), Error> {
if header.number() >= self.u64_param("frontierCompatibilityModeLimit") {
try!(t.check_low_s());
}
Ok(())
}
}
impl Ethash {
fn calculate_difficuty(&self, header: &Header, parent: &Header) -> U256 {
const EXP_DIFF_PERIOD: u64 = 100000;
if header.number == 0 {
panic!("Can't calculate genesis block difficulty");
}
let min_difficulty = self.u256_param("minimumDifficulty");
let difficulty_bound_divisor = self.u256_param("difficultyBoundDivisor");
let duration_limit = self.u64_param("durationLimit");
let frontier_limit = self.u64_param("frontierCompatibilityModeLimit");
let mut target = if header.number < frontier_limit {
if header.timestamp >= parent.timestamp + duration_limit {
parent.difficulty - (parent.difficulty / difficulty_bound_divisor)
}
else {
parent.difficulty + (parent.difficulty / difficulty_bound_divisor)
}
}
else {
let diff_inc = (header.timestamp - parent.timestamp) / 10;
if diff_inc <= 1 {
parent.difficulty + parent.difficulty / From::from(2048) * From::from(1 - diff_inc)
}
else {
parent.difficulty - parent.difficulty / From::from(2048) * From::from(max(diff_inc - 1, 99))
}
};
target = max(min_difficulty, target);
let period = ((parent.number + 1) / EXP_DIFF_PERIOD) as usize;
if period > 1 {
target = max(min_difficulty, target + (U256::from(1) << (period - 2)));
}
target
}
}
#[test]
fn on_close_block() {
use super::*;
let engine = new_morden().to_engine().unwrap();
let genesis_header = engine.spec().genesis_header();
let mut db = OverlayDB::new_temp();
engine.spec().ensure_db_good(&mut db);
let last_hashes = vec![genesis_header.hash()];
let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
}
#[test]
fn on_close_block_with_uncle() {
use super::*;
let engine = new_morden().to_engine().unwrap();
let genesis_header = engine.spec().genesis_header();
let mut db = OverlayDB::new_temp();
engine.spec().ensure_db_good(&mut db);
let last_hashes = vec![genesis_header.hash()];
let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
let mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone();
b.push_uncle(uncle).unwrap();
let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("478eae0e571ba000").unwrap());
assert_eq!(b.state().balance(&uncle_author), U256::from_str("3cb71f51fc558000").unwrap());
}
// TODO: difficulty test

75
src/ethereum/mod.rs Normal file
View File

@@ -0,0 +1,75 @@
//! Ethereum protocol module.
//!
//! Contains all Ethereum network specific stuff, such as denominations and
//! consensus specifications.
pub mod ethash;
pub mod denominations;
pub use self::ethash::*;
pub use self::denominations::*;
use super::spec::*;
/// Create a new Olympic chain spec.
pub fn new_olympic() -> Spec { Spec::from_json_utf8(include_bytes!("../../res/ethereum/olympic.json")) }
/// Create a new Frontier mainnet chain spec.
pub fn new_frontier() -> Spec { Spec::from_json_utf8(include_bytes!("../../res/ethereum/frontier.json")) }
/// Create a new Frontier chain spec as though it never changes to Homestead.
pub fn new_frontier_test() -> Spec { Spec::from_json_utf8(include_bytes!("../../res/ethereum/frontier_test.json")) }
/// Create a new Homestead chain spec as though it never changed from Frontier.
pub fn new_homestead_test() -> Spec { Spec::from_json_utf8(include_bytes!("../../res/ethereum/homestead_test.json")) }
/// Create a new Frontier main net chain spec without genesis accounts.
pub fn new_frontier_like_test() -> Spec { Spec::from_json_utf8(include_bytes!("../../res/ethereum/frontier_like_test.json")) }
/// Create a new Morden chain spec.
pub fn new_morden() -> Spec { Spec::from_json_utf8(include_bytes!("../../res/ethereum/morden.json")) }
#[cfg(test)]
mod tests {
use common::*;
use state::*;
use engine::*;
use super::*;
#[test]
fn ensure_db_good() {
let engine = new_morden().to_engine().unwrap();
let genesis_header = engine.spec().genesis_header();
let mut db = OverlayDB::new_temp();
engine.spec().ensure_db_good(&mut db);
let s = State::from_existing(db.clone(), genesis_header.state_root.clone(), engine.account_start_nonce());
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000003")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000004")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c")), U256::from(1u64) << 200);
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000000")), U256::from(0u64));
}
#[test]
fn morden() {
let morden = new_morden();
assert_eq!(morden.state_root(), H256::from_str("f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9").unwrap());
let genesis = morden.genesis_block();
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap());
let _ = morden.to_engine();
}
#[test]
fn frontier() {
let frontier = new_frontier();
assert_eq!(frontier.state_root(), H256::from_str("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544").unwrap());
let genesis = frontier.genesis_block();
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap());
let _ = frontier.to_engine();
}
}

51
src/evm/evm.rs Normal file
View File

@@ -0,0 +1,51 @@
//! Evm interface.
use common::*;
use evm::Ext;
/// Evm errors.
#[derive(Debug)]
pub enum Error {
/// `OutOfGas` is returned when transaction execution runs out of gas.
/// The state should be reverted to the state from before the
/// transaction execution. But it does not mean that transaction
/// was invalid. Balance still should be transfered and nonce
/// should be increased.
OutOfGas,
/// `BadJumpDestination` is returned when execution tried to move
/// to position that wasn't marked with JUMPDEST instruction
BadJumpDestination {
destination: usize
},
/// `BadInstructions` is returned when given instruction is not supported
BadInstruction {
instruction: u8,
},
/// `StackUnderflow` when there is not enough stack elements to execute instruction
/// First parameter says how many elements were needed and the second how many were actually on Stack
StackUnderflow {
instruction: &'static str,
wanted: usize,
on_stack: usize
},
/// When execution would exceed defined Stack Limit
OutOfStack {
instruction: &'static str,
wanted: usize,
limit: usize
},
/// Returned on evm internal error. Should never be ignored during development.
/// Likely to cause consensus issues.
Internal,
}
/// Evm result.
///
/// Returns gas_left if execution is successfull, otherwise error.
pub type Result = result::Result<U256, Error>;
/// Evm interface.
pub trait Evm {
/// This function should be used to execute transaction.
fn exec(&self, params: ActionParams, ext: &mut Ext) -> Result;
}

91
src/evm/ext.rs Normal file
View File

@@ -0,0 +1,91 @@
//! Interface for Evm externalities.
use common::Bytes;
use util::hash::*;
use util::uint::*;
use evm::{Schedule, Error};
use env_info::*;
/// Result of externalities create function.
pub enum ContractCreateResult {
/// Returned when creation was successfull.
/// Contains an address of newly created contract and gas left.
Created(Address, U256),
/// Returned when contract creation failed.
/// VM doesn't have to know the reason.
Failed
}
/// Result of externalities call function.
pub enum MessageCallResult {
/// Returned when message call was successfull.
/// Contains gas left.
Success(U256),
/// Returned when message call failed.
/// VM doesn't have to know the reason.
Failed
}
pub trait Ext {
/// Returns a value for given key.
fn storage_at(&self, key: &H256) -> H256;
/// Stores a value for given key.
fn set_storage(&mut self, key: H256, value: H256);
/// Determine whether an account exists.
fn exists(&self, address: &Address) -> bool;
/// Returns address balance.
fn balance(&self, address: &Address) -> U256;
/// Returns the hash of one of the 256 most recent complete blocks.
fn blockhash(&self, number: &U256) -> H256;
/// Creates new contract.
///
/// Returns gas_left and contract address if contract creation was succesfull.
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult;
/// Message call.
///
/// Returns Err, if we run out of gas.
/// Otherwise returns call_result which contains gas left
/// and true if subcall was successfull.
fn call(&mut self,
gas: &U256,
address: &Address,
value: &U256,
data: &[u8],
code_address: &Address,
output: &mut [u8]) -> MessageCallResult;
/// Returns code at given address
fn extcode(&self, address: &Address) -> Bytes;
/// Creates log entry with given topics and data
fn log(&mut self, topics: Vec<H256>, data: &[u8]);
/// Should be called when transaction calls `RETURN` opcode.
/// Returns gas_left if cost of returning the data is not too high.
fn ret(&mut self, gas: &U256, data: &[u8]) -> Result<U256, Error>;
/// Should be called when contract commits suicide.
/// Address to which funds should be refunded.
fn suicide(&mut self, refund_address: &Address);
/// Returns schedule.
fn schedule(&self) -> &Schedule;
/// Returns environment info.
fn env_info(&self) -> &EnvInfo;
/// Returns current depth of execution.
///
/// If contract A calls contract B, and contract B calls C,
/// then A depth is 0, B is 1, C is 2 and so on.
fn depth(&self) -> usize;
/// Increments sstore refunds count by 1.
fn inc_sstore_clears(&mut self);
}

123
src/evm/factory.rs Normal file
View File

@@ -0,0 +1,123 @@
//! Evm factory.
use std::fmt;
use evm::Evm;
#[derive(Clone)]
pub enum VMType {
Jit,
Interpreter
}
impl fmt::Display for VMType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", match *self {
VMType::Jit => "JIT",
VMType::Interpreter => "INT"
})
}
}
impl VMType {
/// Return all possible VMs (JIT, Interpreter)
#[cfg(feature="jit")]
pub fn all() -> Vec<VMType> {
vec![VMType::Jit, VMType::Interpreter]
}
/// Return all possible VMs (Interpreter)
#[cfg(not(feature="jit"))]
pub fn all() -> Vec<VMType> {
vec![VMType::Interpreter]
}
}
/// Evm factory. Creates appropriate Evm.
pub struct Factory {
evm : VMType
}
impl Factory {
/// Create fresh instance of VM
pub fn create(&self) -> Box<Evm> {
match self.evm {
VMType::Jit => {
Factory::jit()
},
VMType::Interpreter => {
Box::new(super::interpreter::Interpreter)
}
}
}
/// Create new instance of specific `VMType` factory
pub fn new(evm: VMType) -> Factory {
Factory {
evm: evm
}
}
#[cfg(feature = "jit")]
fn jit() -> Box<Evm> {
Box::new(super::jit::JitEvm)
}
#[cfg(not(feature = "jit"))]
fn jit() -> Box<Evm> {
unimplemented!()
}
/// Returns jitvm factory
#[cfg(feature = "jit")]
pub fn default() -> Factory {
Factory {
evm: VMType::Jit
}
}
/// Returns native rust evm factory
#[cfg(not(feature = "jit"))]
pub fn default() -> Factory {
Factory {
evm: VMType::Interpreter
}
}
}
#[test]
fn test_create_vm() {
let _vm = Factory::default().create();
}
/// Create tests by injecting different VM factories
#[macro_export]
macro_rules! evm_test(
($name_test: ident: $name_jit: ident, $name_int: ident) => {
#[test]
#[cfg(feature = "jit")]
fn $name_jit() {
$name_test(Factory::new(VMType::Jit));
}
#[test]
fn $name_int() {
$name_test(Factory::new(VMType::Interpreter));
}
}
);
/// Create ignored tests by injecting different VM factories
#[macro_export]
macro_rules! evm_test_ignore(
($name_test: ident: $name_jit: ident, $name_int: ident) => {
#[test]
#[ignore]
#[cfg(feature = "jit")]
fn $name_jit() {
$name_test(Factory::new(VMType::Jit));
}
#[test]
#[ignore]
fn $name_int() {
$name_test(Factory::new(VMType::Interpreter));
}
}
);

534
src/evm/instructions.rs Normal file
View File

@@ -0,0 +1,534 @@
//! VM Instructions list and utility functions
pub type Instruction = u8;
/// Returns true if given instruction is `PUSHN` instruction.
pub fn is_push(i: Instruction) -> bool {
i >= PUSH1 && i <= PUSH32
}
/// Returns number of bytes to read for `PUSHN` instruction
/// PUSH1 -> 1
pub fn get_push_bytes(i: Instruction) -> usize {
assert!(is_push(i), "Only for PUSH instructions.");
(i - PUSH1 + 1) as usize
}
#[test]
fn test_get_push_bytes() {
assert_eq!(get_push_bytes(PUSH1), 1);
assert_eq!(get_push_bytes(PUSH3), 3);
assert_eq!(get_push_bytes(PUSH32), 32);
}
/// Returns stack position of item to duplicate
/// DUP1 -> 0
pub fn get_dup_position(i: Instruction) -> usize {
assert!(i >= DUP1 && i <= DUP16);
(i - DUP1) as usize
}
#[test]
fn test_get_dup_position() {
assert_eq!(get_dup_position(DUP1), 0);
assert_eq!(get_dup_position(DUP5), 4);
assert_eq!(get_dup_position(DUP10), 9);
}
/// Returns stack position of item to SWAP top with
/// SWAP1 -> 1
pub fn get_swap_position(i: Instruction) -> usize {
assert!(i >= SWAP1 && i <= SWAP16);
(i - SWAP1 + 1) as usize
}
#[test]
fn test_get_swap_position() {
assert_eq!(get_swap_position(SWAP1), 1);
assert_eq!(get_swap_position(SWAP5), 5);
assert_eq!(get_swap_position(SWAP10), 10);
}
/// Returns number of topcis to take from stack
/// LOG0 -> 0
pub fn get_log_topics (i: Instruction) -> usize {
assert!(i >= LOG0 && i <= LOG4);
(i - LOG0) as usize
}
#[test]
fn test_get_log_topics() {
assert_eq!(get_log_topics(LOG0), 0);
assert_eq!(get_log_topics(LOG2), 2);
assert_eq!(get_log_topics(LOG4), 4);
}
#[derive(PartialEq)]
pub enum GasPriceTier {
/// 0 Zero
Zero,
/// 2 Quick
Base,
/// 3 Fastest
VeryLow,
/// 5 Fast
Low,
/// 8 Mid
Mid,
/// 10 Slow
High,
/// 20 Ext
Ext,
/// Multiparam or otherwise special
Special,
/// Invalid
Invalid
}
/// Returns the index in schedule for specific `GasPriceTier`
pub fn get_tier_idx (tier: GasPriceTier) -> usize {
match tier {
GasPriceTier::Zero => 0,
GasPriceTier::Base => 1,
GasPriceTier::VeryLow => 2,
GasPriceTier::Low => 3,
GasPriceTier::Mid => 4,
GasPriceTier::High => 5,
GasPriceTier::Ext => 6,
GasPriceTier::Special => 7,
GasPriceTier::Invalid => 8
}
}
pub struct InstructionInfo {
pub name: &'static str,
pub additional: usize,
pub args: usize,
pub ret: usize,
pub side_effects: bool,
pub tier: GasPriceTier
}
impl InstructionInfo {
pub fn new(name: &'static str, additional: usize, args: usize, ret: usize, side_effects: bool, tier: GasPriceTier) -> InstructionInfo {
InstructionInfo {
name: name,
additional: additional,
args: args,
ret: ret,
side_effects: side_effects,
tier: tier
}
}
}
/// Return details about specific instruction
pub fn get_info (instruction: Instruction) -> InstructionInfo {
match instruction {
STOP => InstructionInfo::new("STOP", 0, 0, 0, true, GasPriceTier::Zero),
ADD => InstructionInfo::new("ADD", 0, 2, 1, false, GasPriceTier::VeryLow),
SUB => InstructionInfo::new("SUB", 0, 2, 1, false, GasPriceTier::VeryLow),
MUL => InstructionInfo::new("MUL", 0, 2, 1, false, GasPriceTier::Low),
DIV => InstructionInfo::new("DIV", 0, 2, 1, false, GasPriceTier::Low),
SDIV => InstructionInfo::new("SDIV", 0, 2, 1, false, GasPriceTier::Low),
MOD => InstructionInfo::new("MOD", 0, 2, 1, false, GasPriceTier::Low),
SMOD => InstructionInfo::new("SMOD", 0, 2, 1, false, GasPriceTier::Low),
EXP => InstructionInfo::new("EXP", 0, 2, 1, false, GasPriceTier::Special),
NOT => InstructionInfo::new("NOT", 0, 1, 1, false, GasPriceTier::VeryLow),
LT => InstructionInfo::new("LT", 0, 2, 1, false, GasPriceTier::VeryLow),
GT => InstructionInfo::new("GT", 0, 2, 1, false, GasPriceTier::VeryLow),
SLT => InstructionInfo::new("SLT", 0, 2, 1, false, GasPriceTier::VeryLow),
SGT => InstructionInfo::new("SGT", 0, 2, 1, false, GasPriceTier::VeryLow),
EQ => InstructionInfo::new("EQ", 0, 2, 1, false, GasPriceTier::VeryLow),
ISZERO => InstructionInfo::new("ISZERO", 0, 1, 1, false, GasPriceTier::VeryLow),
AND => InstructionInfo::new("AND", 0, 2, 1, false, GasPriceTier::VeryLow),
OR => InstructionInfo::new("OR", 0, 2, 1, false, GasPriceTier::VeryLow),
XOR => InstructionInfo::new("XOR", 0, 2, 1, false, GasPriceTier::VeryLow),
BYTE => InstructionInfo::new("BYTE", 0, 2, 1, false, GasPriceTier::VeryLow),
ADDMOD => InstructionInfo::new("ADDMOD", 0, 3, 1, false, GasPriceTier::Mid),
MULMOD => InstructionInfo::new("MULMOD", 0, 3, 1, false, GasPriceTier::Mid),
SIGNEXTEND => InstructionInfo::new("SIGNEXTEND", 0, 2, 1, false, GasPriceTier::Low),
SHA3 => InstructionInfo::new("SHA3", 0, 2, 1, false, GasPriceTier::Special),
ADDRESS => InstructionInfo::new("ADDRESS", 0, 0, 1, false, GasPriceTier::Base),
BALANCE => InstructionInfo::new("BALANCE", 0, 1, 1, false, GasPriceTier::Ext),
ORIGIN => InstructionInfo::new("ORIGIN", 0, 0, 1, false, GasPriceTier::Base),
CALLER => InstructionInfo::new("CALLER", 0, 0, 1, false, GasPriceTier::Base),
CALLVALUE => InstructionInfo::new("CALLVALUE", 0, 0, 1, false, GasPriceTier::Base),
CALLDATALOAD => InstructionInfo::new("CALLDATALOAD", 0, 1, 1, false, GasPriceTier::VeryLow),
CALLDATASIZE => InstructionInfo::new("CALLDATASIZE", 0, 0, 1, false, GasPriceTier::Base),
CALLDATACOPY => InstructionInfo::new("CALLDATACOPY", 0, 3, 0, true, GasPriceTier::VeryLow),
CODESIZE => InstructionInfo::new("CODESIZE", 0, 0, 1, false, GasPriceTier::Base),
CODECOPY => InstructionInfo::new("CODECOPY", 0, 3, 0, true, GasPriceTier::VeryLow),
GASPRICE => InstructionInfo::new("GASPRICE", 0, 0, 1, false, GasPriceTier::Base),
EXTCODESIZE => InstructionInfo::new("EXTCODESIZE", 0, 1, 1, false, GasPriceTier::Ext),
EXTCODECOPY => InstructionInfo::new("EXTCODECOPY", 0, 4, 0, true, GasPriceTier::Ext),
BLOCKHASH => InstructionInfo::new("BLOCKHASH", 0, 1, 1, false, GasPriceTier::Ext),
COINBASE => InstructionInfo::new("COINBASE", 0, 0, 1, false, GasPriceTier::Base),
TIMESTAMP => InstructionInfo::new("TIMESTAMP", 0, 0, 1, false, GasPriceTier::Base),
NUMBER => InstructionInfo::new("NUMBER", 0, 0, 1, false, GasPriceTier::Base),
DIFFICULTY => InstructionInfo::new("DIFFICULTY", 0, 0, 1, false, GasPriceTier::Base),
GASLIMIT => InstructionInfo::new("GASLIMIT", 0, 0, 1, false, GasPriceTier::Base),
POP => InstructionInfo::new("POP", 0, 1, 0, false, GasPriceTier::Base),
MLOAD => InstructionInfo::new("MLOAD", 0, 1, 1, false, GasPriceTier::VeryLow),
MSTORE => InstructionInfo::new("MSTORE", 0, 2, 0, true, GasPriceTier::VeryLow),
MSTORE8 => InstructionInfo::new("MSTORE8", 0, 2, 0, true, GasPriceTier::VeryLow),
SLOAD => InstructionInfo::new("SLOAD", 0, 1, 1, false, GasPriceTier::Special),
SSTORE => InstructionInfo::new("SSTORE", 0, 2, 0, true, GasPriceTier::Special),
JUMP => InstructionInfo::new("JUMP", 0, 1, 0, true, GasPriceTier::Mid),
JUMPI => InstructionInfo::new("JUMPI", 0, 2, 0, true, GasPriceTier::High),
PC => InstructionInfo::new("PC", 0, 0, 1, false, GasPriceTier::Base),
MSIZE => InstructionInfo::new("MSIZE", 0, 0, 1, false, GasPriceTier::Base),
GAS => InstructionInfo::new("GAS", 0, 0, 1, false, GasPriceTier::Base),
JUMPDEST => InstructionInfo::new("JUMPDEST", 0, 0, 0, true, GasPriceTier::Special),
PUSH1 => InstructionInfo::new("PUSH1", 1, 0, 1, false, GasPriceTier::VeryLow),
PUSH2 => InstructionInfo::new("PUSH2", 2, 0, 1, false, GasPriceTier::VeryLow),
PUSH3 => InstructionInfo::new("PUSH3", 3, 0, 1, false, GasPriceTier::VeryLow),
PUSH4 => InstructionInfo::new("PUSH4", 4, 0, 1, false, GasPriceTier::VeryLow),
PUSH5 => InstructionInfo::new("PUSH5", 5, 0, 1, false, GasPriceTier::VeryLow),
PUSH6 => InstructionInfo::new("PUSH6", 6, 0, 1, false, GasPriceTier::VeryLow),
PUSH7 => InstructionInfo::new("PUSH7", 7, 0, 1, false, GasPriceTier::VeryLow),
PUSH8 => InstructionInfo::new("PUSH8", 8, 0, 1, false, GasPriceTier::VeryLow),
PUSH9 => InstructionInfo::new("PUSH9", 9, 0, 1, false, GasPriceTier::VeryLow),
PUSH10 => InstructionInfo::new("PUSH10", 10, 0, 1, false, GasPriceTier::VeryLow),
PUSH11 => InstructionInfo::new("PUSH11", 11, 0, 1, false, GasPriceTier::VeryLow),
PUSH12 => InstructionInfo::new("PUSH12", 12, 0, 1, false, GasPriceTier::VeryLow),
PUSH13 => InstructionInfo::new("PUSH13", 13, 0, 1, false, GasPriceTier::VeryLow),
PUSH14 => InstructionInfo::new("PUSH14", 14, 0, 1, false, GasPriceTier::VeryLow),
PUSH15 => InstructionInfo::new("PUSH15", 15, 0, 1, false, GasPriceTier::VeryLow),
PUSH16 => InstructionInfo::new("PUSH16", 16, 0, 1, false, GasPriceTier::VeryLow),
PUSH17 => InstructionInfo::new("PUSH17", 17, 0, 1, false, GasPriceTier::VeryLow),
PUSH18 => InstructionInfo::new("PUSH18", 18, 0, 1, false, GasPriceTier::VeryLow),
PUSH19 => InstructionInfo::new("PUSH19", 19, 0, 1, false, GasPriceTier::VeryLow),
PUSH20 => InstructionInfo::new("PUSH20", 20, 0, 1, false, GasPriceTier::VeryLow),
PUSH21 => InstructionInfo::new("PUSH21", 21, 0, 1, false, GasPriceTier::VeryLow),
PUSH22 => InstructionInfo::new("PUSH22", 22, 0, 1, false, GasPriceTier::VeryLow),
PUSH23 => InstructionInfo::new("PUSH23", 23, 0, 1, false, GasPriceTier::VeryLow),
PUSH24 => InstructionInfo::new("PUSH24", 24, 0, 1, false, GasPriceTier::VeryLow),
PUSH25 => InstructionInfo::new("PUSH25", 25, 0, 1, false, GasPriceTier::VeryLow),
PUSH26 => InstructionInfo::new("PUSH26", 26, 0, 1, false, GasPriceTier::VeryLow),
PUSH27 => InstructionInfo::new("PUSH27", 27, 0, 1, false, GasPriceTier::VeryLow),
PUSH28 => InstructionInfo::new("PUSH28", 28, 0, 1, false, GasPriceTier::VeryLow),
PUSH29 => InstructionInfo::new("PUSH29", 29, 0, 1, false, GasPriceTier::VeryLow),
PUSH30 => InstructionInfo::new("PUSH30", 30, 0, 1, false, GasPriceTier::VeryLow),
PUSH31 => InstructionInfo::new("PUSH31", 31, 0, 1, false, GasPriceTier::VeryLow),
PUSH32 => InstructionInfo::new("PUSH32", 32, 0, 1, false, GasPriceTier::VeryLow),
DUP1 => InstructionInfo::new("DUP1", 0, 1, 2, false, GasPriceTier::VeryLow),
DUP2 => InstructionInfo::new("DUP2", 0, 2, 3, false, GasPriceTier::VeryLow),
DUP3 => InstructionInfo::new("DUP3", 0, 3, 4, false, GasPriceTier::VeryLow),
DUP4 => InstructionInfo::new("DUP4", 0, 4, 5, false, GasPriceTier::VeryLow),
DUP5 => InstructionInfo::new("DUP5", 0, 5, 6, false, GasPriceTier::VeryLow),
DUP6 => InstructionInfo::new("DUP6", 0, 6, 7, false, GasPriceTier::VeryLow),
DUP7 => InstructionInfo::new("DUP7", 0, 7, 8, false, GasPriceTier::VeryLow),
DUP8 => InstructionInfo::new("DUP8", 0, 8, 9, false, GasPriceTier::VeryLow),
DUP9 => InstructionInfo::new("DUP9", 0, 9, 10, false, GasPriceTier::VeryLow),
DUP10 => InstructionInfo::new("DUP10", 0, 10, 11, false, GasPriceTier::VeryLow),
DUP11 => InstructionInfo::new("DUP11", 0, 11, 12, false, GasPriceTier::VeryLow),
DUP12 => InstructionInfo::new("DUP12", 0, 12, 13, false, GasPriceTier::VeryLow),
DUP13 => InstructionInfo::new("DUP13", 0, 13, 14, false, GasPriceTier::VeryLow),
DUP14 => InstructionInfo::new("DUP14", 0, 14, 15, false, GasPriceTier::VeryLow),
DUP15 => InstructionInfo::new("DUP15", 0, 15, 16, false, GasPriceTier::VeryLow),
DUP16 => InstructionInfo::new("DUP16", 0, 16, 17, false, GasPriceTier::VeryLow),
SWAP1 => InstructionInfo::new("SWAP1", 0, 2, 2, false, GasPriceTier::VeryLow),
SWAP2 => InstructionInfo::new("SWAP2", 0, 3, 3, false, GasPriceTier::VeryLow),
SWAP3 => InstructionInfo::new("SWAP3", 0, 4, 4, false, GasPriceTier::VeryLow),
SWAP4 => InstructionInfo::new("SWAP4", 0, 5, 5, false, GasPriceTier::VeryLow),
SWAP5 => InstructionInfo::new("SWAP5", 0, 6, 6, false, GasPriceTier::VeryLow),
SWAP6 => InstructionInfo::new("SWAP6", 0, 7, 7, false, GasPriceTier::VeryLow),
SWAP7 => InstructionInfo::new("SWAP7", 0, 8, 8, false, GasPriceTier::VeryLow),
SWAP8 => InstructionInfo::new("SWAP8", 0, 9, 9, false, GasPriceTier::VeryLow),
SWAP9 => InstructionInfo::new("SWAP9", 0, 10, 10, false, GasPriceTier::VeryLow),
SWAP10 => InstructionInfo::new("SWAP10", 0, 11, 11, false, GasPriceTier::VeryLow),
SWAP11 => InstructionInfo::new("SWAP11", 0, 12, 12, false, GasPriceTier::VeryLow),
SWAP12 => InstructionInfo::new("SWAP12", 0, 13, 13, false, GasPriceTier::VeryLow),
SWAP13 => InstructionInfo::new("SWAP13", 0, 14, 14, false, GasPriceTier::VeryLow),
SWAP14 => InstructionInfo::new("SWAP14", 0, 15, 15, false, GasPriceTier::VeryLow),
SWAP15 => InstructionInfo::new("SWAP15", 0, 16, 16, false, GasPriceTier::VeryLow),
SWAP16 => InstructionInfo::new("SWAP16", 0, 17, 17, false, GasPriceTier::VeryLow),
LOG0 => InstructionInfo::new("LOG0", 0, 2, 0, true, GasPriceTier::Special),
LOG1 => InstructionInfo::new("LOG1", 0, 3, 0, true, GasPriceTier::Special),
LOG2 => InstructionInfo::new("LOG2", 0, 4, 0, true, GasPriceTier::Special),
LOG3 => InstructionInfo::new("LOG3", 0, 5, 0, true, GasPriceTier::Special),
LOG4 => InstructionInfo::new("LOG4", 0, 6, 0, true, GasPriceTier::Special),
CREATE => InstructionInfo::new("CREATE", 0, 3, 1, true, GasPriceTier::Special),
CALL => InstructionInfo::new("CALL", 0, 7, 1, true, GasPriceTier::Special),
CALLCODE => InstructionInfo::new("CALLCODE", 0, 7, 1, true, GasPriceTier::Special),
RETURN => InstructionInfo::new("RETURN", 0, 2, 0, true, GasPriceTier::Zero),
DELEGATECALL => InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special),
SUICIDE => InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Zero),
_ => InstructionInfo::new("INVALID_INSTRUCTION", 0, 0, 0, false, GasPriceTier::Invalid)
}
}
/// Virtual machine bytecode instruction.
/// halts execution
pub const STOP: Instruction = 0x00;
/// addition operation
pub const ADD: Instruction = 0x01;
/// mulitplication operation
pub const MUL: Instruction = 0x02;
/// subtraction operation
pub const SUB: Instruction = 0x03;
/// integer division operation
pub const DIV: Instruction = 0x04;
/// signed integer division operation
pub const SDIV: Instruction = 0x05;
/// modulo remainder operation
pub const MOD: Instruction = 0x06;
/// signed modulo remainder operation
pub const SMOD: Instruction = 0x07;
/// unsigned modular addition
pub const ADDMOD: Instruction = 0x08;
/// unsigned modular multiplication
pub const MULMOD: Instruction = 0x09;
/// exponential operation
pub const EXP: Instruction = 0x0a;
/// extend length of signed integer
pub const SIGNEXTEND: Instruction = 0x0b;
/// less-than comparision
pub const LT: Instruction = 0x10;
/// greater-than comparision
pub const GT: Instruction = 0x11;
/// signed less-than comparision
pub const SLT: Instruction = 0x12;
/// signed greater-than comparision
pub const SGT: Instruction = 0x13;
/// equality comparision
pub const EQ: Instruction = 0x14;
/// simple not operator
pub const ISZERO: Instruction = 0x15;
/// bitwise AND operation
pub const AND: Instruction = 0x16;
/// bitwise OR operation
pub const OR: Instruction = 0x17;
/// bitwise XOR operation
pub const XOR: Instruction = 0x18;
/// bitwise NOT opertation
pub const NOT: Instruction = 0x19;
/// retrieve single byte from word
pub const BYTE: Instruction = 0x1a;
/// compute SHA3-256 hash
pub const SHA3: Instruction = 0x20;
/// get address of currently executing account
pub const ADDRESS: Instruction = 0x30;
/// get balance of the given account
pub const BALANCE: Instruction = 0x31;
/// get execution origination address
pub const ORIGIN: Instruction = 0x32;
/// get caller address
pub const CALLER: Instruction = 0x33;
/// get deposited value by the instruction/transaction responsible for this execution
pub const CALLVALUE: Instruction = 0x34;
/// get input data of current environment
pub const CALLDATALOAD: Instruction = 0x35;
/// get size of input data in current environment
pub const CALLDATASIZE: Instruction = 0x36;
/// copy input data in current environment to memory
pub const CALLDATACOPY: Instruction = 0x37;
/// get size of code running in current environment
pub const CODESIZE: Instruction = 0x38;
/// copy code running in current environment to memory
pub const CODECOPY: Instruction = 0x39;
/// get price of gas in current environment
pub const GASPRICE: Instruction = 0x3a;
/// get external code size (from another contract)
pub const EXTCODESIZE: Instruction = 0x3b;
/// copy external code (from another contract)
pub const EXTCODECOPY: Instruction = 0x3c;
/// get hash of most recent complete block
pub const BLOCKHASH: Instruction = 0x40;
/// get the block's coinbase address
pub const COINBASE: Instruction = 0x41;
/// get the block's timestamp
pub const TIMESTAMP: Instruction = 0x42;
/// get the block's number
pub const NUMBER: Instruction = 0x43;
/// get the block's difficulty
pub const DIFFICULTY: Instruction = 0x44;
/// get the block's gas limit
pub const GASLIMIT: Instruction = 0x45;
/// remove item from stack
pub const POP: Instruction = 0x50;
/// load word from memory
pub const MLOAD: Instruction = 0x51;
/// save word to memory
pub const MSTORE: Instruction = 0x52;
/// save byte to memory
pub const MSTORE8: Instruction = 0x53;
/// load word from storage
pub const SLOAD: Instruction = 0x54;
/// save word to storage
pub const SSTORE: Instruction = 0x55;
/// alter the program counter
pub const JUMP: Instruction = 0x56;
/// conditionally alter the program counter
pub const JUMPI: Instruction = 0x57;
/// get the program counter
pub const PC: Instruction = 0x58;
/// get the size of active memory
pub const MSIZE: Instruction = 0x59;
/// get the amount of available gas
pub const GAS: Instruction = 0x5a;
/// set a potential jump destination
pub const JUMPDEST: Instruction = 0x5b;
/// place 1 byte item on stack
pub const PUSH1: Instruction = 0x60;
/// place 2 byte item on stack
pub const PUSH2: Instruction = 0x61;
/// place 3 byte item on stack
pub const PUSH3: Instruction = 0x62;
/// place 4 byte item on stack
pub const PUSH4: Instruction = 0x63;
/// place 5 byte item on stack
pub const PUSH5: Instruction = 0x64;
/// place 6 byte item on stack
pub const PUSH6: Instruction = 0x65;
/// place 7 byte item on stack
pub const PUSH7: Instruction = 0x66;
/// place 8 byte item on stack
pub const PUSH8: Instruction = 0x67;
/// place 9 byte item on stack
pub const PUSH9: Instruction = 0x68;
/// place 10 byte item on stack
pub const PUSH10: Instruction = 0x69;
/// place 11 byte item on stack
pub const PUSH11: Instruction = 0x6a;
/// place 12 byte item on stack
pub const PUSH12: Instruction = 0x6b;
/// place 13 byte item on stack
pub const PUSH13: Instruction = 0x6c;
/// place 14 byte item on stack
pub const PUSH14: Instruction = 0x6d;
/// place 15 byte item on stack
pub const PUSH15: Instruction = 0x6e;
/// place 16 byte item on stack
pub const PUSH16: Instruction = 0x6f;
/// place 17 byte item on stack
pub const PUSH17: Instruction = 0x70;
/// place 18 byte item on stack
pub const PUSH18: Instruction = 0x71;
/// place 19 byte item on stack
pub const PUSH19: Instruction = 0x72;
/// place 20 byte item on stack
pub const PUSH20: Instruction = 0x73;
/// place 21 byte item on stack
pub const PUSH21: Instruction = 0x74;
/// place 22 byte item on stack
pub const PUSH22: Instruction = 0x75;
/// place 23 byte item on stack
pub const PUSH23: Instruction = 0x76;
/// place 24 byte item on stack
pub const PUSH24: Instruction = 0x77;
/// place 25 byte item on stack
pub const PUSH25: Instruction = 0x78;
/// place 26 byte item on stack
pub const PUSH26: Instruction = 0x79;
/// place 27 byte item on stack
pub const PUSH27: Instruction = 0x7a;
/// place 28 byte item on stack
pub const PUSH28: Instruction = 0x7b;
/// place 29 byte item on stack
pub const PUSH29: Instruction = 0x7c;
/// place 30 byte item on stack
pub const PUSH30: Instruction = 0x7d;
/// place 31 byte item on stack
pub const PUSH31: Instruction = 0x7e;
/// place 32 byte item on stack
pub const PUSH32: Instruction = 0x7f;
/// copies the highest item in the stack to the top of the stack
pub const DUP1: Instruction = 0x80;
/// copies the second highest item in the stack to the top of the stack
pub const DUP2: Instruction = 0x81;
/// copies the third highest item in the stack to the top of the stack
pub const DUP3: Instruction = 0x82;
/// copies the 4th highest item in the stack to the top of the stack
pub const DUP4: Instruction = 0x83;
/// copies the 5th highest item in the stack to the top of the stack
pub const DUP5: Instruction = 0x84;
/// copies the 6th highest item in the stack to the top of the stack
pub const DUP6: Instruction = 0x85;
/// copies the 7th highest item in the stack to the top of the stack
pub const DUP7: Instruction = 0x86;
/// copies the 8th highest item in the stack to the top of the stack
pub const DUP8: Instruction = 0x87;
/// copies the 9th highest item in the stack to the top of the stack
pub const DUP9: Instruction = 0x88;
/// copies the 10th highest item in the stack to the top of the stack
pub const DUP10: Instruction = 0x89;
/// copies the 11th highest item in the stack to the top of the stack
pub const DUP11: Instruction = 0x8a;
/// copies the 12th highest item in the stack to the top of the stack
pub const DUP12: Instruction = 0x8b;
/// copies the 13th highest item in the stack to the top of the stack
pub const DUP13: Instruction = 0x8c;
/// copies the 14th highest item in the stack to the top of the stack
pub const DUP14: Instruction = 0x8d;
/// copies the 15th highest item in the stack to the top of the stack
pub const DUP15: Instruction = 0x8e;
/// copies the 16th highest item in the stack to the top of the stack
pub const DUP16: Instruction = 0x8f;
/// swaps the highest and second highest value on the stack
pub const SWAP1: Instruction = 0x90;
/// swaps the highest and third highest value on the stack
pub const SWAP2: Instruction = 0x91;
/// swaps the highest and 4th highest value on the stack
pub const SWAP3: Instruction = 0x92;
/// swaps the highest and 5th highest value on the stack
pub const SWAP4: Instruction = 0x93;
/// swaps the highest and 6th highest value on the stack
pub const SWAP5: Instruction = 0x94;
/// swaps the highest and 7th highest value on the stack
pub const SWAP6: Instruction = 0x95;
/// swaps the highest and 8th highest value on the stack
pub const SWAP7: Instruction = 0x96;
/// swaps the highest and 9th highest value on the stack
pub const SWAP8: Instruction = 0x97;
/// swaps the highest and 10th highest value on the stack
pub const SWAP9: Instruction = 0x98;
/// swaps the highest and 11th highest value on the stack
pub const SWAP10: Instruction = 0x99;
/// swaps the highest and 12th highest value on the stack
pub const SWAP11: Instruction = 0x9a;
/// swaps the highest and 13th highest value on the stack
pub const SWAP12: Instruction = 0x9b;
/// swaps the highest and 14th highest value on the stack
pub const SWAP13: Instruction = 0x9c;
/// swaps the highest and 15th highest value on the stack
pub const SWAP14: Instruction = 0x9d;
/// swaps the highest and 16th highest value on the stack
pub const SWAP15: Instruction = 0x9e;
/// swaps the highest and 17th highest value on the stack
pub const SWAP16: Instruction = 0x9f;
/// Makes a log entry; no topics.
pub const LOG0: Instruction = 0xa0;
/// Makes a log entry; 1 topic.
pub const LOG1: Instruction = 0xa1;
/// Makes a log entry; 2 topics.
pub const LOG2: Instruction = 0xa2;
/// Makes a log entry; 3 topics.
pub const LOG3: Instruction = 0xa3;
/// Makes a log entry; 4 topics.
pub const LOG4: Instruction = 0xa4;
/// Maximal number of topics for log instructions
pub const MAX_NO_OF_TOPICS : usize = 4;
/// create a new account with associated code
pub const CREATE: Instruction = 0xf0;
/// message-call into an account
pub const CALL: Instruction = 0xf1;
/// message-call with another account's code only
pub const CALLCODE: Instruction = 0xf2;
/// halt execution returning output data
pub const RETURN: Instruction = 0xf3;
/// like CALLCODE but keeps caller's value and sender
pub const DELEGATECALL: Instruction = 0xf4;
/// halt execution and register account for later deletion
pub const SUICIDE: Instruction = 0xff;

1210
src/evm/interpreter.rs Normal file

File diff suppressed because it is too large Load Diff

363
src/evm/jit.rs Normal file
View File

@@ -0,0 +1,363 @@
//! Just in time compiler execution environment.
use common::*;
use evmjit;
use evm;
/// Should be used to convert jit types to ethcore
trait FromJit<T>: Sized {
fn from_jit(input: T) -> Self;
}
/// Should be used to covert ethcore types to jit
trait IntoJit<T> {
fn into_jit(self) -> T;
}
impl<'a> FromJit<&'a evmjit::I256> for U256 {
fn from_jit(input: &'a evmjit::I256) -> Self {
unsafe {
let mut res: U256 = mem::uninitialized();
ptr::copy(input.words.as_ptr(), res.0.as_mut_ptr(), 4);
res
}
}
}
impl<'a> FromJit<&'a evmjit::I256> for H256 {
fn from_jit(input: &'a evmjit::I256) -> Self {
let u = U256::from_jit(input);
H256::from(&u)
}
}
impl<'a> FromJit<&'a evmjit::I256> for Address {
fn from_jit(input: &'a evmjit::I256) -> Self {
Address::from(H256::from_jit(input))
}
}
impl<'a> FromJit<&'a evmjit::H256> for H256 {
fn from_jit(input: &'a evmjit::H256) -> Self {
H256::from_jit(&evmjit::I256::from(input.clone()))
}
}
impl<'a> FromJit<&'a evmjit::H256> for Address {
fn from_jit(input: &'a evmjit::H256) -> Self {
Address::from(H256::from_jit(input))
}
}
impl IntoJit<evmjit::I256> for U256 {
fn into_jit(self) -> evmjit::I256 {
unsafe {
let mut res: evmjit::I256 = mem::uninitialized();
ptr::copy(self.0.as_ptr(), res.words.as_mut_ptr(), 4);
res
}
}
}
impl IntoJit<evmjit::I256> for H256 {
fn into_jit(self) -> evmjit::I256 {
let mut ret = [0; 4];
for i in 0..self.bytes().len() {
let rev = self.bytes().len() - 1 - i;
let pos = rev / 8;
ret[pos] += (self.bytes()[i] as u64) << (rev % 8) * 8;
}
evmjit::I256 { words: ret }
}
}
impl IntoJit<evmjit::H256> for H256 {
fn into_jit(self) -> evmjit::H256 {
let i: evmjit::I256 = self.into_jit();
From::from(i)
}
}
impl IntoJit<evmjit::I256> for Address {
fn into_jit(self) -> evmjit::I256 {
H256::from(self).into_jit()
}
}
impl IntoJit<evmjit::H256> for Address {
fn into_jit(self) -> evmjit::H256 {
H256::from(self).into_jit()
}
}
/// Externalities adapter. Maps callbacks from evmjit to externalities trait.
///
/// Evmjit doesn't have to know about children execution failures.
/// This adapter 'catches' them and moves upstream.
struct ExtAdapter<'a> {
ext: &'a mut evm::Ext,
address: Address
}
impl<'a> ExtAdapter<'a> {
fn new(ext: &'a mut evm::Ext, address: Address) -> Self {
ExtAdapter {
ext: ext,
address: address
}
}
}
impl<'a> evmjit::Ext for ExtAdapter<'a> {
fn sload(&self, key: *const evmjit::I256, out_value: *mut evmjit::I256) {
unsafe {
let i = H256::from_jit(&*key);
let o = self.ext.storage_at(&i);
*out_value = o.into_jit();
}
}
fn sstore(&mut self, key: *const evmjit::I256, value: *const evmjit::I256) {
let key = unsafe { H256::from_jit(&*key) };
let value = unsafe { H256::from_jit(&*value) };
let old_value = self.ext.storage_at(&key);
// if SSTORE nonzero -> zero, increment refund count
if !old_value.is_zero() && value.is_zero() {
self.ext.inc_sstore_clears();
}
self.ext.set_storage(key, value);
}
fn balance(&self, address: *const evmjit::H256, out_value: *mut evmjit::I256) {
unsafe {
let a = Address::from_jit(&*address);
let o = self.ext.balance(&a);
*out_value = o.into_jit();
}
}
fn blockhash(&self, number: *const evmjit::I256, out_hash: *mut evmjit::H256) {
unsafe {
let n = U256::from_jit(&*number);
let o = self.ext.blockhash(&n);
*out_hash = o.into_jit();
}
}
fn create(&mut self,
io_gas: *mut u64,
value: *const evmjit::I256,
init_beg: *const u8,
init_size: u64,
address: *mut evmjit::H256) {
let gas = unsafe { U256::from(*io_gas) };
let value = unsafe { U256::from_jit(&*value) };
let code = unsafe { slice::from_raw_parts(init_beg, init_size as usize) };
// check if balance is sufficient and we are not too deep
if self.ext.balance(&self.address) >= value && self.ext.depth() < self.ext.schedule().max_depth {
match self.ext.create(&gas, &value, code) {
evm::ContractCreateResult::Created(new_address, gas_left) => unsafe {
*address = new_address.into_jit();
*io_gas = gas_left.low_u64();
},
evm::ContractCreateResult::Failed => unsafe {
*address = Address::new().into_jit();
*io_gas = 0;
}
}
} else {
unsafe { *address = Address::new().into_jit(); }
}
}
fn call(&mut self,
io_gas: *mut u64,
call_gas: u64,
receive_address: *const evmjit::H256,
value: *const evmjit::I256,
in_beg: *const u8,
in_size: u64,
out_beg: *mut u8,
out_size: u64,
code_address: *const evmjit::H256) -> bool {
let mut gas = unsafe { U256::from(*io_gas) };
let mut call_gas = U256::from(call_gas);
let mut gas_cost = call_gas;
let receive_address = unsafe { Address::from_jit(&*receive_address) };
let code_address = unsafe { Address::from_jit(&*code_address) };
let value = unsafe { U256::from_jit(&*value) };
// receive address and code address are the same in normal calls
let is_callcode = receive_address != code_address;
if !is_callcode && !self.ext.exists(&code_address) {
gas_cost = gas_cost + U256::from(self.ext.schedule().call_new_account_gas);
}
if value > U256::zero() {
assert!(self.ext.schedule().call_value_transfer_gas > self.ext.schedule().call_stipend, "overflow possible");
gas_cost = gas_cost + U256::from(self.ext.schedule().call_value_transfer_gas);
call_gas = call_gas + U256::from(self.ext.schedule().call_stipend);
}
if gas_cost > gas {
unsafe {
*io_gas = -1i64 as u64;
return false;
}
}
gas = gas - gas_cost;
// check if balance is sufficient and we are not too deep
if self.ext.balance(&self.address) < value || self.ext.depth() >= self.ext.schedule().max_depth {
unsafe {
*io_gas = (gas + call_gas).low_u64();
return false;
}
}
match self.ext.call(&call_gas,
&receive_address,
&value,
unsafe { slice::from_raw_parts(in_beg, in_size as usize) },
&code_address,
unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) }) {
evm::MessageCallResult::Success(gas_left) => unsafe {
*io_gas = (gas + gas_left).low_u64();
true
},
evm::MessageCallResult::Failed => unsafe {
*io_gas = gas.low_u64();
false
}
}
}
fn log(&mut self,
beg: *const u8,
size: u64,
topic1: *const evmjit::H256,
topic2: *const evmjit::H256,
topic3: *const evmjit::H256,
topic4: *const evmjit::H256) {
unsafe {
let mut topics = vec![];
if !topic1.is_null() {
topics.push(H256::from_jit(&*topic1));
}
if !topic2.is_null() {
topics.push(H256::from_jit(&*topic2));
}
if !topic3.is_null() {
topics.push(H256::from_jit(&*topic3));
}
if !topic4.is_null() {
topics.push(H256::from_jit(&*topic4));
}
let bytes_ref: &[u8] = slice::from_raw_parts(beg, size as usize);
self.ext.log(topics, bytes_ref.to_vec());
}
}
fn extcode(&self, address: *const evmjit::H256, size: *mut u64) -> *const u8 {
unsafe {
let code = self.ext.extcode(&Address::from_jit(&*address));
*size = code.len() as u64;
let ptr = code.as_ptr();
mem::forget(code);
ptr
}
}
}
pub struct JitEvm;
impl evm::Evm for JitEvm {
fn exec(&self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result {
// Dirty hack. This is unsafe, but we interact with ffi, so it's justified.
let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, params.address.clone())) };
let mut ext_handle = evmjit::ExtHandle::new(ext_adapter);
assert!(params.gas <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63");
assert!(params.gas_price <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63");
let call_data = params.data.unwrap_or(vec![]);
let code = params.code.unwrap_or(vec![]);
let mut data = evmjit::RuntimeDataHandle::new();
data.gas = params.gas.low_u64() as i64;
data.gas_price = params.gas_price.low_u64() as i64;
data.call_data = call_data.as_ptr();
data.call_data_size = call_data.len() as u64;
mem::forget(call_data);
data.code = code.as_ptr();
data.code_size = code.len() as u64;
data.code_hash = code.sha3().into_jit();
mem::forget(code);
data.address = params.address.into_jit();
data.caller = params.sender.into_jit();
data.origin = params.origin.into_jit();
data.call_value = params.value.into_jit();
data.author = ext.env_info().author.clone().into_jit();
data.difficulty = ext.env_info().difficulty.into_jit();
data.gas_limit = ext.env_info().gas_limit.into_jit();
data.number = ext.env_info().number;
// don't really know why jit timestamp is int..
data.timestamp = ext.env_info().timestamp as i64;
let mut context = unsafe { evmjit::ContextHandle::new(data, &mut ext_handle) };
let res = context.exec();
match res {
evmjit::ReturnCode::Stop => Ok(U256::from(context.gas_left())),
evmjit::ReturnCode::Return => ext.ret(&U256::from(context.gas_left()), context.output_data()),
evmjit::ReturnCode::Suicide => {
ext.suicide(&Address::from_jit(&context.suicide_refund_address()));
Ok(U256::from(context.gas_left()))
},
evmjit::ReturnCode::OutOfGas => Err(evm::Error::OutOfGas),
_err => Err(evm::Error::Internal)
}
}
}
#[test]
fn test_to_and_from_u256() {
let u = U256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap();
let j = u.into_jit();
let u2 = U256::from_jit(&j);
assert_eq!(u, u2);
}
#[test]
fn test_to_and_from_h256() {
let h = H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap();
let j: ::evmjit::I256 = h.clone().into_jit();
let h2 = H256::from_jit(&j);
assert_eq!(h, h2);
let j: ::evmjit::H256 = h.clone().into_jit();
let h2 = H256::from_jit(&j);
assert_eq!(h, h2);
}
#[test]
fn test_to_and_from_address() {
let a = Address::from_str("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").unwrap();
let j: ::evmjit::I256 = a.clone().into_jit();
let a2 = Address::from_jit(&j);
assert_eq!(a, a2);
let j: ::evmjit::H256 = a.clone().into_jit();
let a2 = Address::from_jit(&j);
assert_eq!(a, a2);
}

20
src/evm/mod.rs Normal file
View File

@@ -0,0 +1,20 @@
//! Ethereum virtual machine.
pub mod ext;
pub mod evm;
pub mod interpreter;
#[macro_use]
pub mod factory;
pub mod schedule;
mod instructions;
#[cfg(feature = "jit" )]
mod jit;
#[cfg(test)]
mod tests;
pub use self::evm::{Evm, Error, Result};
pub use self::ext::{Ext, ContractCreateResult, MessageCallResult};
pub use self::factory::Factory;
pub use self::schedule::Schedule;
pub use self::factory::VMType;

84
src/evm/schedule.rs Normal file
View File

@@ -0,0 +1,84 @@
//! Cost schedule and other parameterisations for the EVM.
/// Definition of the cost schedule and other parameterisations for the EVM.
pub struct Schedule {
pub exceptional_failed_code_deposit: bool,
pub have_delegate_call: bool,
pub stack_limit: usize,
pub max_depth: usize,
pub tier_step_gas: [usize; 8],
pub exp_gas: usize,
pub exp_byte_gas: usize,
pub sha3_gas: usize,
pub sha3_word_gas: usize,
pub sload_gas: usize,
pub sstore_set_gas: usize,
pub sstore_reset_gas: usize,
pub sstore_refund_gas: usize,
pub jumpdest_gas: usize,
pub log_gas: usize,
pub log_data_gas: usize,
pub log_topic_gas: usize,
pub create_gas: usize,
pub call_gas: usize,
pub call_stipend: usize,
pub call_value_transfer_gas: usize,
pub call_new_account_gas: usize,
pub suicide_refund_gas: usize,
pub memory_gas: usize,
pub quad_coeff_div: usize,
pub create_data_gas: usize,
pub tx_gas: usize,
pub tx_create_gas: usize,
pub tx_data_zero_gas: usize,
pub tx_data_non_zero_gas: usize,
pub copy_gas: usize,
}
impl Schedule {
/// Schedule for the Frontier-era of the Ethereum main net.
pub fn new_frontier() -> Schedule {
Self::new(false, false, 21000)
}
/// Schedule for the Homestead-era of the Ethereum main net.
pub fn new_homestead() -> Schedule {
Self::new(true, true, 53000)
}
fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule {
Schedule{
exceptional_failed_code_deposit: efcd,
have_delegate_call: hdc,
stack_limit: 1024,
max_depth: 1024,
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
exp_gas: 10,
exp_byte_gas: 10,
sha3_gas: 30,
sha3_word_gas: 6,
sload_gas: 50,
sstore_set_gas: 20000,
sstore_reset_gas: 5000,
sstore_refund_gas: 15000,
jumpdest_gas: 1,
log_gas: 375,
log_data_gas: 8,
log_topic_gas: 375,
create_gas: 32000,
call_gas: 40,
call_stipend: 2300,
call_value_transfer_gas: 9000,
call_new_account_gas: 25000,
suicide_refund_gas: 24000,
memory_gas: 3,
quad_coeff_div: 512,
create_data_gas: 200,
tx_gas: 21000,
tx_create_gas: tcg,
tx_data_zero_gas: 4,
tx_data_non_zero_gas: 68,
copy_gas: 3,
}
}
}

473
src/evm/tests.rs Normal file
View File

@@ -0,0 +1,473 @@
use common::*;
use evm;
use evm::{Ext, Schedule, Factory, VMType, ContractCreateResult, MessageCallResult};
struct FakeLogEntry {
topics: Vec<H256>,
data: Bytes
}
/// Fake externalities test structure.
///
/// Can't do recursive calls.
#[derive(Default)]
struct FakeExt {
store: HashMap<H256, H256>,
_balances: HashMap<Address, U256>,
blockhashes: HashMap<U256, H256>,
codes: HashMap<Address, Bytes>,
logs: Vec<FakeLogEntry>,
_suicides: HashSet<Address>,
info: EnvInfo,
_schedule: Schedule
}
impl FakeExt {
fn new() -> Self {
FakeExt::default()
}
}
impl Default for Schedule {
fn default() -> Self {
Schedule::new_frontier()
}
}
impl Ext for FakeExt {
fn storage_at(&self, key: &H256) -> H256 {
self.store.get(key).unwrap_or(&H256::new()).clone()
}
fn set_storage(&mut self, key: H256, value: H256) {
self.store.insert(key, value);
}
fn exists(&self, _address: &Address) -> bool {
unimplemented!();
}
fn balance(&self, _address: &Address) -> U256 {
unimplemented!();
}
fn blockhash(&self, number: &U256) -> H256 {
self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
}
fn create(&mut self, _gas: &U256, _value: &U256, _code: &[u8]) -> ContractCreateResult {
unimplemented!();
}
fn call(&mut self,
_gas: &U256,
_address: &Address,
_value: &U256,
_data: &[u8],
_code_address: &Address,
_output: &mut [u8]) -> MessageCallResult {
unimplemented!();
}
fn extcode(&self, address: &Address) -> Bytes {
self.codes.get(address).unwrap_or(&Bytes::new()).clone()
}
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
self.logs.push(FakeLogEntry {
topics: topics,
data: data.to_vec()
});
}
fn ret(&mut self, _gas: &U256, _data: &[u8]) -> result::Result<U256, evm::Error> {
unimplemented!();
}
fn suicide(&mut self, _refund_address: &Address) {
unimplemented!();
}
fn schedule(&self) -> &Schedule {
&self._schedule
}
fn env_info(&self) -> &EnvInfo {
&self.info
}
fn depth(&self) -> usize {
unimplemented!();
}
fn inc_sstore_clears(&mut self) {
unimplemented!();
}
}
#[test]
fn test_stack_underflow() {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "01600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let err = {
let vm : Box<evm::Evm> = Box::new(super::interpreter::Interpreter);
vm.exec(params, &mut ext).unwrap_err()
};
match err {
evm::Error::StackUnderflow {instruction: _, wanted, on_stack} => {
assert_eq!(wanted, 2);
assert_eq!(on_stack, 0);
}
_ => {
assert!(false, "Expected StackUndeflow")
}
};
}
evm_test!{test_add: test_add_jit, test_add_int}
fn test_add(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_988));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe").unwrap());
}
evm_test!{test_sha3: test_sha3_jit, test_sha3_int}
fn test_sha3(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "6000600020600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_961));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap());
}
evm_test!{test_address: test_address_jit, test_address_int}
fn test_address(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "30600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap());
}
evm_test!{test_origin: test_origin_jit, test_origin_int}
fn test_origin(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let origin = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap();
let code = "32600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.origin = origin.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap());
}
evm_test!{test_sender: test_sender_jit, test_sender_int}
fn test_sender(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap();
let code = "33600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap());
}
evm_test!{test_extcodecopy: test_extcodecopy_jit, test_extcodecopy_int}
fn test_extcodecopy(factory: super::Factory) {
// 33 - sender
// 3b - extcodesize
// 60 00 - push 0
// 60 00 - push 0
// 33 - sender
// 3c - extcodecopy
// 60 00 - push 0
// 51 - load word from memory
// 60 00 - push 0
// 55 - sstore
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap();
let code = "333b60006000333c600051600055".from_hex().unwrap();
let sender_code = "6005600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
ext.codes.insert(sender, sender_code);
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_935));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("6005600055000000000000000000000000000000000000000000000000000000").unwrap());
}
evm_test!{test_log_empty: test_log_empty_jit, test_log_empty_int}
fn test_log_empty(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "60006000a0".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(99_619));
assert_eq!(ext.logs.len(), 1);
assert_eq!(ext.logs[0].topics.len(), 0);
assert_eq!(ext.logs[0].data, vec![]);
}
evm_test!{test_log_sender: test_log_sender_jit, test_log_sender_int}
fn test_log_sender(factory: super::Factory) {
// 60 ff - push ff
// 60 00 - push 00
// 53 - mstore
// 33 - sender
// 60 20 - push 20
// 60 00 - push 0
// a1 - log with 1 topic
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let code = "60ff6000533360206000a1".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(98_974));
assert_eq!(ext.logs.len(), 1);
assert_eq!(ext.logs[0].topics.len(), 1);
assert_eq!(ext.logs[0].topics[0], H256::from_str("000000000000000000000000cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
assert_eq!(ext.logs[0].data, "ff00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap());
}
evm_test!{test_blockhash: test_blockhash_jit, test_blockhash_int}
fn test_blockhash(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "600040600055".from_hex().unwrap();
let blockhash = H256::from_str("123400000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
ext.blockhashes.insert(U256::zero(), blockhash.clone());
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_974));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash);
}
evm_test!{test_calldataload: test_calldataload_jit, test_calldataload_int}
fn test_calldataload(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "600135600055".from_hex().unwrap();
let data = "0123ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23".from_hex().unwrap();
let mut params = ActionParams::new();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.data = Some(data);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_991));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23").unwrap());
}
evm_test!{test_author: test_author_jit, test_author_int}
fn test_author(factory: super::Factory) {
let author = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "41600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
ext.info.author = author;
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap());
}
evm_test!{test_timestamp: test_timestamp_jit, test_timestamp_int}
fn test_timestamp(factory: super::Factory) {
let timestamp = 0x1234;
let code = "42600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
ext.info.timestamp = timestamp;
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap());
}
evm_test!{test_number: test_number_jit, test_number_int}
fn test_number(factory: super::Factory) {
let number = 0x1234;
let code = "43600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
ext.info.number = number;
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap());
}
evm_test!{test_difficulty: test_difficulty_jit, test_difficulty_int}
fn test_difficulty(factory: super::Factory) {
let difficulty = U256::from(0x1234);
let code = "44600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
ext.info.difficulty = difficulty;
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap());
}
evm_test!{test_gas_limit: test_gas_limit_jit, test_gas_limit_int}
fn test_gas_limit(factory: super::Factory) {
let gas_limit = U256::from(0x1234);
let code = "45600055".from_hex().unwrap();
let mut params = ActionParams::new();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
ext.info.gas_limit = gas_limit;
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap());
}

819
src/executive.rs Normal file
View File

@@ -0,0 +1,819 @@
//! Transaction Execution environment.
use common::*;
use state::*;
use engine::*;
use evm::{self, Ext};
use externalities::*;
use substate::*;
/// Returns new address created from address and given nonce.
pub fn contract_address(address: &Address, nonce: &U256) -> Address {
let mut stream = RlpStream::new_list(2);
stream.append(address);
stream.append(nonce);
From::from(stream.out().sha3())
}
/// Transaction execution receipt.
#[derive(Debug)]
pub struct Executed {
/// Gas paid up front for execution of transaction.
pub gas: U256,
/// Gas used during execution of transaction.
pub gas_used: U256,
/// Gas refunded after the execution of transaction.
/// To get gas that was required up front, add `refunded` and `gas_used`.
pub refunded: U256,
/// Cumulative gas used in current block so far.
///
/// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)`
///
/// where `tn` is current transaction.
pub cumulative_gas_used: U256,
/// Vector of logs generated by transaction.
pub logs: Vec<LogEntry>,
/// Addresses of contracts created during execution of transaction.
/// Ordered from earliest creation.
///
/// eg. sender creates contract A and A in constructor creates contract B
///
/// B creation ends first, and it will be the first element of the vector.
pub contracts_created: Vec<Address>
}
/// Transaction execution result.
pub type ExecutionResult = Result<Executed, ExecutionError>;
/// Transaction executor.
pub struct Executive<'a> {
state: &'a mut State,
info: &'a EnvInfo,
engine: &'a Engine,
depth: usize
}
impl<'a> Executive<'a> {
/// Basic constructor.
pub fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine) -> Self {
Executive::new_with_depth(state, info, engine, 0)
}
/// Populates executive from parent properties. Increments executive depth.
pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self {
Executive::new_with_depth(state, info, engine, depth + 1)
}
/// Helper constructor. Should be used to create `Executive` with desired depth.
/// Private.
fn new_with_depth(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self {
Executive {
state: state,
info: info,
engine: engine,
depth: depth
}
}
/// Creates `Externalities` from `Executive`.
pub fn to_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_>) -> Externalities {
Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output)
}
/// This funtion should be used to execute transaction.
pub fn transact(&'a mut self, t: &Transaction) -> Result<Executed, Error> {
let sender = try!(t.sender());
let nonce = self.state.nonce(&sender);
let schedule = self.engine.schedule(self.info);
let base_gas_required = U256::from(t.gas_required(&schedule));
if t.gas < base_gas_required {
return Err(From::from(ExecutionError::NotEnoughBaseGas { required: base_gas_required, got: t.gas }));
}
let init_gas = t.gas - base_gas_required;
// validate transaction nonce
if t.nonce != nonce {
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }));
}
// validate if transaction fits into given block
if self.info.gas_used + t.gas > self.info.gas_limit {
return Err(From::from(ExecutionError::BlockGasLimitReached {
gas_limit: self.info.gas_limit,
gas_used: self.info.gas_used,
gas: t.gas
}));
}
// TODO: we might need bigints here, or at least check overflows.
let balance = self.state.balance(&sender);
let gas_cost = U512::from(t.gas) * U512::from(t.gas_price);
let total_cost = U512::from(t.value) + gas_cost;
// avoid unaffordable transactions
if U512::from(balance) < total_cost {
return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, got: U512::from(balance) }));
}
// NOTE: there can be no invalid transactions from this point.
self.state.inc_nonce(&sender);
self.state.sub_balance(&sender, &U256::from(gas_cost));
let mut substate = Substate::new();
let res = match t.action() {
&Action::Create => {
let new_address = contract_address(&sender, &nonce);
let params = ActionParams {
code_address: new_address.clone(),
address: new_address,
sender: sender.clone(),
origin: sender.clone(),
gas: init_gas,
gas_price: t.gas_price,
value: t.value,
code: Some(t.data.clone()),
data: None,
};
self.create(params, &mut substate)
},
&Action::Call(ref address) => {
let params = ActionParams {
code_address: address.clone(),
address: address.clone(),
sender: sender.clone(),
origin: sender.clone(),
gas: init_gas,
gas_price: t.gas_price,
value: t.value,
code: self.state.code(address),
data: Some(t.data.clone()),
};
// TODO: move output upstream
let mut out = vec![];
self.call(params, &mut substate, BytesRef::Flexible(&mut out))
}
};
// finalize here!
Ok(try!(self.finalize(t, substate, res)))
}
/// Calls contract function with given contract params.
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
/// Modifies the substate and the output.
/// Returns either gas_left or `evm::Error`.
pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result {
// backup used in case of running out of gas
let backup = self.state.clone();
// at first, transfer value to destination
self.state.transfer_balance(&params.sender, &params.address, &params.value);
debug!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
if self.engine.is_builtin(&params.code_address) {
// if destination is builtin, try to execute it
let default = [];
let data = if let &Some(ref d) = &params.data { d as &[u8] } else { &default as &[u8] };
let cost = self.engine.cost_of_builtin(&params.code_address, data);
match cost <= params.gas {
true => {
self.engine.execute_builtin(&params.code_address, data, &mut output);
Ok(params.gas - cost)
},
// just drain the whole gas
false => {
self.state.revert(backup);
Err(evm::Error::OutOfGas)
}
}
} else if params.code.is_some() {
// if destination is a contract, do normal message call
// part of substate that may be reverted
let mut unconfirmed_substate = Substate::new();
let res = {
let mut ext = self.to_externalities(OriginInfo::from(&params), &mut unconfirmed_substate, OutputPolicy::Return(output));
self.engine.vm_factory().create().exec(params, &mut ext)
};
trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count);
trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
self.enact_result(&res, substate, unconfirmed_substate, backup);
trace!("exec: new substate={:?}\n", substate);
res
} else {
// otherwise, nothing
Ok(params.gas)
}
}
/// Creates contract with given contract params.
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
/// Modifies the substate.
pub fn create(&mut self, params: ActionParams, substate: &mut Substate) -> evm::Result {
// backup used in case of running out of gas
let backup = self.state.clone();
// part of substate that may be reverted
let mut unconfirmed_substate = Substate::new();
// at first create new contract
self.state.new_contract(&params.address);
// then transfer value to it
self.state.transfer_balance(&params.sender, &params.address, &params.value);
let res = {
let mut ext = self.to_externalities(OriginInfo::from(&params), &mut unconfirmed_substate, OutputPolicy::InitContract);
self.engine.vm_factory().create().exec(params, &mut ext)
};
self.enact_result(&res, substate, unconfirmed_substate, backup);
res
}
/// Finalizes the transaction (does refunds and suicides).
fn finalize(&mut self, t: &Transaction, substate: Substate, result: evm::Result) -> ExecutionResult {
let schedule = self.engine.schedule(self.info);
// refunds from SSTORE nonzero -> zero
let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.sstore_clears_count;
// refunds from contract suicides
let suicide_refunds = U256::from(schedule.suicide_refund_gas) * U256::from(substate.suicides.len());
let refunds_bound = sstore_refunds + suicide_refunds;
// real ammount to refund
let gas_left_prerefund = match &result { &Ok(x) => x, _ => x!(0) };
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) / U256::from(2));
let gas_left = gas_left_prerefund + refunded;
let gas_used = t.gas - gas_left;
let refund_value = gas_left * t.gas_price;
let fees_value = gas_used * t.gas_price;
trace!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n",
t.gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value);
trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, t.sender().unwrap());
self.state.add_balance(&t.sender().unwrap(), &refund_value);
trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author);
self.state.add_balance(&self.info.author, &fees_value);
// perform suicides
for address in substate.suicides.iter() {
trace!("Killing {}", address);
self.state.kill_account(address);
}
match result {
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
// TODO [ToDr] BadJumpDestination @debris - how to handle that?
Err(evm::Error::OutOfGas)
| Err(evm::Error::BadJumpDestination { destination: _ })
| Err(evm::Error::BadInstruction { instruction: _ })
| Err(evm::Error::StackUnderflow {instruction: _, wanted: _, on_stack: _})
| Err(evm::Error::OutOfStack {instruction: _, wanted: _, limit: _}) => {
Ok(Executed {
gas: t.gas,
gas_used: t.gas,
refunded: U256::zero(),
cumulative_gas_used: self.info.gas_used + t.gas,
logs: vec![],
contracts_created: vec![]
})
},
_ => {
Ok(Executed {
gas: t.gas,
gas_used: gas_used,
refunded: refunded,
cumulative_gas_used: self.info.gas_used + gas_used,
logs: substate.logs,
contracts_created: substate.contracts_created,
})
},
}
}
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, backup: State) {
// TODO: handle other evm::Errors same as OutOfGas once they are implemented
match result {
&Err(evm::Error::OutOfGas)
| &Err(evm::Error::BadJumpDestination { destination: _ })
| &Err(evm::Error::BadInstruction { instruction: _ })
| &Err(evm::Error::StackUnderflow {instruction: _, wanted: _, on_stack: _})
| &Err(evm::Error::OutOfStack {instruction: _, wanted: _, limit: _}) => {
self.state.revert(backup);
},
&Ok(_) | &Err(evm::Error::Internal) => substate.accrue(un_substate)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use common::*;
use state::*;
use ethereum;
use engine::*;
use spec::*;
use evm::{Schedule, Factory, VMType};
use substate::*;
struct TestEngine {
factory: Factory,
spec: Spec,
max_depth: usize
}
impl TestEngine {
fn new(max_depth: usize, factory: Factory) -> TestEngine {
TestEngine {
factory: factory,
spec: ethereum::new_frontier_test(),
max_depth: max_depth
}
}
}
impl Engine for TestEngine {
fn name(&self) -> &str { "TestEngine" }
fn spec(&self) -> &Spec { &self.spec }
fn vm_factory(&self) -> &Factory {
&self.factory
}
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
let mut schedule = Schedule::new_frontier();
schedule.max_depth = self.max_depth;
schedule
}
}
#[test]
fn test_contract_address() {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let expected_address = Address::from_str("3f09c73a5ed19289fb9bdc72f1742566df146f56").unwrap();
assert_eq!(expected_address, contract_address(&address, &U256::from(88)));
}
// TODO: replace params with transactions!
evm_test!{test_sender_balance: test_sender_balance_jit, test_sender_balance_int}
fn test_sender_balance(factory: Factory) {
let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let address = contract_address(&sender, &U256::zero());
let mut params = ActionParams::new();
params.address = address.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some("3331600055".from_hex().unwrap());
params.value = U256::from(0x7);
let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(0x100u64));
let info = EnvInfo::new();
let engine = TestEngine::new(0, factory);
let mut substate = Substate::new();
let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate).unwrap()
};
assert_eq!(gas_left, U256::from(79_975));
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0xf9u64)));
assert_eq!(state.balance(&sender), U256::from(0xf9));
assert_eq!(state.balance(&address), U256::from(0x7));
// 0 cause contract hasn't returned
assert_eq!(substate.contracts_created.len(), 0);
// TODO: just test state root.
}
evm_test!{test_create_contract: test_create_contract_jit, test_create_contract_int}
fn test_create_contract(factory: Factory) {
// code:
//
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
// 60 00 - push 0
// 52
// 60 1d - push 29
// 60 03 - push 3
// 60 17 - push 17
// f0 - create
// 60 00 - push 0
// 55 sstore
//
// other code:
//
// 60 10 - push 16
// 80 - duplicate first stack item
// 60 0c - push 12
// 60 00 - push 0
// 39 - copy current code to memory
// 60 00 - push 0
// f3 - return
let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055".from_hex().unwrap();
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let address = contract_address(&sender, &U256::zero());
// TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &U256::zero());
let mut params = ActionParams::new();
params.address = address.clone();
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.value = U256::from(100);
let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(100));
let info = EnvInfo::new();
let engine = TestEngine::new(0, factory);
let mut substate = Substate::new();
let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate).unwrap()
};
assert_eq!(gas_left, U256::from(62_976));
// ended with max depth
assert_eq!(substate.contracts_created.len(), 0);
}
evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_jit, test_create_contract_value_too_high_int}
fn test_create_contract_value_too_high(factory: Factory) {
// code:
//
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
// 60 00 - push 0
// 52
// 60 1d - push 29
// 60 03 - push 3
// 60 e6 - push 230
// f0 - create a contract trying to send 230.
// 60 00 - push 0
// 55 sstore
//
// other code:
//
// 60 10 - push 16
// 80 - duplicate first stack item
// 60 0c - push 12
// 60 00 - push 0
// 39 - copy current code to memory
// 60 00 - push 0
// f3 - return
let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d600360e6f0600055".from_hex().unwrap();
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let address = contract_address(&sender, &U256::zero());
// TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &U256::zero());
let mut params = ActionParams::new();
params.address = address.clone();
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.value = U256::from(100);
let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(100));
let info = EnvInfo::new();
let engine = TestEngine::new(0, factory);
let mut substate = Substate::new();
let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate).unwrap()
};
assert_eq!(gas_left, U256::from(62_976));
assert_eq!(substate.contracts_created.len(), 0);
}
evm_test!{test_create_contract_without_max_depth: test_create_contract_without_max_depth_jit, test_create_contract_without_max_depth_int}
fn test_create_contract_without_max_depth(factory: Factory) {
// code:
//
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
// 60 00 - push 0
// 52
// 60 1d - push 29
// 60 03 - push 3
// 60 17 - push 17
// f0 - create
// 60 00 - push 0
// 55 sstore
//
// other code:
//
// 60 10 - push 16
// 80 - duplicate first stack item
// 60 0c - push 12
// 60 00 - push 0
// 39 - copy current code to memory
// 60 00 - push 0
// f3 - return
let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0".from_hex().unwrap();
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let address = contract_address(&sender, &U256::zero());
let next_address = contract_address(&address, &U256::zero());
let mut params = ActionParams::new();
params.address = address.clone();
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.value = U256::from(100);
let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(100));
let info = EnvInfo::new();
let engine = TestEngine::new(1024, factory);
let mut substate = Substate::new();
{
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate).unwrap();
}
assert_eq!(substate.contracts_created.len(), 1);
assert_eq!(substate.contracts_created[0], next_address);
}
// test is incorrect, mk
evm_test_ignore!{test_aba_calls: test_aba_calls_jit, test_aba_calls_int}
fn test_aba_calls(factory: Factory) {
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 18 - push 18
// 73 945304eb96065b2a98b57a48a06ae28d285a71b5 - push this address
// 61 03e8 - push 1000
// f1 - message call
// 58 - get PC
// 55 - sstore
let code_a = "6000600060006000601873945304eb96065b2a98b57a48a06ae28d285a71b56103e8f15855".from_hex().unwrap();
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 17 - push 17
// 73 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 - push this address
// 61 0x01f4 - push 500
// f1 - message call
// 60 01 - push 1
// 01 - add
// 58 - get PC
// 55 - sstore
let code_b = "60006000600060006017730f572e5295c57f15886f9b263e2f6d2d6c7b5ec66101f4f16001015855".from_hex().unwrap();
let address_a = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let address_b = Address::from_str("945304eb96065b2a98b57a48a06ae28d285a71b5" ).unwrap();
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let mut params = ActionParams::new();
params.address = address_a.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code_a.clone());
params.value = U256::from(100_000);
let mut state = State::new_temp();
state.init_code(&address_a, code_a.clone());
state.init_code(&address_b, code_b.clone());
state.add_balance(&sender, &U256::from(100_000));
let info = EnvInfo::new();
let engine = TestEngine::new(0, factory);
let mut substate = Substate::new();
let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.call(params, &mut substate, BytesRef::Fixed(&mut [])).unwrap()
};
assert_eq!(gas_left, U256::from(73_237));
assert_eq!(state.storage_at(&address_a, &H256::from(&U256::from(0x23))), H256::from(&U256::from(1)));
}
// test is incorrect, mk
evm_test_ignore!{test_recursive_bomb1: test_recursive_bomb1_jit, test_recursive_bomb1_int}
fn test_recursive_bomb1(factory: Factory) {
// 60 01 - push 1
// 60 00 - push 0
// 54 - sload
// 01 - add
// 60 00 - push 0
// 55 - sstore
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 30 - load address
// 60 e0 - push e0
// 5a - get gas
// 03 - sub
// f1 - message call (self in this case)
// 60 01 - push 1
// 55 - sstore
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let code = "600160005401600055600060006000600060003060e05a03f1600155".from_hex().unwrap();
let address = contract_address(&sender, &U256::zero());
let mut params = ActionParams::new();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
let mut state = State::new_temp();
state.init_code(&address, code.clone());
let info = EnvInfo::new();
let engine = TestEngine::new(0, factory);
let mut substate = Substate::new();
let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.call(params, &mut substate, BytesRef::Fixed(&mut [])).unwrap()
};
assert_eq!(gas_left, U256::from(59_870));
assert_eq!(state.storage_at(&address, &H256::from(&U256::zero())), H256::from(&U256::from(1)));
assert_eq!(state.storage_at(&address, &H256::from(&U256::one())), H256::from(&U256::from(1)));
}
// test is incorrect, mk
evm_test_ignore!{test_transact_simple: test_transact_simple_jit, test_transact_simple_int}
fn test_transact_simple(factory: Factory) {
let mut t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::zero(), U256::zero());
let keypair = KeyPair::create().unwrap();
t.sign(&keypair.secret());
let sender = t.sender().unwrap();
let contract = contract_address(&sender, &U256::zero());
let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(18));
let mut info = EnvInfo::new();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0, factory);
let executed = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t).unwrap()
};
assert_eq!(executed.gas, U256::from(100_000));
assert_eq!(executed.gas_used, U256::from(41_301));
assert_eq!(executed.refunded, U256::from(58_699));
assert_eq!(executed.cumulative_gas_used, U256::from(41_301));
assert_eq!(executed.logs.len(), 0);
assert_eq!(executed.contracts_created.len(), 0);
assert_eq!(state.balance(&sender), U256::from(1));
assert_eq!(state.balance(&contract), U256::from(17));
assert_eq!(state.nonce(&sender), U256::from(1));
assert_eq!(state.storage_at(&contract, &H256::new()), H256::from(&U256::from(1)));
}
evm_test!{test_transact_invalid_sender: test_transact_invalid_sender_jit, test_transact_invalid_sender_int}
fn test_transact_invalid_sender(factory: Factory) {
let t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::zero(), U256::zero());
let mut state = State::new_temp();
let mut info = EnvInfo::new();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0, factory);
let res = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t)
};
match res {
Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))) => (),
_ => assert!(false, "Expected invalid signature error.")
}
}
evm_test!{test_transact_invalid_nonce: test_transact_invalid_nonce_jit, test_transact_invalid_nonce_int}
fn test_transact_invalid_nonce(factory: Factory) {
let mut t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::zero(), U256::one());
let keypair = KeyPair::create().unwrap();
t.sign(&keypair.secret());
let sender = t.sender().unwrap();
let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(17));
let mut info = EnvInfo::new();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0, factory);
let res = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t)
};
match res {
Err(Error::Execution(ExecutionError::InvalidNonce { expected, got }))
if expected == U256::zero() && got == U256::one() => (),
_ => assert!(false, "Expected invalid nonce error.")
}
}
evm_test!{test_transact_gas_limit_reached: test_transact_gas_limit_reached_jit, test_transact_gas_limit_reached_int}
fn test_transact_gas_limit_reached(factory: Factory) {
let mut t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(80_001), U256::zero(), U256::zero());
let keypair = KeyPair::create().unwrap();
t.sign(&keypair.secret());
let sender = t.sender().unwrap();
let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(17));
let mut info = EnvInfo::new();
info.gas_used = U256::from(20_000);
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0, factory);
let res = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t)
};
match res {
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas }))
if gas_limit == U256::from(100_000) && gas_used == U256::from(20_000) && gas == U256::from(80_001) => (),
_ => assert!(false, "Expected block gas limit error.")
}
}
evm_test!{test_not_enough_cash: test_not_enough_cash_jit, test_not_enough_cash_int}
fn test_not_enough_cash(factory: Factory) {
let mut t = Transaction::new_create(U256::from(18), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::one(), U256::zero());
let keypair = KeyPair::create().unwrap();
t.sign(&keypair.secret());
let sender = t.sender().unwrap();
let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(100_017));
let mut info = EnvInfo::new();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0, factory);
let res = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t)
};
match res {
Err(Error::Execution(ExecutionError::NotEnoughCash { required , got }))
if required == U512::from(100_018) && got == U512::from(100_017) => (),
_ => assert!(false, "Expected not enough cash error. {:?}", res)
}
}
evm_test!{test_sha3: test_sha3_jit, test_sha3_int}
fn test_sha3(factory: Factory) {
let code = "6064640fffffffff20600055".from_hex().unwrap();
let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let address = contract_address(&sender, &U256::zero());
// TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &U256::zero());
let mut params = ActionParams::new();
params.address = address.clone();
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(0x0186a0);
params.code = Some(code.clone());
params.value = U256::from_str("0de0b6b3a7640000").unwrap();
let mut state = State::new_temp();
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap());
let info = EnvInfo::new();
let engine = TestEngine::new(0, factory);
let mut substate = Substate::new();
let result = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate)
};
match result {
Err(_) => {
},
_ => {
panic!("Expected OutOfGas");
}
}
}
}

226
src/externalities.rs Normal file
View File

@@ -0,0 +1,226 @@
//! Transaction Execution environment.
use common::*;
use state::*;
use engine::*;
use executive::*;
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult};
use substate::*;
/// Policy for handling output data on `RETURN` opcode.
pub enum OutputPolicy<'a> {
/// Return reference to fixed sized output.
/// Used for message calls.
Return(BytesRef<'a>),
/// Init new contract as soon as `RETURN` is called.
InitContract
}
/// Transaction properties that externalities need to know about.
pub struct OriginInfo {
address: Address,
origin: Address,
gas_price: U256
}
impl OriginInfo {
/// Populates origin info from action params.
pub fn from(params: &ActionParams) -> Self {
OriginInfo {
address: params.address.clone(),
origin: params.origin.clone(),
gas_price: params.gas_price.clone()
}
}
}
/// Implementation of evm Externalities.
pub struct Externalities<'a> {
state: &'a mut State,
env_info: &'a EnvInfo,
engine: &'a Engine,
depth: usize,
origin_info: OriginInfo,
substate: &'a mut Substate,
schedule: Schedule,
output: OutputPolicy<'a>
}
impl<'a> Externalities<'a> {
/// Basic `Externalities` constructor.
pub fn new(state: &'a mut State,
env_info: &'a EnvInfo,
engine: &'a Engine,
depth: usize,
origin_info: OriginInfo,
substate: &'a mut Substate,
output: OutputPolicy<'a>) -> Self {
Externalities {
state: state,
env_info: env_info,
engine: engine,
depth: depth,
origin_info: origin_info,
substate: substate,
schedule: engine.schedule(env_info),
output: output
}
}
}
impl<'a> Ext for Externalities<'a> {
fn storage_at(&self, key: &H256) -> H256 {
self.state.storage_at(&self.origin_info.address, key)
}
fn set_storage(&mut self, key: H256, value: H256) {
self.state.set_storage(&self.origin_info.address, key, value)
}
fn exists(&self, address: &Address) -> bool {
self.state.exists(address)
}
fn balance(&self, address: &Address) -> U256 {
self.state.balance(address)
}
fn blockhash(&self, number: &U256) -> H256 {
match *number < U256::from(self.env_info.number) && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 {
true => {
let index = self.env_info.number - number.low_u64() - 1;
let r = self.env_info.last_hashes[index as usize].clone();
trace!("ext: blockhash({}) -> {} self.env_info.number={}\n", number, r, self.env_info.number);
r
},
false => {
trace!("ext: blockhash({}) -> null self.env_info.number={}\n", number, self.env_info.number);
H256::from(&U256::zero())
},
}
}
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult {
// create new contract address
let address = contract_address(&self.origin_info.address, &self.state.nonce(&self.origin_info.address));
// prepare the params
let params = ActionParams {
code_address: address.clone(),
address: address.clone(),
sender: self.origin_info.address.clone(),
origin: self.origin_info.origin.clone(),
gas: *gas,
gas_price: self.origin_info.gas_price.clone(),
value: value.clone(),
code: Some(code.to_vec()),
data: None,
};
self.state.inc_nonce(&self.origin_info.address);
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
// TODO: handle internal error separately
match ex.create(params, self.substate) {
Ok(gas_left) => {
self.substate.contracts_created.push(address.clone());
ContractCreateResult::Created(address, gas_left)
},
_ => ContractCreateResult::Failed
}
}
fn call(&mut self,
gas: &U256,
address: &Address,
value: &U256,
data: &[u8],
code_address: &Address,
output: &mut [u8]) -> MessageCallResult {
let params = ActionParams {
code_address: code_address.clone(),
address: address.clone(),
sender: self.origin_info.address.clone(),
origin: self.origin_info.origin.clone(),
gas: *gas,
gas_price: self.origin_info.gas_price.clone(),
value: value.clone(),
code: self.state.code(code_address),
data: Some(data.to_vec()),
};
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
match ex.call(params, self.substate, BytesRef::Fixed(output)) {
Ok(gas_left) => MessageCallResult::Success(gas_left),
_ => MessageCallResult::Failed
}
}
fn extcode(&self, address: &Address) -> Bytes {
self.state.code(address).unwrap_or(vec![])
}
fn ret(&mut self, gas: &U256, data: &[u8]) -> Result<U256, evm::Error> {
match &mut self.output {
&mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe {
let len = cmp::min(slice.len(), data.len());
ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len);
Ok(*gas)
},
&mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe {
vec.clear();
vec.reserve(data.len());
ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len());
vec.set_len(data.len());
Ok(*gas)
},
&mut OutputPolicy::InitContract => {
let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas);
if return_cost > *gas {
return match self.schedule.exceptional_failed_code_deposit {
true => Err(evm::Error::OutOfGas),
false => Ok(*gas)
}
}
let mut code = vec![];
code.reserve(data.len());
unsafe {
ptr::copy(data.as_ptr(), code.as_mut_ptr(), data.len());
code.set_len(data.len());
}
let address = &self.origin_info.address;
self.state.init_code(address, code);
Ok(*gas - return_cost)
}
}
}
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
let address = self.origin_info.address.clone();
self.substate.logs.push(LogEntry::new(address, topics, data.to_vec()));
}
fn suicide(&mut self, refund_address: &Address) {
let address = self.origin_info.address.clone();
let balance = self.balance(&address);
self.state.transfer_balance(&address, refund_address, &balance);
self.substate.suicides.insert(address);
}
fn schedule(&self) -> &Schedule {
&self.schedule
}
fn env_info(&self) -> &EnvInfo {
&self.env_info
}
fn depth(&self) -> usize {
self.depth
}
fn inc_sstore_clears(&mut self) {
self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one();
}
}

257
src/extras.rs Normal file
View File

@@ -0,0 +1,257 @@
use util::*;
use header::BlockNumber;
use rocksdb::{DB, Writable};
/// Represents index of extra data in database
#[derive(Copy, Clone)]
pub enum ExtrasIndex {
BlockDetails = 0,
BlockHash = 1,
TransactionAddress = 2,
BlockLogBlooms = 3,
BlocksBlooms = 4
}
/// trait used to write Extras data to db
pub trait ExtrasWritable {
fn put_extras<K, T>(&self, hash: &K, value: &T) where
T: ExtrasIndexable + Encodable,
K: ExtrasSliceConvertable;
}
/// trait used to read Extras data from db
pub trait ExtrasReadable {
fn get_extras<K, T>(&self, hash: &K) -> Option<T> where
T: ExtrasIndexable + Decodable,
K: ExtrasSliceConvertable;
fn extras_exists<K, T>(&self, hash: &K) -> bool where
T: ExtrasIndexable,
K: ExtrasSliceConvertable;
}
impl<W> ExtrasWritable for W where W: Writable {
fn put_extras<K, T>(&self, hash: &K, value: &T) where
T: ExtrasIndexable + Encodable,
K: ExtrasSliceConvertable {
self.put(&hash.to_extras_slice(T::extras_index()), &encode(value)).unwrap()
}
}
impl ExtrasReadable for DB {
fn get_extras<K, T>(&self, hash: &K) -> Option<T> where
T: ExtrasIndexable + Decodable,
K: ExtrasSliceConvertable {
self.get(&hash.to_extras_slice(T::extras_index())).unwrap()
.map(|v| decode(&v))
}
fn extras_exists<K, T>(&self, hash: &K) -> bool where
T: ExtrasIndexable,
K: ExtrasSliceConvertable {
self.get(&hash.to_extras_slice(T::extras_index())).unwrap().is_some()
}
}
/// Implementations should convert arbitrary type to database key slice
pub trait ExtrasSliceConvertable {
fn to_extras_slice(&self, i: ExtrasIndex) -> H264;
}
impl ExtrasSliceConvertable for H256 {
fn to_extras_slice(&self, i: ExtrasIndex) -> H264 {
let mut slice = H264::from_slice(self);
slice[32] = i as u8;
slice
}
}
impl ExtrasSliceConvertable for U256 {
fn to_extras_slice(&self, i: ExtrasIndex) -> H264 {
H256::from(self).to_extras_slice(i)
}
}
// NICE: make less horrible.
impl ExtrasSliceConvertable for BlockNumber {
fn to_extras_slice(&self, i: ExtrasIndex) -> H264 {
U256::from(*self).to_extras_slice(i)
}
}
/// Types implementing this trait can be indexed in extras database
pub trait ExtrasIndexable {
fn extras_index() -> ExtrasIndex;
}
impl ExtrasIndexable for H256 {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::BlockHash
}
}
/// Familial details concerning a block
#[derive(Debug, Clone)]
pub struct BlockDetails {
pub number: BlockNumber,
pub total_difficulty: U256,
pub parent: H256,
pub children: Vec<H256>
}
impl ExtrasIndexable for BlockDetails {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::BlockDetails
}
}
impl HeapSizeOf for BlockDetails {
fn heap_size_of_children(&self) -> usize {
self.children.heap_size_of_children()
}
}
impl Decodable for BlockDetails {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = try!(decoder.as_list());
let details = BlockDetails {
number: try!(Decodable::decode(&d[0])),
total_difficulty: try!(Decodable::decode(&d[1])),
parent: try!(Decodable::decode(&d[2])),
children: try!(Decodable::decode(&d[3]))
};
Ok(details)
}
}
impl Encodable for BlockDetails {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
encoder.emit_list(| e | {
self.number.encode(e);
self.total_difficulty.encode(e);
self.parent.encode(e);
self.children.encode(e);
})
}
}
/// Log blooms of certain block
#[derive(Clone)]
pub struct BlockLogBlooms {
pub blooms: Vec<H2048>
}
impl ExtrasIndexable for BlockLogBlooms {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::BlockLogBlooms
}
}
impl HeapSizeOf for BlockLogBlooms {
fn heap_size_of_children(&self) -> usize {
self.blooms.heap_size_of_children()
}
}
impl Decodable for BlockLogBlooms {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let block_blooms = BlockLogBlooms {
blooms: try!(Decodable::decode(decoder))
};
Ok(block_blooms)
}
}
impl Encodable for BlockLogBlooms {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
self.blooms.encode(encoder);
}
}
/// Neighboring log blooms on certain level
pub struct BlocksBlooms {
pub blooms: [H2048; 16]
}
impl ExtrasIndexable for BlocksBlooms {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::BlocksBlooms
}
}
impl HeapSizeOf for BlocksBlooms {
fn heap_size_of_children(&self) -> usize { 0 }
}
impl Clone for BlocksBlooms {
fn clone(&self) -> Self {
let mut blooms: [H2048; 16] = unsafe { ::std::mem::uninitialized() };
for i in 0..self.blooms.len() {
blooms[i] = self.blooms[i].clone();
}
BlocksBlooms {
blooms: blooms
}
}
}
impl Decodable for BlocksBlooms {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let blocks_blooms = BlocksBlooms {
blooms: try!(Decodable::decode(decoder))
};
Ok(blocks_blooms)
}
}
impl Encodable for BlocksBlooms {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
let blooms_ref: &[H2048] = &self.blooms;
blooms_ref.encode(encoder);
}
}
/// Represents address of certain transaction within block
#[derive(Clone)]
pub struct TransactionAddress {
pub block_hash: H256,
pub index: u64
}
impl ExtrasIndexable for TransactionAddress {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::TransactionAddress
}
}
impl HeapSizeOf for TransactionAddress {
fn heap_size_of_children(&self) -> usize { 0 }
}
impl Decodable for TransactionAddress {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = try!(decoder.as_list());
let tx_address = TransactionAddress {
block_hash: try!(Decodable::decode(&d[0])),
index: try!(Decodable::decode(&d[1]))
};
Ok(tx_address)
}
}
impl Encodable for TransactionAddress {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
encoder.emit_list(| e | {
self.block_hash.encode(e);
self.index.encode(e);
})
}
}

View File

@@ -1,12 +0,0 @@
use standard::*;
#[macro_export]
macro_rules! xjson {
( $x:expr ) => {
FromJson::from_json($x)
}
}
pub trait FromJson {
fn from_json(json: &Json) -> Self;
}

View File

@@ -1,614 +0,0 @@
//! General hash types, a fixed-size raw-data type used as the output of hash functions.
use standard::*;
use math::log2;
use error::UtilError;
use rand::Rng;
use rand::os::OsRng;
use bytes::{BytesConvertable,Populatable};
use from_json::*;
use uint::{Uint, U256};
/// Trait for a fixed-size byte array to be used as the output of hash functions.
///
/// Note: types implementing `FixedHash` must be also `BytesConvertable`.
pub trait FixedHash: Sized + BytesConvertable + Populatable + FromStr + Default {
fn new() -> Self;
/// Synonym for `new()`. Prefer to new as it's more readable.
fn zero() -> Self;
fn random() -> Self;
fn randomize(&mut self);
fn size() -> usize;
fn from_slice(src: &[u8]) -> Self;
fn clone_from_slice(&mut self, src: &[u8]) -> usize;
fn copy_to(&self, dest: &mut [u8]);
fn shift_bloomed<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash;
fn with_bloomed<T>(mut self, b: &T) -> Self where T: FixedHash { self.shift_bloomed(b); self }
fn bloom_part<T>(&self, m: usize) -> T where T: FixedHash;
fn contains_bloomed<T>(&self, b: &T) -> bool where T: FixedHash;
fn contains<'a>(&'a self, b: &'a Self) -> bool;
fn is_zero(&self) -> bool;
}
fn clean_0x(s: &str) -> &str {
if s.len() >= 2 && &s[0..2] == "0x" {
&s[2..]
} else {
s
}
}
macro_rules! impl_hash {
($from: ident, $size: expr) => {
#[derive(Eq)]
pub struct $from (pub [u8; $size]);
impl BytesConvertable for $from {
fn bytes(&self) -> &[u8] {
&self.0
}
}
impl Deref for $from {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
&self.0
}
}
impl DerefMut for $from {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl FixedHash for $from {
fn new() -> $from {
$from([0; $size])
}
fn zero() -> $from {
$from([0; $size])
}
fn random() -> $from {
let mut hash = $from::new();
hash.randomize();
hash
}
fn randomize(&mut self) {
let mut rng = OsRng::new().unwrap();
rng.fill_bytes(&mut self.0);
}
fn size() -> usize {
$size
}
// TODO: remove once slice::clone_from_slice is stable
#[inline]
fn clone_from_slice(&mut self, src: &[u8]) -> usize {
let min = ::std::cmp::min($size, src.len());
let dst = &mut self.deref_mut()[.. min];
let src = &src[.. min];
for i in 0..min {
dst[i] = src[i];
}
min
}
fn from_slice(src: &[u8]) -> Self {
let mut r = Self::new();
r.clone_from_slice(src);
r
}
fn copy_to(&self, dest: &mut[u8]) {
unsafe {
let min = ::std::cmp::min($size, dest.len());
::std::ptr::copy(self.0.as_ptr(), dest.as_mut_ptr(), min);
}
}
fn shift_bloomed<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash {
let bp: Self = b.bloom_part($size);
let new_self = &bp | self;
// impl |= instead
// TODO: that's done now!
unsafe {
use std::{mem, ptr};
ptr::copy(new_self.0.as_ptr(), self.0.as_mut_ptr(), mem::size_of::<Self>());
}
self
}
fn bloom_part<T>(&self, m: usize) -> T where T: FixedHash {
// numbers of bits
// TODO: move it to some constant
let p = 3;
let bloom_bits = m * 8;
let mask = bloom_bits - 1;
let bloom_bytes = (log2(bloom_bits) + 7) / 8;
//println!("bb: {}", bloom_bytes);
// must be a power of 2
assert_eq!(m & (m - 1), 0);
// out of range
assert!(p * bloom_bytes <= $size);
// return type
let mut ret = T::new();
// 'ptr' to out slice
let mut ptr = 0;
// set p number of bits,
// p is equal 3 according to yellowpaper
for _ in 0..p {
let mut index = 0 as usize;
for _ in 0..bloom_bytes {
index = (index << 8) | self.0[ptr] as usize;
ptr += 1;
}
index &= mask;
ret.as_slice_mut()[m - 1 - index / 8] |= 1 << (index % 8);
}
ret
}
fn contains_bloomed<T>(&self, b: &T) -> bool where T: FixedHash {
let bp: Self = b.bloom_part($size);
self.contains(&bp)
}
fn contains<'a>(&'a self, b: &'a Self) -> bool {
&(b & self) == b
}
fn is_zero(&self) -> bool {
self.eq(&Self::new())
}
}
impl FromStr for $from {
type Err = UtilError;
fn from_str(s: &str) -> Result<$from, UtilError> {
let a = try!(s.from_hex());
if a.len() != $size { return Err(UtilError::BadSize); }
let mut ret = $from([0;$size]);
for i in 0..$size {
ret.0[i] = a[i];
}
Ok(ret)
}
}
impl FromJson for $from {
fn from_json(json: &Json) -> Self {
match json {
&Json::String(ref s) => {
match s.len() % 2 {
0 => FromStr::from_str(clean_0x(s)).unwrap(),
_ => FromStr::from_str(&("0".to_string() + &(clean_0x(s).to_string()))[..]).unwrap()
}
},
_ => Default::default(),
}
}
}
impl fmt::Debug for $from {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in self.0.iter() {
try!(write!(f, "{:02x}", i));
}
Ok(())
}
}
impl fmt::Display for $from {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in self.0[0..3].iter() {
try!(write!(f, "{:02x}", i));
}
write!(f, "…{:02x}", self.0.last().unwrap())
}
}
impl Clone for $from {
fn clone(&self) -> $from {
unsafe {
use std::{mem, ptr};
let mut ret: $from = mem::uninitialized();
ptr::copy(self.0.as_ptr(), ret.0.as_mut_ptr(), mem::size_of::<$from>());
ret
}
}
}
impl PartialEq for $from {
fn eq(&self, other: &Self) -> bool {
for i in 0..$size {
if self.0[i] != other.0[i] {
return false;
}
}
true
}
}
impl Ord for $from {
fn cmp(&self, other: &Self) -> Ordering {
for i in 0..$size {
if self.0[i] > other.0[i] {
return Ordering::Greater;
} else if self.0[i] < other.0[i] {
return Ordering::Less;
}
}
Ordering::Equal
}
}
impl PartialOrd for $from {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for $from {
fn hash<H>(&self, state: &mut H) where H: Hasher {
state.write(&self.0);
state.finish();
}
}
impl Index<usize> for $from {
type Output = u8;
fn index<'a>(&'a self, index: usize) -> &'a u8 {
&self.0[index]
}
}
impl IndexMut<usize> for $from {
fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut u8 {
&mut self.0[index]
}
}
impl Index<ops::Range<usize>> for $from {
type Output = [u8];
fn index<'a>(&'a self, index: ops::Range<usize>) -> &'a [u8] {
&self.0[index]
}
}
impl IndexMut<ops::Range<usize>> for $from {
fn index_mut<'a>(&'a mut self, index: ops::Range<usize>) -> &'a mut [u8] {
&mut self.0[index]
}
}
impl Index<ops::RangeFull> for $from {
type Output = [u8];
fn index<'a>(&'a self, _index: ops::RangeFull) -> &'a [u8] {
&self.0
}
}
impl IndexMut<ops::RangeFull> for $from {
fn index_mut<'a>(&'a mut self, _index: ops::RangeFull) -> &'a mut [u8] {
&mut self.0
}
}
/// BitOr on references
impl<'a> BitOr for &'a $from {
type Output = $from;
fn bitor(self, rhs: Self) -> Self::Output {
unsafe {
use std::mem;
let mut ret: $from = mem::uninitialized();
for i in 0..$size {
ret.0[i] = self.0[i] | rhs.0[i];
}
ret
}
}
}
/// Moving BitOr
impl BitOr for $from {
type Output = $from;
fn bitor(self, rhs: Self) -> Self::Output {
&self | &rhs
}
}
/// Moving BitOrAssign
impl<'a> BitOrAssign<&'a $from> for $from {
fn bitor_assign(&mut self, rhs: &'a Self) {
for i in 0..$size {
self.0[i] = self.0[i] | rhs.0[i];
}
}
}
/// BitAnd on references
impl <'a> BitAnd for &'a $from {
type Output = $from;
fn bitand(self, rhs: Self) -> Self::Output {
unsafe {
use std::mem;
let mut ret: $from = mem::uninitialized();
for i in 0..$size {
ret.0[i] = self.0[i] & rhs.0[i];
}
ret
}
}
}
/// Moving BitAnd
impl BitAnd for $from {
type Output = $from;
fn bitand(self, rhs: Self) -> Self::Output {
&self & &rhs
}
}
/// BitXor on references
impl <'a> BitXor for &'a $from {
type Output = $from;
fn bitxor(self, rhs: Self) -> Self::Output {
unsafe {
use std::mem;
let mut ret: $from = mem::uninitialized();
for i in 0..$size {
ret.0[i] = self.0[i] ^ rhs.0[i];
}
ret
}
}
}
/// Moving BitXor
impl BitXor for $from {
type Output = $from;
fn bitxor(self, rhs: Self) -> Self::Output {
&self ^ &rhs
}
}
impl $from {
pub fn hex(&self) -> String {
format!("{:?}", self)
}
pub fn from_bloomed<T>(b: &T) -> Self where T: FixedHash { b.bloom_part($size) }
}
impl Default for $from {
fn default() -> Self { $from::new() }
}
impl From<u64> for $from {
fn from(mut value: u64) -> $from {
let mut ret = $from::new();
for i in 0..8 {
if i < $size {
ret.0[$size - i - 1] = (value & 0xff) as u8;
value >>= 8;
}
}
ret
}
}
impl<'_> From<&'_ str> for $from {
fn from(s: &'_ str) -> $from {
use std::str::FromStr;
if s.len() % 2 == 1 {
$from::from_str(&("0".to_string() + &(clean_0x(s).to_string()))[..]).unwrap_or($from::new())
} else {
$from::from_str(clean_0x(s)).unwrap_or($from::new())
}
}
}
}
}
impl From<U256> for H256 {
fn from(value: U256) -> H256 {
unsafe {
let mut ret: H256 = ::std::mem::uninitialized();
value.to_bytes(&mut ret);
ret
}
}
}
impl<'_> From<&'_ U256> for H256 {
fn from(value: &'_ U256) -> H256 {
unsafe {
let mut ret: H256 = ::std::mem::uninitialized();
value.to_bytes(&mut ret);
ret
}
}
}
impl From<H256> for Address {
fn from(value: H256) -> Address {
unsafe {
let mut ret: Address = ::std::mem::uninitialized();
::std::ptr::copy(value.as_ptr().offset(12), ret.as_mut_ptr(), 20);
ret
}
}
}
impl From<H256> for H64 {
fn from(value: H256) -> H64 {
unsafe {
let mut ret: H64 = ::std::mem::uninitialized();
::std::ptr::copy(value.as_ptr().offset(20), ret.as_mut_ptr(), 8);
ret
}
}
}
/*
impl<'_> From<&'_ H256> for Address {
fn from(value: &'_ H256) -> Address {
unsafe {
let mut ret: Address = ::std::mem::uninitialized();
::std::ptr::copy(value.as_ptr().offset(12), ret.as_mut_ptr(), 20);
ret
}
}
}
*/
impl From<Address> for H256 {
fn from(value: Address) -> H256 {
unsafe {
let mut ret = H256::new();
::std::ptr::copy(value.as_ptr(), ret.as_mut_ptr().offset(12), 20);
ret
}
}
}
impl<'_> From<&'_ Address> for H256 {
fn from(value: &'_ Address) -> H256 {
unsafe {
let mut ret = H256::new();
::std::ptr::copy(value.as_ptr(), ret.as_mut_ptr().offset(12), 20);
ret
}
}
}
pub fn h256_from_hex(s: &str) -> H256 {
use std::str::FromStr;
H256::from_str(s).unwrap()
}
pub fn h256_from_u64(n: u64) -> H256 {
use uint::U256;
H256::from(&U256::from(n))
}
pub fn address_from_hex(s: &str) -> Address {
use std::str::FromStr;
Address::from_str(s).unwrap()
}
pub fn address_from_u64(n: u64) -> Address {
let h256 = h256_from_u64(n);
From::from(h256)
}
impl_hash!(H32, 4);
impl_hash!(H64, 8);
impl_hash!(H128, 16);
impl_hash!(Address, 20);
impl_hash!(H256, 32);
impl_hash!(H264, 33);
impl_hash!(H512, 64);
impl_hash!(H520, 65);
impl_hash!(H1024, 128);
impl_hash!(H2048, 256);
/// Constant address for point 0. Often used as a default.
pub static ZERO_ADDRESS: Address = Address([0x00; 20]);
/// Constant 256-bit datum for 0. Often used as a default.
pub static ZERO_H256: H256 = H256([0x00; 32]);
#[cfg(test)]
mod tests {
use hash::*;
use std::str::FromStr;
#[test]
fn hash() {
let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h);
assert_eq!(format!("{}", h), "012345…ef");
assert_eq!(format!("{:?}", h), "0123456789abcdef");
assert_eq!(h.hex(), "0123456789abcdef");
assert!(h == h);
assert!(h != H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xee]));
assert!(h != H64([0; 8]));
}
#[test]
fn hash_bitor() {
let a = H64([1; 8]);
let b = H64([2; 8]);
let c = H64([3; 8]);
// borrow
assert_eq!(&a | &b, c);
// move
assert_eq!(a | b, c);
}
#[test]
fn shift_bloomed() {
use sha3::Hashable;
let bloom = H2048::from_str("00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap();
let topic = H256::from_str("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap();
let mut my_bloom = H2048::new();
assert!(!my_bloom.contains_bloomed(&address.sha3()));
assert!(!my_bloom.contains_bloomed(&topic.sha3()));
my_bloom.shift_bloomed(&address.sha3());
assert!(my_bloom.contains_bloomed(&address.sha3()));
assert!(!my_bloom.contains_bloomed(&topic.sha3()));
my_bloom.shift_bloomed(&topic.sha3());
assert_eq!(my_bloom, bloom);
assert!(my_bloom.contains_bloomed(&address.sha3()));
assert!(my_bloom.contains_bloomed(&topic.sha3()));
}
#[test]
fn from_and_to_address() {
let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap();
let h = H256::from(address.clone());
let a = Address::from(h);
assert_eq!(address, a);
}
#[test]
fn from_u64() {
assert_eq!(H128::from(0x1234567890abcdef), H128::from_str("00000000000000001234567890abcdef").unwrap());
assert_eq!(H64::from(0x1234567890abcdef), H64::from_str("1234567890abcdef").unwrap());
assert_eq!(H32::from(0x1234567890abcdef), H32::from_str("90abcdef").unwrap());
}
#[test]
fn from_str() {
assert_eq!(H64::from(0x1234567890abcdef), H64::from("0x1234567890abcdef"));
assert_eq!(H64::from(0x1234567890abcdef), H64::from("1234567890abcdef"));
assert_eq!(H64::from(0x234567890abcdef), H64::from("0x234567890abcdef"));
// too short.
assert_eq!(H64::from(0), H64::from("0x34567890abcdef"));
}
}

View File

@@ -1,97 +0,0 @@
//! Database of byte-slices keyed to their Keccak hash.
use hash::*;
use bytes::*;
use std::collections::HashMap;
/// Trait modelling datastore keyed by a 32-byte Keccak hash.
pub trait HashDB {
/// Get the keys in the database together with number of underlying references.
fn keys(&self) -> HashMap<H256, i32>;
/// Deprecated. use `get`.
fn lookup(&self, key: &H256) -> Option<&[u8]>; // TODO: rename to get.
/// Look up a given hash into the bytes that hash to it, returning None if the
/// hash is not known.
///
/// # Examples
/// ```rust
/// extern crate ethcore_util;
/// use ethcore_util::hashdb::*;
/// use ethcore_util::memorydb::*;
/// fn main() {
/// let mut m = MemoryDB::new();
/// let hello_bytes = "Hello world!".as_bytes();
/// let hash = m.insert(hello_bytes);
/// assert_eq!(m.lookup(&hash).unwrap(), hello_bytes);
/// }
/// ```
fn get(&self, key: &H256) -> Option<&[u8]> { self.lookup(key) }
/// Deprecated. Use `contains`.
fn exists(&self, key: &H256) -> bool; // TODO: rename to contains.
/// Check for the existance of a hash-key.
///
/// # Examples
/// ```rust
/// extern crate ethcore_util;
/// use ethcore_util::hashdb::*;
/// use ethcore_util::memorydb::*;
/// use ethcore_util::sha3::*;
/// fn main() {
/// let mut m = MemoryDB::new();
/// let hello_bytes = "Hello world!".as_bytes();
/// assert!(!m.exists(&hello_bytes.sha3()));
/// let key = m.insert(hello_bytes);
/// assert!(m.exists(&key));
/// m.kill(&key);
/// assert!(!m.exists(&key));
/// }
/// ```
fn contains(&self, key: &H256) -> bool { self.exists(key) }
/// Insert a datum item into the DB and return the datum's hash for a later lookup. Insertions
/// are counted and the equivalent number of `kill()`s must be performed before the data
/// is considered dead.
///
/// # Examples
/// ```rust
/// extern crate ethcore_util;
/// use ethcore_util::hashdb::*;
/// use ethcore_util::memorydb::*;
/// use ethcore_util::hash::*;
/// fn main() {
/// let mut m = MemoryDB::new();
/// let key = m.insert("Hello world!".as_bytes());
/// assert!(m.exists(&key));
/// }
/// ```
fn insert(&mut self, value: &[u8]) -> H256;
/// Like `insert()` , except you provide the key and the data is all moved.
fn emplace(&mut self, key: H256, value: Bytes);
/// Deprecated - use `remove`.
fn kill(&mut self, key: &H256); // TODO: rename to remove.
/// Remove a datum previously inserted. Insertions can be "owed" such that the same number of `insert()`s may
/// happen without the data being eventually being inserted into the DB.
///
/// # Examples
/// ```rust
/// extern crate ethcore_util;
/// use ethcore_util::hashdb::*;
/// use ethcore_util::memorydb::*;
/// use ethcore_util::sha3::*;
/// fn main() {
/// let mut m = MemoryDB::new();
/// let d = "Hello world!".as_bytes();
/// let key = &d.sha3();
/// m.kill(key); // OK - we now owe an insertion.
/// assert!(!m.exists(key));
/// m.insert(d); // OK - now it's "empty" again.
/// assert!(!m.exists(key));
/// m.insert(d); // OK - now we've
/// assert_eq!(m.lookup(key).unwrap(), d);
/// }
/// ```
fn remove(&mut self, key: &H256) { self.kill(key) }
}

196
src/header.rs Normal file
View File

@@ -0,0 +1,196 @@
use util::*;
use basic_types::*;
use time::now_utc;
pub type BlockNumber = u64;
/// A block header.
///
/// Reflects the specific RLP fields of a block in the chain with additional room for the seal
/// which is non-specific.
///
/// Doesn't do all that much on its own.
#[derive(Debug, Clone)]
pub struct Header {
// TODO: make all private.
pub parent_hash: H256,
pub timestamp: u64,
pub number: BlockNumber,
pub author: Address,
pub transactions_root: H256,
pub uncles_hash: H256,
pub extra_data: Bytes,
pub state_root: H256,
pub receipts_root: H256,
pub log_bloom: LogBloom,
pub gas_used: U256,
pub gas_limit: U256,
pub difficulty: U256,
pub seal: Vec<Bytes>,
pub hash: RefCell<Option<H256>>,
}
impl Header {
/// Create a new, default-valued, header.
pub fn new() -> Header {
Header {
parent_hash: ZERO_H256.clone(),
timestamp: 0,
number: 0,
author: ZERO_ADDRESS.clone(),
transactions_root: SHA3_NULL_RLP,
uncles_hash: SHA3_EMPTY_LIST_RLP,
extra_data: vec![],
state_root: SHA3_NULL_RLP,
receipts_root: SHA3_NULL_RLP,
log_bloom: ZERO_LOGBLOOM.clone(),
gas_used: ZERO_U256,
gas_limit: ZERO_U256,
difficulty: ZERO_U256,
seal: vec![],
hash: RefCell::new(None),
}
}
pub fn number(&self) -> BlockNumber { self.number }
pub fn timestamp(&self) -> u64 { self.timestamp }
pub fn author(&self) -> &Address { &self.author }
pub fn extra_data(&self) -> &Bytes { &self.extra_data }
pub fn state_root(&self) -> &H256 { &self.state_root }
pub fn receipts_root(&self) -> &H256 { &self.receipts_root }
pub fn gas_limit(&self) -> &U256 { &self.gas_limit }
pub fn difficulty(&self) -> &U256 { &self.difficulty }
pub fn seal(&self) -> &Vec<Bytes> { &self.seal }
// TODO: seal_at, set_seal_at &c.
pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); }
pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); }
pub fn set_timestamp_now(&mut self) { self.timestamp = now_utc().to_timespec().sec as u64; self.note_dirty(); }
pub fn set_author(&mut self, a: Address) { if a != self.author { self.author = a; self.note_dirty(); } }
pub fn set_extra_data(&mut self, a: Bytes) { if a != self.extra_data { self.extra_data = a; self.note_dirty(); } }
pub fn set_gas_used(&mut self, a: U256) { self.gas_used = a; self.note_dirty(); }
pub fn set_gas_limit(&mut self, a: U256) { self.gas_limit = a; self.note_dirty(); }
pub fn set_difficulty(&mut self, a: U256) { self.difficulty = a; self.note_dirty(); }
pub fn set_seal(&mut self, a: Vec<Bytes>) { self.seal = a; self.note_dirty(); }
/// Get the hash of this header (sha3 of the RLP).
pub fn hash(&self) -> H256 {
let mut hash = self.hash.borrow_mut();
match &mut *hash {
&mut Some(ref h) => h.clone(),
hash @ &mut None => {
*hash = Some(self.rlp_sha3(Seal::With));
hash.as_ref().unwrap().clone()
}
}
}
/// Note that some fields have changed. Resets the memoised hash.
pub fn note_dirty(&self) {
*self.hash.borrow_mut() = None;
}
// TODO: get hash without seal.
// TODO: make these functions traity
pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) {
s.append_list(13 + match with_seal { Seal::With => self.seal.len(), _ => 0 });
s.append(&self.parent_hash);
s.append(&self.uncles_hash);
s.append(&self.author);
s.append(&self.state_root);
s.append(&self.transactions_root);
s.append(&self.receipts_root);
s.append(&self.log_bloom);
s.append(&self.difficulty);
s.append(&self.number);
s.append(&self.gas_limit);
s.append(&self.gas_used);
s.append(&self.timestamp);
s.append(&self.extra_data);
match with_seal {
Seal::With => for b in self.seal.iter() { s.append_raw(&b, 1); },
_ => {}
}
}
pub fn rlp(&self, with_seal: Seal) -> Bytes {
let mut s = RlpStream::new();
self.stream_rlp(&mut s, with_seal);
s.out()
}
pub fn rlp_sha3(&self, with_seal: Seal) -> H256 { self.rlp(with_seal).sha3() }
}
impl Decodable for Header {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let r = decoder.as_rlp();
let mut blockheader = Header {
parent_hash: try!(r.val_at(0)),
uncles_hash: try!(r.val_at(1)),
author: try!(r.val_at(2)),
state_root: try!(r.val_at(3)),
transactions_root: try!(r.val_at(4)),
receipts_root: try!(r.val_at(5)),
log_bloom: try!(r.val_at(6)),
difficulty: try!(r.val_at(7)),
number: try!(r.val_at(8)),
gas_limit: try!(r.val_at(9)),
gas_used: try!(r.val_at(10)),
timestamp: try!(r.val_at(11)),
extra_data: try!(r.val_at(12)),
seal: vec![],
hash: RefCell::new(Some(r.as_raw().sha3()))
};
for i in 13..r.item_count() {
blockheader.seal.push(try!(r.at(i)).as_raw().to_vec())
}
Ok(blockheader)
}
}
impl Encodable for Header {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
encoder.emit_list(| e | {
self.parent_hash.encode(e);
self.uncles_hash.encode(e);
self.author.encode(e);
self.state_root.encode(e);
self.transactions_root.encode(e);
self.receipts_root.encode(e);
self.log_bloom.encode(e);
self.difficulty.encode(e);
self.number.encode(e);
self.gas_limit.encode(e);
self.gas_used.encode(e);
self.timestamp.encode(e);
self.extra_data.encode(e);
for b in self.seal.iter() {
e.emit_raw(&b);
}
})
}
}
#[cfg(test)]
mod tests {
}

View File

@@ -1,5 +0,0 @@
use uint::*;
use hash::*;
known_heap_size!(0, H32, H64, H128, Address, H256, H264, H512, H520, H1024, H2048);
known_heap_size!(0, U128, U256);

View File

@@ -1,107 +0,0 @@
/// General IO module.
///
/// Example usage for craeting a network service and adding an IO handler:
///
/// ```rust
/// extern crate ethcore_util;
/// use ethcore_util::*;
///
/// struct MyHandler;
///
/// struct MyMessage {
/// data: u32
/// }
///
/// impl IoHandler<MyMessage> for MyHandler {
/// fn initialize(&mut self, io: &mut IoContext<MyMessage>) {
/// io.register_timer(1000).unwrap();
/// }
///
/// fn timeout(&mut self, _io: &mut IoContext<MyMessage>, timer: TimerToken) {
/// println!("Timeout {}", timer);
/// }
///
/// fn message(&mut self, _io: &mut IoContext<MyMessage>, message: &mut MyMessage) {
/// println!("Message {}", message.data);
/// }
/// }
///
/// fn main () {
/// let mut service = IoService::<MyMessage>::start().expect("Error creating network service");
/// service.register_handler(Box::new(MyHandler)).unwrap();
///
/// // Wait for quit condition
/// // ...
/// // Drop the service
/// }
/// ```
mod service;
#[derive(Debug)]
pub enum IoError {
Mio(::std::io::Error),
}
impl<Message> From<::mio::NotifyError<service::IoMessage<Message>>> for IoError where Message: Send {
fn from(_err: ::mio::NotifyError<service::IoMessage<Message>>) -> IoError {
IoError::Mio(::std::io::Error::new(::std::io::ErrorKind::ConnectionAborted, "Network IO notification error"))
}
}
/// Generic IO handler.
/// All the handler function are called from within IO event loop.
/// `Message` type is used as notification data
pub trait IoHandler<Message>: Send where Message: Send + 'static {
/// Initialize the handler
fn initialize<'s>(&'s mut self, _io: &mut IoContext<'s, Message>) {}
/// Timer function called after a timeout created with `HandlerIo::timeout`.
fn timeout<'s>(&'s mut self, _io: &mut IoContext<'s, Message>, _timer: TimerToken) {}
/// Called when a broadcasted message is received. The message can only be sent from a different IO handler.
fn message<'s>(&'s mut self, _io: &mut IoContext<'s, Message>, _message: &'s mut Message) {} // TODO: make message immutable and provide internal channel for adding network handler
/// Called when an IO stream gets closed
fn stream_hup<'s>(&'s mut self, _io: &mut IoContext<'s, Message>, _stream: StreamToken) {}
/// Called when an IO stream can be read from
fn stream_readable<'s>(&'s mut self, _io: &mut IoContext<'s, Message>, _stream: StreamToken) {}
/// Called when an IO stream can be written to
fn stream_writable<'s>(&'s mut self, _io: &mut IoContext<'s, Message>, _stream: StreamToken) {}
}
pub type TimerToken = service::TimerToken;
pub type StreamToken = service::StreamToken;
pub type IoContext<'s, M> = service::IoContext<'s, M>;
pub type IoService<M> = service::IoService<M>;
pub type IoChannel<M> = service::IoChannel<M>;
//pub const USER_TOKEN_START: usize = service::USER_TOKEN; // TODO: ICE in rustc 1.7.0-nightly (49c382779 2016-01-12)
#[cfg(test)]
mod tests {
use io::*;
struct MyHandler;
struct MyMessage {
data: u32
}
impl IoHandler<MyMessage> for MyHandler {
fn initialize(&mut self, io: &mut IoContext<MyMessage>) {
io.register_timer(1000).unwrap();
}
fn timeout(&mut self, _io: &mut IoContext<MyMessage>, timer: TimerToken) {
println!("Timeout {}", timer);
}
fn message(&mut self, _io: &mut IoContext<MyMessage>, message: &mut MyMessage) {
println!("Message {}", message.data);
}
}
#[test]
fn test_service_register_handler () {
let mut service = IoService::<MyMessage>::start().expect("Error creating network service");
service.register_handler(Box::new(MyHandler)).unwrap();
}
}

View File

@@ -1,211 +0,0 @@
use std::thread::{self, JoinHandle};
use mio::*;
use mio::util::{Slab};
use hash::*;
use rlp::*;
use error::*;
use io::{IoError, IoHandler};
pub type TimerToken = usize;
pub type StreamToken = usize;
// Tokens
const MAX_USER_TIMERS: usize = 32;
const USER_TIMER: usize = 0;
const LAST_USER_TIMER: usize = USER_TIMER + MAX_USER_TIMERS - 1;
//const USER_TOKEN: usize = LAST_USER_TIMER + 1;
/// Messages used to communicate with the event loop from other threads.
pub enum IoMessage<Message> where Message: Send + Sized {
/// Shutdown the event loop
Shutdown,
/// Register a new protocol handler.
AddHandler {
handler: Box<IoHandler<Message>+Send>,
},
/// Broadcast a message across all protocol handlers.
UserMessage(Message)
}
/// IO access point. This is passed to all IO handlers and provides an interface to the IO subsystem.
pub struct IoContext<'s, Message> where Message: Send + 'static {
timers: &'s mut Slab<UserTimer>,
/// Low leve MIO Event loop for custom handler registration.
pub event_loop: &'s mut EventLoop<IoManager<Message>>,
}
impl<'s, Message> IoContext<'s, Message> where Message: Send + 'static {
/// Create a new IO access point. Takes references to all the data that can be updated within the IO handler.
fn new(event_loop: &'s mut EventLoop<IoManager<Message>>, timers: &'s mut Slab<UserTimer>) -> IoContext<'s, Message> {
IoContext {
event_loop: event_loop,
timers: timers,
}
}
/// Register a new IO timer. Returns a new timer token. 'IoHandler::timeout' will be called with the token.
pub fn register_timer(&mut self, ms: u64) -> Result<TimerToken, UtilError> {
match self.timers.insert(UserTimer {
delay: ms,
}) {
Ok(token) => {
self.event_loop.timeout_ms(token, ms).expect("Error registering user timer");
Ok(token.as_usize())
},
_ => { panic!("Max timers reached") }
}
}
/// Broadcast a message to other IO clients
pub fn message(&mut self, message: Message) {
match self.event_loop.channel().send(IoMessage::UserMessage(message)) {
Ok(_) => {}
Err(e) => { panic!("Error sending io message {:?}", e); }
}
}
}
struct UserTimer {
delay: u64,
}
/// Root IO handler. Manages user handlers, messages and IO timers.
pub struct IoManager<Message> where Message: Send {
timers: Slab<UserTimer>,
handlers: Vec<Box<IoHandler<Message>>>,
}
impl<Message> IoManager<Message> where Message: Send + 'static {
/// Creates a new instance and registers it with the event loop.
pub fn start(event_loop: &mut EventLoop<IoManager<Message>>) -> Result<(), UtilError> {
let mut io = IoManager {
timers: Slab::new_starting_at(Token(USER_TIMER), MAX_USER_TIMERS),
handlers: Vec::new(),
};
try!(event_loop.run(&mut io));
Ok(())
}
}
impl<Message> Handler for IoManager<Message> where Message: Send + 'static {
type Timeout = Token;
type Message = IoMessage<Message>;
fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
if events.is_hup() {
for h in self.handlers.iter_mut() {
h.stream_hup(&mut IoContext::new(event_loop, &mut self.timers), token.as_usize());
}
}
else if events.is_readable() {
for h in self.handlers.iter_mut() {
h.stream_readable(&mut IoContext::new(event_loop, &mut self.timers), token.as_usize());
}
}
else if events.is_writable() {
for h in self.handlers.iter_mut() {
h.stream_writable(&mut IoContext::new(event_loop, &mut self.timers), token.as_usize());
}
}
}
fn timeout(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
match token.as_usize() {
USER_TIMER ... LAST_USER_TIMER => {
let delay = {
let timer = self.timers.get_mut(token).expect("Unknown user timer token");
timer.delay
};
for h in self.handlers.iter_mut() {
h.timeout(&mut IoContext::new(event_loop, &mut self.timers), token.as_usize());
}
event_loop.timeout_ms(token, delay).expect("Error re-registering user timer");
}
_ => { // Just pass the event down. IoHandler is supposed to re-register it if required.
for h in self.handlers.iter_mut() {
h.timeout(&mut IoContext::new(event_loop, &mut self.timers), token.as_usize());
}
}
}
}
fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Self::Message) {
let mut m = msg;
match m {
IoMessage::Shutdown => event_loop.shutdown(),
IoMessage::AddHandler {
handler,
} => {
self.handlers.push(handler);
self.handlers.last_mut().unwrap().initialize(&mut IoContext::new(event_loop, &mut self.timers));
},
IoMessage::UserMessage(ref mut data) => {
for h in self.handlers.iter_mut() {
h.message(&mut IoContext::new(event_loop, &mut self.timers), data);
}
}
}
}
}
/// Allows sending messages into the event loop. All the IO handlers will get the message
/// in the `message` callback.
pub struct IoChannel<Message> where Message: Send {
channel: Sender<IoMessage<Message>>
}
impl<Message> IoChannel<Message> where Message: Send {
pub fn send(&mut self, message: Message) -> Result<(), IoError> {
try!(self.channel.send(IoMessage::UserMessage(message)));
Ok(())
}
}
/// General IO Service. Starts an event loop and dispatches IO requests.
/// 'Message' is a notification message type
pub struct IoService<Message> where Message: Send + 'static {
thread: Option<JoinHandle<()>>,
host_channel: Sender<IoMessage<Message>>
}
impl<Message> IoService<Message> where Message: Send + 'static {
/// Starts IO event loop
pub fn start() -> Result<IoService<Message>, UtilError> {
let mut event_loop = EventLoop::new().unwrap();
let channel = event_loop.channel();
let thread = thread::spawn(move || {
IoManager::<Message>::start(&mut event_loop).unwrap(); //TODO:
});
Ok(IoService {
thread: Some(thread),
host_channel: channel
})
}
/// Regiter a IO hadnler with the event loop.
pub fn register_handler(&mut self, handler: Box<IoHandler<Message>+Send>) -> Result<(), IoError> {
try!(self.host_channel.send(IoMessage::AddHandler {
handler: handler,
}));
Ok(())
}
/// Send a message over the network. Normaly `HostIo::send` should be used. This can be used from non-io threads.
pub fn send_message(&mut self, message: Message) -> Result<(), IoError> {
try!(self.host_channel.send(IoMessage::UserMessage(message)));
Ok(())
}
/// Create a new message channel
pub fn channel(&mut self) -> IoChannel<Message> {
IoChannel { channel: self.host_channel.clone() }
}
}
impl<Message> Drop for IoService<Message> where Message: Send {
fn drop(&mut self) {
self.host_channel.send(IoMessage::Shutdown).unwrap();
self.thread.take().unwrap().join().unwrap();
}
}

View File

@@ -1,137 +0,0 @@
use common::*;
pub fn clean(s: &str) -> &str {
if s.len() >= 2 && &s[0..2] == "0x" {
&s[2..]
} else {
s
}
}
fn u256_from_str(s: &str) -> U256 {
if s.len() >= 2 && &s[0..2] == "0x" {
U256::from_str(&s[2..]).unwrap_or(U256::from(0))
} else {
U256::from_dec_str(s).unwrap_or(U256::from(0))
}
}
impl FromJson for Bytes {
fn from_json(json: &Json) -> Self {
match json {
&Json::String(ref s) => match s.len() % 2 {
0 => FromHex::from_hex(clean(s)).unwrap_or(vec![]),
_ => FromHex::from_hex(&("0".to_string() + &(clean(s).to_string()))[..]).unwrap_or(vec![]),
},
_ => vec![],
}
}
}
impl FromJson for BTreeMap<H256, H256> {
fn from_json(json: &Json) -> Self {
match json {
&Json::Object(ref o) => o.iter().map(|(key, value)| (x!(&u256_from_str(key)), x!(&U256::from_json(value)))).collect(),
_ => BTreeMap::new(),
}
}
}
impl<T> FromJson for Vec<T> where T: FromJson {
fn from_json(json: &Json) -> Self {
match json {
&Json::Array(ref o) => o.iter().map(|x|T::from_json(x)).collect(),
_ => Vec::new(),
}
}
}
impl<T> FromJson for Option<T> where T: FromJson {
fn from_json(json: &Json) -> Self {
match json {
&Json::String(ref o) if o.is_empty() => None,
&Json::Null => None,
_ => Some(FromJson::from_json(json)),
}
}
}
impl FromJson for u64 {
fn from_json(json: &Json) -> Self {
U256::from_json(json).low_u64()
}
}
impl FromJson for u32 {
fn from_json(json: &Json) -> Self {
U256::from_json(json).low_u64() as u32
}
}
impl FromJson for u16 {
fn from_json(json: &Json) -> Self {
U256::from_json(json).low_u64() as u16
}
}
#[test]
fn u256_from_json() {
let j = Json::from_str("{ \"dec\": \"10\", \"hex\": \"0x0a\", \"int\": 10 }").unwrap();
let v: U256 = xjson!(&j["dec"]);
assert_eq!(U256::from(10), v);
let v: U256 = xjson!(&j["hex"]);
assert_eq!(U256::from(10), v);
let v: U256 = xjson!(&j["int"]);
assert_eq!(U256::from(10), v);
}
#[test]
fn h256_from_json() {
let j = Json::from_str("{ \"with\": \"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\", \"without\": \"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\" }").unwrap();
let v: H256 = xjson!(&j["with"]);
assert_eq!(H256::from_str("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").unwrap(), v);
let v: H256 = xjson!(&j["without"]);
assert_eq!(H256::from_str("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").unwrap(), v);
}
#[test]
fn vec_u256_from_json() {
let j = Json::from_str("{ \"array\": [ \"10\", \"0x0a\", 10] }").unwrap();
let v: Vec<U256> = xjson!(&j["array"]);
assert_eq!(vec![U256::from(10); 3], v);
}
#[test]
fn vec_h256_from_json() {
let j = Json::from_str("{ \"array\": [ \"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\", \"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\"] }").unwrap();
let v: Vec<H256> = xjson!(&j["array"]);
assert_eq!(vec![H256::from_str("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").unwrap(); 2], v);
}
#[test]
fn simple_types() {
let j = Json::from_str("{ \"null\": null, \"empty\": \"\", \"int\": 42, \"dec\": \"42\", \"hex\": \"0x2a\" }").unwrap();
let v: u16 = xjson!(&j["int"]);
assert_eq!(42u16, v);
let v: u32 = xjson!(&j["dec"]);
assert_eq!(42u32, v);
let v: u64 = xjson!(&j["hex"]);
assert_eq!(42u64, v);
}
#[test]
fn option_types() {
let j = Json::from_str("{ \"null\": null, \"empty\": \"\", \"int\": 42, \"dec\": \"42\", \"hex\": \"0x2a\" }").unwrap();
let v: Option<u16> = xjson!(&j["int"]);
assert_eq!(Some(42u16), v);
let v: Option<u16> = xjson!(&j["dec"]);
assert_eq!(Some(42u16), v);
let v: Option<u16> = xjson!(&j["null"]);
assert_eq!(None, v);
let v: Option<u16> = xjson!(&j["empty"]);
assert_eq!(None, v);
}

View File

@@ -1,101 +1,128 @@
#![feature(op_assign_traits)]
#![feature(cell_extras)]
#![feature(augmented_assignments)]
#![feature(associated_consts)]
#![feature(wrapping)]
//! Ethcore-util library
//#![feature(plugin)]
//#![plugin(interpolate_idents)]
//! Ethcore's ethereum implementation
//!
//! ### Rust version:
//! ### Rust version
//! - beta
//! - nightly
//!
//! ### Supported platforms:
//! - OSX
//! - Linux
//! - Linux/Ubuntu
//!
//! ### Dependencies:
//! - RocksDB 3.13
//! - LLVM 3.7 (optional, required for `jit`)
//! - evmjit (optional, required for `jit`)
//!
//! ### Dependencies Installation:
//! ### Dependencies Installation
//!
//! - OSX:
//! - OSX
//!
//! - rocksdb
//! ```bash
//! brew install rocksdb
//! ```
//!
//! - From source:
//! - llvm
//!
//! ```bash
//! wget https://github.com/facebook/rocksdb/archive/rocksdb-3.13.tar.gz
//! tar xvf rocksdb-3.13.tar.gz && cd rocksdb-rocksdb-3.13 && make shared_lib
//! sudo make install
//! ```
//! - download llvm 3.7 from http://llvm.org/apt/
//!
//! ```bash
//! cd llvm-3.7.0.src
//! mkdir build && cd $_
//! cmake -G "Unix Makefiles" .. -DCMAKE_C_FLAGS_RELEASE= -DCMAKE_CXX_FLAGS_RELEASE= -DCMAKE_INSTALL_PREFIX=/usr/local/Cellar/llvm/3.7 -DCMAKE_BUILD_TYPE=Release
//! make && make install
//! ```
//! - evmjit
//!
//! - download from https://github.com/debris/evmjit
//!
//! ```bash
//! cd evmjit
//! mkdir build && cd $_
//! cmake -DLLVM_DIR=/usr/local/lib/llvm-3.7/share/llvm/cmake ..
//! make && make install
//! ```
//!
//! - Linux/Ubuntu
//!
//! - rocksdb
//!
//! ```bash
//! wget https://github.com/facebook/rocksdb/archive/rocksdb-3.13.tar.gz
//! tar xvf rocksdb-3.13.tar.gz && cd rocksdb-rocksdb-3.13 && make shared_lib
//! sudo make install
//! ```
//!
//! - llvm
//!
//! - install using packages from http://llvm.org/apt/
//!
//! - evmjit
//!
//! - download from https://github.com/debris/evmjit
//!
//! ```bash
//! cd evmjit
//! mkdir build && cd $_
//! cmake .. && make
//! sudo make install
//! sudo ldconfig
//! ```
extern crate slab;
extern crate rustc_serialize;
extern crate mio;
extern crate rand;
extern crate rocksdb;
extern crate tiny_keccak;
#[macro_use]
extern crate heapsize;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate itertools;
extern crate env_logger;
extern crate rustc_serialize;
extern crate flate2;
extern crate rocksdb;
extern crate heapsize;
extern crate crypto;
extern crate time;
extern crate crypto as rcrypto;
extern crate secp256k1;
extern crate arrayvec;
extern crate elastic_array;
extern crate env_logger;
#[cfg(feature = "jit" )]
extern crate evmjit;
#[macro_use]
extern crate ethcore_util as util;
pub mod standard;
#[macro_use]
pub mod from_json;
#[macro_use]
pub mod common;
pub mod basic_types;
#[macro_use]
pub mod evm;
pub mod error;
pub mod hash;
pub mod uint;
pub mod bytes;
pub mod rlp;
pub mod misc;
pub mod json_aid;
pub mod vector;
pub mod sha3;
pub mod hashdb;
pub mod memorydb;
pub mod overlaydb;
pub mod math;
pub mod chainfilter;
pub mod crypto;
pub mod triehash;
pub mod trie;
pub mod nibbleslice;
pub mod heapsizeof;
pub mod squeeze;
pub mod semantic_version;
pub mod io;
pub mod network;
pub mod log_entry;
pub mod env_info;
pub mod pod_account;
pub mod pod_state;
pub mod account_diff;
pub mod state_diff;
pub mod engine;
pub mod state;
pub mod account;
pub mod action_params;
pub mod header;
pub mod transaction;
pub mod receipt;
pub mod null_engine;
pub mod builtin;
pub mod spec;
pub mod views;
pub mod blockchain;
pub mod extras;
pub mod substate;
pub mod service;
pub mod executive;
pub mod externalities;
pub use common::*;
pub use misc::*;
pub use json_aid::*;
pub use rlp::*;
pub use hashdb::*;
pub use memorydb::*;
pub use overlaydb::*;
pub use math::*;
pub use chainfilter::*;
pub use crypto::*;
pub use triehash::*;
pub use trie::*;
pub use nibbleslice::*;
pub use heapsizeof::*;
pub use squeeze::*;
pub use semantic_version::*;
pub use network::*;
pub use io::*;
#[cfg(test)]
mod tests;
pub mod client;
pub mod sync;
pub mod block;
pub mod verification;
pub mod queue;
pub mod ethereum;

76
src/log_entry.rs Normal file
View File

@@ -0,0 +1,76 @@
use util::*;
use basic_types::LogBloom;
/// A single log's entry.
#[derive(Debug,PartialEq,Eq)]
pub struct LogEntry {
pub address: Address,
pub topics: Vec<H256>,
pub data: Bytes,
}
impl RlpStandard for LogEntry {
fn rlp_append(&self, s: &mut RlpStream) {
s.append_list(3);
s.append(&self.address);
s.append(&self.topics);
s.append(&self.data);
}
}
impl LogEntry {
/// Create a new log entry.
pub fn new(address: Address, topics: Vec<H256>, data: Bytes) -> LogEntry {
LogEntry {
address: address,
topics: topics,
data: data
}
}
/// Returns reference to address.
pub fn address(&self) -> &Address {
&self.address
}
/// Returns reference to topics.
pub fn topics(&self) -> &Vec<H256> {
&self.topics
}
/// Returns reference to data.
pub fn data(&self) -> &Bytes {
&self.data
}
/// Calculates the bloom of this log entry.
pub fn bloom(&self) -> LogBloom {
self.topics.iter().fold(LogBloom::from_bloomed(&self.address.sha3()), |b, t| b.with_bloomed(&t.sha3()))
}
}
impl FromJson for LogEntry {
/// Convert given JSON object to a LogEntry.
fn from_json(json: &Json) -> LogEntry {
// TODO: check bloom.
LogEntry {
address: xjson!(&json["address"]),
topics: xjson!(&json["topics"]),
data: xjson!(&json["data"]),
}
}
}
#[cfg(test)]
mod tests {
use util::*;
use super::LogEntry;
#[test]
fn test_empty_log_bloom() {
let bloom = H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let log = LogEntry::new(address, vec![], vec![]);
assert_eq!(log.bloom(), bloom);
}
}

View File

@@ -1,9 +0,0 @@
/// log2
pub fn log2(x: usize) -> u32 {
if x <= 1 {
return 0;
}
let n = x.leading_zeros();
::std::mem::size_of::<usize>() as u32 * 8 - n
}

View File

@@ -1,219 +0,0 @@
//! Reference-counted memory-based HashDB implementation.
use hash::*;
use bytes::*;
use rlp::*;
use sha3::*;
use hashdb::*;
use std::mem;
use std::collections::HashMap;
#[derive(Debug,Clone)]
/// Reference-counted memory-based HashDB implementation.
///
/// Use `new()` to create a new database. Insert items with `insert()`, remove items
/// with `kill()`, check for existance with `exists()` and lookup a hash to derive
/// the data with `lookup()`. Clear with `clear()` and purge the portions of the data
/// that have no references with `purge()`.
///
/// # Example
/// ```rust
/// extern crate ethcore_util;
/// use ethcore_util::hashdb::*;
/// use ethcore_util::memorydb::*;
/// fn main() {
/// let mut m = MemoryDB::new();
/// let d = "Hello world!".as_bytes();
///
/// let k = m.insert(d);
/// assert!(m.exists(&k));
/// assert_eq!(m.lookup(&k).unwrap(), d);
///
/// m.insert(d);
/// assert!(m.exists(&k));
///
/// m.kill(&k);
/// assert!(m.exists(&k));
///
/// m.kill(&k);
/// assert!(!m.exists(&k));
///
/// m.kill(&k);
/// assert!(!m.exists(&k));
///
/// m.insert(d);
/// assert!(!m.exists(&k));
/// m.insert(d);
/// assert!(m.exists(&k));
/// assert_eq!(m.lookup(&k).unwrap(), d);
///
/// m.kill(&k);
/// assert!(!m.exists(&k));
/// }
/// ```
pub struct MemoryDB {
data: HashMap<H256, (Bytes, i32)>,
static_null_rlp: (Bytes, i32),
}
impl MemoryDB {
/// Create a new instance of the memory DB.
pub fn new() -> MemoryDB {
MemoryDB {
data: HashMap::new(),
static_null_rlp: (vec![0x80u8; 1], 1),
}
}
/// Clear all data from the database.
///
/// # Examples
/// ```rust
/// extern crate ethcore_util;
/// use ethcore_util::hashdb::*;
/// use ethcore_util::memorydb::*;
/// fn main() {
/// let mut m = MemoryDB::new();
/// let hello_bytes = "Hello world!".as_bytes();
/// let hash = m.insert(hello_bytes);
/// assert!(m.exists(&hash));
/// m.clear();
/// assert!(!m.exists(&hash));
/// }
/// ```
pub fn clear(&mut self) {
self.data.clear();
}
/// Purge all zero-referenced data from the database.
pub fn purge(&mut self) {
let empties: Vec<_> = self.data.iter()
.filter(|&(_, &(_, rc))| rc == 0)
.map(|(k, _)| k.clone())
.collect();
for empty in empties { self.data.remove(&empty); }
}
/// Grab the raw information associated with a key. Returns None if the key
/// doesn't exist.
///
/// Even when Some is returned, the data is only guaranteed to be useful
/// when the refs > 0.
pub fn raw(&self, key: &H256) -> Option<&(Bytes, i32)> {
if key == &SHA3_NULL_RLP {
return Some(&self.static_null_rlp);
}
self.data.get(key)
}
pub fn drain(&mut self) -> HashMap<H256, (Bytes, i32)> {
let mut data = HashMap::new();
mem::swap(&mut self.data, &mut data);
data
}
pub fn denote(&self, key: &H256, value: Bytes) -> &(Bytes, i32) {
if self.raw(key) == None {
unsafe {
let p = &self.data as *const HashMap<H256, (Bytes, i32)> as *mut HashMap<H256, (Bytes, i32)>;
(*p).insert(key.clone(), (value, 0));
}
}
self.raw(key).unwrap()
}
}
static NULL_RLP_STATIC: [u8; 1] = [0x80; 1];
impl HashDB for MemoryDB {
fn lookup(&self, key: &H256) -> Option<&[u8]> {
if key == &SHA3_NULL_RLP {
return Some(&NULL_RLP_STATIC);
}
match self.data.get(key) {
Some(&(ref d, rc)) if rc > 0 => Some(d),
_ => None
}
}
fn keys(&self) -> HashMap<H256, i32> {
self.data.iter().filter_map(|(k, v)| if v.1 != 0 {Some((k.clone(), v.1))} else {None}).collect()
}
fn exists(&self, key: &H256) -> bool {
if key == &SHA3_NULL_RLP {
return true;
}
match self.data.get(key) {
Some(&(_, x)) if x > 0 => true,
_ => false
}
}
fn insert(&mut self, value: &[u8]) -> H256 {
if value == &NULL_RLP {
return SHA3_NULL_RLP.clone();
}
let key = value.sha3();
if match self.data.get_mut(&key) {
Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => {
*old_value = From::from(value.bytes());
*rc += 1;
false
},
Some(&mut (_, ref mut x)) => { *x += 1; false } ,
None => true,
}{ // ... None falls through into...
self.data.insert(key.clone(), (From::from(value.bytes()), 1));
}
key
}
fn emplace(&mut self, key: H256, value: Bytes) {
if value == &NULL_RLP {
return;
}
match self.data.get_mut(&key) {
Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => {
*old_value = value;
*rc += 1;
return;
},
Some(&mut (_, ref mut x)) => { *x += 1; return; } ,
None => {},
}
// ... None falls through into...
self.data.insert(key, (value, 1));
}
fn kill(&mut self, key: &H256) {
if key == &SHA3_NULL_RLP {
return;
}
if match self.data.get_mut(key) {
Some(&mut (_, ref mut x)) => { *x -= 1; false }
None => true
}{ // ... None falls through into...
self.data.insert(key.clone(), (Bytes::new(), -1));
}
}
}
#[test]
fn memorydb_denote() {
let mut m = MemoryDB::new();
let hello_bytes = b"Hello world!";
let hash = m.insert(hello_bytes);
assert_eq!(m.lookup(&hash).unwrap(), b"Hello world!");
for _ in 0..1000 {
let r = H256::random();
let k = r.sha3();
let &(ref v, ref rc) = m.denote(&k, r.bytes().to_vec());
assert_eq!(v, &r.bytes());
assert_eq!(*rc, 0);
}
assert_eq!(m.lookup(&hash).unwrap(), b"Hello world!");
}

View File

@@ -1,31 +0,0 @@
use common::*;
#[derive(Debug,Clone,PartialEq,Eq)]
/// Diff type for specifying a change (or not).
pub enum Diff<T> where T: Eq {
Same,
Born(T),
Changed(T, T),
Died(T),
}
impl<T> Diff<T> where T: Eq {
/// Construct new object with given `pre` and `post`.
pub fn new(pre: T, post: T) -> Self { if pre == post { Diff::Same } else { Diff::Changed(pre, post) } }
/// Get the before value, if there is one.
pub fn pre(&self) -> Option<&T> { match self { &Diff::Died(ref x) | &Diff::Changed(ref x, _) => Some(x), _ => None } }
/// Get the after value, if there is one.
pub fn post(&self) -> Option<&T> { match self { &Diff::Born(ref x) | &Diff::Changed(_, ref x) => Some(x), _ => None } }
/// Determine whether there was a change or not.
pub fn is_same(&self) -> bool { match self { &Diff::Same => true, _ => false }}
}
#[derive(PartialEq,Eq,Clone,Copy)]
/// Boolean type for clean/dirty status.
pub enum Filth {
Clean,
Dirty,
}

View File

@@ -1,410 +0,0 @@
use std::collections::VecDeque;
use mio::{Handler, Token, EventSet, EventLoop, Timeout, PollOpt, TryRead, TryWrite};
use mio::tcp::*;
use hash::*;
use sha3::*;
use bytes::*;
use rlp::*;
use std::io::{self, Cursor, Read};
use error::*;
use network::error::NetworkError;
use network::handshake::Handshake;
use crypto;
use rcrypto::blockmodes::*;
use rcrypto::aessafe::*;
use rcrypto::symmetriccipher::*;
use rcrypto::buffer::*;
use tiny_keccak::Keccak;
const ENCRYPTED_HEADER_LEN: usize = 32;
/// Low level tcp connection
pub struct Connection {
/// Connection id (token)
pub token: Token,
/// Network socket
pub socket: TcpStream,
/// Receive buffer
rec_buf: Bytes,
/// Expected size
rec_size: usize,
/// Send out packets FIFO
send_queue: VecDeque<Cursor<Bytes>>,
/// Event flags this connection expects
interest: EventSet,
}
/// Connection write status.
#[derive(PartialEq, Eq)]
pub enum WriteStatus {
/// Some data is still pending for current packet
Ongoing,
/// All data sent.
Complete
}
impl Connection {
/// Create a new connection with given id and socket.
pub fn new(token: Token, socket: TcpStream) -> Connection {
Connection {
token: token,
socket: socket,
send_queue: VecDeque::new(),
rec_buf: Bytes::new(),
rec_size: 0,
interest: EventSet::hup(),
}
}
/// Put a connection into read mode. Receiving up `size` bytes of data.
pub fn expect(&mut self, size: usize) {
if self.rec_size != self.rec_buf.len() {
warn!(target:"net", "Unexpected connection read start");
}
unsafe { self.rec_buf.set_len(0) }
self.rec_size = size;
}
/// Readable IO handler. Called when there is some data to be read.
//TODO: return a slice
pub fn readable(&mut self) -> io::Result<Option<Bytes>> {
if self.rec_size == 0 || self.rec_buf.len() >= self.rec_size {
warn!(target:"net", "Unexpected connection read");
}
let max = self.rec_size - self.rec_buf.len();
// resolve "multiple applicable items in scope [E0034]" error
let sock_ref = <TcpStream as Read>::by_ref(&mut self.socket);
match sock_ref.take(max as u64).try_read_buf(&mut self.rec_buf) {
Ok(Some(_)) if self.rec_buf.len() == self.rec_size => {
self.rec_size = 0;
Ok(Some(::std::mem::replace(&mut self.rec_buf, Bytes::new())))
},
Ok(_) => Ok(None),
Err(e) => Err(e),
}
}
/// Add a packet to send queue.
pub fn send(&mut self, data: Bytes) {
if data.len() != 0 {
self.send_queue.push_back(Cursor::new(data));
}
if !self.interest.is_writable() {
self.interest.insert(EventSet::writable());
}
}
/// Writable IO handler. Called when the socket is ready to send.
pub fn writable(&mut self) -> io::Result<WriteStatus> {
if self.send_queue.is_empty() {
return Ok(WriteStatus::Complete)
}
{
let buf = self.send_queue.front_mut().unwrap();
let send_size = buf.get_ref().len();
if (buf.position() as usize) >= send_size {
warn!(target:"net", "Unexpected connection data");
return Ok(WriteStatus::Complete)
}
match self.socket.try_write_buf(buf) {
Ok(_) if (buf.position() as usize) < send_size => {
self.interest.insert(EventSet::writable());
Ok(WriteStatus::Ongoing)
},
Ok(_) if (buf.position() as usize) == send_size => {
Ok(WriteStatus::Complete)
},
Ok(_) => { panic!("Wrote past buffer");},
Err(e) => Err(e)
}
}.and_then(|r| {
if r == WriteStatus::Complete {
self.send_queue.pop_front();
}
if self.send_queue.is_empty() {
self.interest.remove(EventSet::writable());
}
else {
self.interest.insert(EventSet::writable());
}
Ok(r)
})
}
/// Register this connection with the IO event loop.
pub fn register<Host: Handler>(&mut self, event_loop: &mut EventLoop<Host>) -> io::Result<()> {
trace!(target: "net", "connection register; token={:?}", self.token);
self.interest.insert(EventSet::readable());
event_loop.register(&self.socket, self.token, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| {
error!("Failed to register {:?}, {:?}", self.token, e);
Err(e)
})
}
/// Update connection registration. Should be called at the end of the IO handler.
pub fn reregister<Host: Handler>(&mut self, event_loop: &mut EventLoop<Host>) -> io::Result<()> {
trace!(target: "net", "connection reregister; token={:?}", self.token);
event_loop.reregister( &self.socket, self.token, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| {
error!("Failed to reregister {:?}, {:?}", self.token, e);
Err(e)
})
}
}
/// RLPx packet
pub struct Packet {
pub protocol: u16,
pub data: Bytes,
}
/// Encrypted connection receiving state.
enum EncryptedConnectionState {
/// Reading a header.
Header,
/// Reading the rest of the packet.
Payload,
}
/// Connection implementing RLPx framing
/// https://github.com/ethereum/devp2p/blob/master/rlpx.md#framing
pub struct EncryptedConnection {
/// Underlying tcp connection
connection: Connection,
/// Egress data encryptor
encoder: CtrMode<AesSafe256Encryptor>,
/// Ingress data decryptor
decoder: CtrMode<AesSafe256Encryptor>,
/// Ingress data decryptor
mac_encoder: EcbEncryptor<AesSafe256Encryptor, EncPadding<NoPadding>>,
/// MAC for egress data
egress_mac: Keccak,
/// MAC for ingress data
ingress_mac: Keccak,
/// Read state
read_state: EncryptedConnectionState,
/// Disconnect timeout
idle_timeout: Option<Timeout>,
/// Protocol id for the last received packet
protocol_id: u16,
/// Payload expected to be received for the last header.
payload_len: usize,
}
impl EncryptedConnection {
/// Create an encrypted connection out of the handshake. Consumes a handshake object.
pub fn new(handshake: Handshake) -> Result<EncryptedConnection, UtilError> {
let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public));
let mut nonce_material = H512::new();
if handshake.originated {
handshake.remote_nonce.copy_to(&mut nonce_material[0..32]);
handshake.nonce.copy_to(&mut nonce_material[32..64]);
}
else {
handshake.nonce.copy_to(&mut nonce_material[0..32]);
handshake.remote_nonce.copy_to(&mut nonce_material[32..64]);
}
let mut key_material = H512::new();
shared.copy_to(&mut key_material[0..32]);
nonce_material.sha3_into(&mut key_material[32..64]);
key_material.sha3().copy_to(&mut key_material[32..64]);
key_material.sha3().copy_to(&mut key_material[32..64]);
let iv = vec![0u8; 16];
let encoder = CtrMode::new(AesSafe256Encryptor::new(&key_material[32..64]), iv);
let iv = vec![0u8; 16];
let decoder = CtrMode::new(AesSafe256Encryptor::new(&key_material[32..64]), iv);
key_material.sha3().copy_to(&mut key_material[32..64]);
let mac_encoder = EcbEncryptor::new(AesSafe256Encryptor::new(&key_material[32..64]), NoPadding);
let mut egress_mac = Keccak::new_keccak256();
let mut mac_material = &H256::from_slice(&key_material[32..64]) ^ &handshake.remote_nonce;
egress_mac.update(&mac_material);
egress_mac.update(if handshake.originated { &handshake.auth_cipher } else { &handshake.ack_cipher });
let mut ingress_mac = Keccak::new_keccak256();
mac_material = &H256::from_slice(&key_material[32..64]) ^ &handshake.nonce;
ingress_mac.update(&mac_material);
ingress_mac.update(if handshake.originated { &handshake.ack_cipher } else { &handshake.auth_cipher });
Ok(EncryptedConnection {
connection: handshake.connection,
encoder: encoder,
decoder: decoder,
mac_encoder: mac_encoder,
egress_mac: egress_mac,
ingress_mac: ingress_mac,
read_state: EncryptedConnectionState::Header,
idle_timeout: None,
protocol_id: 0,
payload_len: 0
})
}
/// Send a packet
pub fn send_packet(&mut self, payload: &[u8]) -> Result<(), UtilError> {
let mut header = RlpStream::new();
let len = payload.len() as usize;
header.append_raw(&[(len >> 16) as u8, (len >> 8) as u8, len as u8], 1);
header.append_raw(&[0xc2u8, 0x80u8, 0x80u8], 1);
//TODO: ger rid of vectors here
let mut header = header.out();
let padding = (16 - (payload.len() % 16)) % 16;
header.resize(16, 0u8);
let mut packet = vec![0u8; (32 + payload.len() + padding + 16)];
self.encoder.encrypt(&mut RefReadBuffer::new(&header), &mut RefWriteBuffer::new(&mut packet), false).expect("Invalid length or padding");
EncryptedConnection::update_mac(&mut self.egress_mac, &mut self.mac_encoder, &packet[0..16]);
self.egress_mac.clone().finalize(&mut packet[16..32]);
self.encoder.encrypt(&mut RefReadBuffer::new(&payload), &mut RefWriteBuffer::new(&mut packet[32..(32 + len)]), padding == 0).expect("Invalid length or padding");
if padding != 0 {
let pad = [0u8; 16];
self.encoder.encrypt(&mut RefReadBuffer::new(&pad[0..padding]), &mut RefWriteBuffer::new(&mut packet[(32 + len)..(32 + len + padding)]), true).expect("Invalid length or padding");
}
self.egress_mac.update(&packet[32..(32 + len + padding)]);
EncryptedConnection::update_mac(&mut self.egress_mac, &mut self.mac_encoder, &[0u8; 0]);
self.egress_mac.clone().finalize(&mut packet[(32 + len + padding)..]);
self.connection.send(packet);
Ok(())
}
/// Decrypt and authenticate an incoming packet header. Prepare for receiving payload.
fn read_header(&mut self, header: &[u8]) -> Result<(), UtilError> {
if header.len() != ENCRYPTED_HEADER_LEN {
return Err(From::from(NetworkError::Auth));
}
EncryptedConnection::update_mac(&mut self.ingress_mac, &mut self.mac_encoder, &header[0..16]);
let mac = &header[16..];
let mut expected = H256::new();
self.ingress_mac.clone().finalize(&mut expected);
if mac != &expected[0..16] {
return Err(From::from(NetworkError::Auth));
}
let mut hdec = H128::new();
self.decoder.decrypt(&mut RefReadBuffer::new(&header[0..16]), &mut RefWriteBuffer::new(&mut hdec), false).expect("Invalid length or padding");
let length = ((((hdec[0] as u32) << 8) + (hdec[1] as u32)) << 8) + (hdec[2] as u32);
let header_rlp = UntrustedRlp::new(&hdec[3..6]);
let protocol_id = try!(header_rlp.val_at::<u16>(0));
self.payload_len = length as usize;
self.protocol_id = protocol_id;
self.read_state = EncryptedConnectionState::Payload;
let padding = (16 - (length % 16)) % 16;
let full_length = length + padding + 16;
self.connection.expect(full_length as usize);
Ok(())
}
/// Decrypt and authenticate packet payload.
fn read_payload(&mut self, payload: &[u8]) -> Result<Packet, UtilError> {
let padding = (16 - (self.payload_len % 16)) % 16;
let full_length = self.payload_len + padding + 16;
if payload.len() != full_length {
return Err(From::from(NetworkError::Auth));
}
self.ingress_mac.update(&payload[0..payload.len() - 16]);
EncryptedConnection::update_mac(&mut self.ingress_mac, &mut self.mac_encoder, &[0u8; 0]);
let mac = &payload[(payload.len() - 16)..];
let mut expected = H128::new();
self.ingress_mac.clone().finalize(&mut expected);
if mac != &expected[..] {
return Err(From::from(NetworkError::Auth));
}
let mut packet = vec![0u8; self.payload_len];
self.decoder.decrypt(&mut RefReadBuffer::new(&payload[0..self.payload_len]), &mut RefWriteBuffer::new(&mut packet), false).expect("Invalid length or padding");
let mut pad_buf = [0u8; 16];
self.decoder.decrypt(&mut RefReadBuffer::new(&payload[self.payload_len..(payload.len() - 16)]), &mut RefWriteBuffer::new(&mut pad_buf), false).expect("Invalid length or padding");
Ok(Packet {
protocol: self.protocol_id,
data: packet
})
}
/// Update MAC after reading or writing any data.
fn update_mac(mac: &mut Keccak, mac_encoder: &mut EcbEncryptor<AesSafe256Encryptor, EncPadding<NoPadding>>, seed: &[u8]) {
let mut prev = H128::new();
mac.clone().finalize(&mut prev);
let mut enc = H128::new();
mac_encoder.encrypt(&mut RefReadBuffer::new(&prev), &mut RefWriteBuffer::new(&mut enc), true).unwrap();
mac_encoder.reset();
enc = enc ^ if seed.is_empty() { prev } else { H128::from_slice(seed) };
mac.update(&enc);
}
/// Readable IO handler. Tracker receive status and returns decoded packet if avaialable.
pub fn readable<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>) -> Result<Option<Packet>, UtilError> {
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
match self.read_state {
EncryptedConnectionState::Header => {
match try!(self.connection.readable()) {
Some(data) => {
try!(self.read_header(&data));
},
None => {}
};
Ok(None)
},
EncryptedConnectionState::Payload => {
match try!(self.connection.readable()) {
Some(data) => {
self.read_state = EncryptedConnectionState::Header;
self.connection.expect(ENCRYPTED_HEADER_LEN);
Ok(Some(try!(self.read_payload(&data))))
},
None => Ok(None)
}
}
}
}
/// Writable IO handler. Processes send queeue.
pub fn writable<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>) -> Result<(), UtilError> {
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
try!(self.connection.writable());
Ok(())
}
/// Register this connection with the event handler.
pub fn register<Host:Handler<Timeout=Token>>(&mut self, event_loop: &mut EventLoop<Host>) -> Result<(), UtilError> {
self.connection.expect(ENCRYPTED_HEADER_LEN);
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
self.idle_timeout = event_loop.timeout_ms(self.connection.token, 1800).ok();
try!(self.connection.reregister(event_loop));
Ok(())
}
/// Update connection registration. This should be called at the end of the event loop.
pub fn reregister<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>) -> Result<(), UtilError> {
try!(self.connection.reregister(event_loop));
Ok(())
}
}
#[test]
pub fn test_encryption() {
use hash::*;
use std::str::FromStr;
let key = H256::from_str("2212767d793a7a3d66f869ae324dd11bd17044b82c9f463b8a541a4d089efec5").unwrap();
let before = H128::from_str("12532abaec065082a3cf1da7d0136f15").unwrap();
let before2 = H128::from_str("7e99f682356fdfbc6b67a9562787b18a").unwrap();
let after = H128::from_str("89464c6b04e7c99e555c81d3f7266a05").unwrap();
let after2 = H128::from_str("85c070030589ef9c7a2879b3a8489316").unwrap();
let mut got = H128::new();
let mut encoder = EcbEncryptor::new(AesSafe256Encryptor::new(&key), NoPadding);
encoder.encrypt(&mut RefReadBuffer::new(&before), &mut RefWriteBuffer::new(&mut got), true).unwrap();
encoder.reset();
assert_eq!(got, after);
got = H128::new();
encoder.encrypt(&mut RefReadBuffer::new(&before2), &mut RefWriteBuffer::new(&mut got), true).unwrap();
encoder.reset();
assert_eq!(got, after2);
}

View File

@@ -1,206 +0,0 @@
// This module is a work in progress
#![allow(dead_code)] //TODO: remove this after everything is done
use std::collections::{HashSet, BTreeMap};
use std::cell::{RefCell};
use std::ops::{DerefMut};
use mio::*;
use mio::udp::*;
use hash::*;
use sha3::Hashable;
use crypto::*;
use network::node::*;
const ADDRESS_BYTES_SIZE: u32 = 32; ///< Size of address type in bytes.
const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE; ///< Denoted by n in [Kademlia].
const NODE_BINS: u32 = ADDRESS_BITS - 1; ///< Size of m_state (excludes root, which is us).
const DISCOVERY_MAX_STEPS: u16 = 8; ///< Max iterations of discovery. (discover)
const BUCKET_SIZE: u32 = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket.
const ALPHA: usize = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests.
struct NodeBucket {
distance: u32,
nodes: Vec<NodeId>
}
impl NodeBucket {
fn new(distance: u32) -> NodeBucket {
NodeBucket {
distance: distance,
nodes: Vec::new()
}
}
}
struct Discovery {
id: NodeId,
discovery_round: u16,
discovery_id: NodeId,
discovery_nodes: HashSet<NodeId>,
node_buckets: Vec<NodeBucket>,
}
struct FindNodePacket;
impl FindNodePacket {
fn new(_endpoint: &NodeEndpoint, _id: &NodeId) -> FindNodePacket {
FindNodePacket
}
fn sign(&mut self, _secret: &Secret) {
}
fn send(& self, _socket: &mut UdpSocket) {
}
}
impl Discovery {
pub fn new(id: &NodeId) -> Discovery {
Discovery {
id: id.clone(),
discovery_round: 0,
discovery_id: NodeId::new(),
discovery_nodes: HashSet::new(),
node_buckets: (0..NODE_BINS).map(|x| NodeBucket::new(x)).collect(),
}
}
pub fn add_node(&mut self, id: &NodeId) {
self.node_buckets[Discovery::distance(&self.id, &id) as usize].nodes.push(id.clone());
}
fn start_node_discovery<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>) {
self.discovery_round = 0;
self.discovery_id.randomize();
self.discovery_nodes.clear();
self.discover(event_loop);
}
fn discover<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>) {
if self.discovery_round == DISCOVERY_MAX_STEPS
{
debug!("Restarting discovery");
self.start_node_discovery(event_loop);
return;
}
let mut tried_count = 0;
{
let nearest = Discovery::nearest_node_entries(&self.id, &self.discovery_id, &self.node_buckets).into_iter();
let nodes = RefCell::new(&mut self.discovery_nodes);
let nearest = nearest.filter(|x| nodes.borrow().contains(&x)).take(ALPHA);
for r in nearest {
//let mut p = FindNodePacket::new(&r.endpoint, &self.discovery_id);
//p.sign(&self.secret);
//p.send(&mut self.udp_socket);
let mut borrowed = nodes.borrow_mut();
borrowed.deref_mut().insert(r.clone());
tried_count += 1;
}
}
if tried_count == 0
{
debug!("Restarting discovery");
self.start_node_discovery(event_loop);
return;
}
self.discovery_round += 1;
//event_loop.timeout_ms(Token(NODETABLE_DISCOVERY), 1200).unwrap();
}
fn distance(a: &NodeId, b: &NodeId) -> u32 {
let d = a.sha3() ^ b.sha3();
let mut ret:u32 = 0;
for i in 0..32 {
let mut v: u8 = d[i];
while v != 0 {
v >>= 1;
ret += 1;
}
}
ret
}
fn nearest_node_entries<'b>(source: &NodeId, target: &NodeId, buckets: &'b Vec<NodeBucket>) -> Vec<&'b NodeId>
{
// send ALPHA FindNode packets to nodes we know, closest to target
const LAST_BIN: u32 = NODE_BINS - 1;
let mut head = Discovery::distance(source, target);
let mut tail = if head == 0 { LAST_BIN } else { (head - 1) % NODE_BINS };
let mut found: BTreeMap<u32, Vec<&'b NodeId>> = BTreeMap::new();
let mut count = 0;
// if d is 0, then we roll look forward, if last, we reverse, else, spread from d
if head > 1 && tail != LAST_BIN {
while head != tail && head < NODE_BINS && count < BUCKET_SIZE
{
for n in buckets[head as usize].nodes.iter()
{
if count < BUCKET_SIZE {
count += 1;
found.entry(Discovery::distance(target, &n)).or_insert(Vec::new()).push(n);
}
else {
break;
}
}
if count < BUCKET_SIZE && tail != 0 {
for n in buckets[tail as usize].nodes.iter() {
if count < BUCKET_SIZE {
count += 1;
found.entry(Discovery::distance(target, &n)).or_insert(Vec::new()).push(n);
}
else {
break;
}
}
}
head += 1;
if tail > 0 {
tail -= 1;
}
}
}
else if head < 2 {
while head < NODE_BINS && count < BUCKET_SIZE {
for n in buckets[head as usize].nodes.iter() {
if count < BUCKET_SIZE {
count += 1;
found.entry(Discovery::distance(target, &n)).or_insert(Vec::new()).push(n);
}
else {
break;
}
}
head += 1;
}
}
else {
while tail > 0 && count < BUCKET_SIZE {
for n in buckets[tail as usize].nodes.iter() {
if count < BUCKET_SIZE {
count += 1;
found.entry(Discovery::distance(target, &n)).or_insert(Vec::new()).push(n);
}
else {
break;
}
}
tail -= 1;
}
}
let mut ret:Vec<&NodeId> = Vec::new();
for (_, nodes) in found {
for n in nodes {
if ret.len() < BUCKET_SIZE as usize /* && n->endpoint && n->endpoint.isAllowed() */ {
ret.push(n);
}
}
}
ret
}
}

View File

@@ -1,41 +0,0 @@
use io::IoError;
use rlp::*;
#[derive(Debug, Copy, Clone)]
pub enum DisconnectReason
{
DisconnectRequested,
//TCPError,
//BadProtocol,
UselessPeer,
//TooManyPeers,
//DuplicatePeer,
//IncompatibleProtocol,
//NullIdentity,
//ClientQuit,
//UnexpectedIdentity,
//LocalIdentity,
//PingTimeout,
}
#[derive(Debug)]
pub enum NetworkError {
Auth,
BadProtocol,
PeerNotFound,
Disconnect(DisconnectReason),
Io(IoError),
}
impl From<DecoderError> for NetworkError {
fn from(_err: DecoderError) -> NetworkError {
NetworkError::Auth
}
}
impl From<IoError> for NetworkError {
fn from(err: IoError) -> NetworkError {
NetworkError::Io(err)
}
}

View File

@@ -1,217 +0,0 @@
use mio::*;
use mio::tcp::*;
use hash::*;
use sha3::Hashable;
use bytes::Bytes;
use crypto::*;
use crypto;
use network::connection::{Connection};
use network::host::{HostInfo};
use network::node::NodeId;
use error::*;
use network::error::NetworkError;
#[derive(PartialEq, Eq, Debug)]
enum HandshakeState {
/// Just created
New,
/// Waiting for auth packet
ReadingAuth,
/// Waiting for ack packet
ReadingAck,
/// Ready to start a session
StartSession,
}
/// RLPx protocol handhake. See https://github.com/ethereum/devp2p/blob/master/rlpx.md#encrypted-handshake
pub struct Handshake {
/// Remote node public key
pub id: NodeId,
/// Underlying connection
pub connection: Connection,
/// Handshake state
state: HandshakeState,
/// Outgoing or incoming connection
pub originated: bool,
/// Disconnect timeout
idle_timeout: Option<Timeout>,
/// ECDH ephemeral
pub ecdhe: KeyPair,
/// Connection nonce
pub nonce: H256,
/// Handshake public key
pub remote_public: Public,
/// Remote connection nonce.
pub remote_nonce: H256,
/// A copy of received encryped auth packet
pub auth_cipher: Bytes,
/// A copy of received encryped ack packet
pub ack_cipher: Bytes
}
const AUTH_PACKET_SIZE: usize = 307;
const ACK_PACKET_SIZE: usize = 210;
impl Handshake {
/// Create a new handshake object
pub fn new(token: Token, id: &NodeId, socket: TcpStream, nonce: &H256) -> Result<Handshake, UtilError> {
Ok(Handshake {
id: id.clone(),
connection: Connection::new(token, socket),
originated: false,
state: HandshakeState::New,
idle_timeout: None,
ecdhe: try!(KeyPair::create()),
nonce: nonce.clone(),
remote_public: Public::new(),
remote_nonce: H256::new(),
auth_cipher: Bytes::new(),
ack_cipher: Bytes::new(),
})
}
/// Start a handhsake
pub fn start(&mut self, host: &HostInfo, originated: bool) -> Result<(), UtilError> {
self.originated = originated;
if originated {
try!(self.write_auth(host));
}
else {
self.state = HandshakeState::ReadingAuth;
self.connection.expect(AUTH_PACKET_SIZE);
};
Ok(())
}
/// Check if handshake is complete
pub fn done(&self) -> bool {
self.state == HandshakeState::StartSession
}
/// Readable IO handler. Drives the state change.
pub fn readable<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>, host: &HostInfo) -> Result<(), UtilError> {
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
match self.state {
HandshakeState::ReadingAuth => {
match try!(self.connection.readable()) {
Some(data) => {
try!(self.read_auth(host, &data));
try!(self.write_ack());
},
None => {}
};
},
HandshakeState::ReadingAck => {
match try!(self.connection.readable()) {
Some(data) => {
try!(self.read_ack(host, &data));
self.state = HandshakeState::StartSession;
},
None => {}
};
},
_ => { panic!("Unexpected state"); }
}
if self.state != HandshakeState::StartSession {
try!(self.connection.reregister(event_loop));
}
Ok(())
}
/// Writabe IO handler.
pub fn writable<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>, _host: &HostInfo) -> Result<(), UtilError> {
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
try!(self.connection.writable());
if self.state != HandshakeState::StartSession {
try!(self.connection.reregister(event_loop));
}
Ok(())
}
/// Register the IO handler with the event loop
pub fn register<Host:Handler<Timeout=Token>>(&mut self, event_loop: &mut EventLoop<Host>) -> Result<(), UtilError> {
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
self.idle_timeout = event_loop.timeout_ms(self.connection.token, 1800).ok();
try!(self.connection.register(event_loop));
Ok(())
}
/// Parse, validate and confirm auth message
fn read_auth(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), UtilError> {
trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr());
assert!(data.len() == AUTH_PACKET_SIZE);
self.auth_cipher = data.to_vec();
let auth = try!(ecies::decrypt(host.secret(), data));
let (sig, rest) = auth.split_at(65);
let (hepubk, rest) = rest.split_at(32);
let (pubk, rest) = rest.split_at(64);
let (nonce, _) = rest.split_at(32);
self.remote_public.clone_from_slice(pubk);
self.remote_nonce.clone_from_slice(nonce);
let shared = try!(ecdh::agree(host.secret(), &self.remote_public));
let signature = Signature::from_slice(sig);
let spub = try!(ec::recover(&signature, &(&shared ^ &self.remote_nonce)));
if &spub.sha3()[..] != hepubk {
trace!(target:"net", "Handshake hash mismath with {:?}", self.connection.socket.peer_addr());
return Err(From::from(NetworkError::Auth));
};
self.write_ack()
}
/// Parse and validate ack message
fn read_ack(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), UtilError> {
trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr());
assert!(data.len() == ACK_PACKET_SIZE);
self.ack_cipher = data.to_vec();
let ack = try!(ecies::decrypt(host.secret(), data));
self.remote_public.clone_from_slice(&ack[0..64]);
self.remote_nonce.clone_from_slice(&ack[64..(64+32)]);
Ok(())
}
/// Sends auth message
fn write_auth(&mut self, host: &HostInfo) -> Result<(), UtilError> {
trace!(target:"net", "Sending handshake auth to {:?}", self.connection.socket.peer_addr());
let mut data = [0u8; /*Signature::SIZE*/ 65 + /*H256::SIZE*/ 32 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32 + 1]; //TODO: use associated constants
let len = data.len();
{
data[len - 1] = 0x0;
let (sig, rest) = data.split_at_mut(65);
let (hepubk, rest) = rest.split_at_mut(32);
let (pubk, rest) = rest.split_at_mut(64);
let (nonce, _) = rest.split_at_mut(32);
// E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
let shared = try!(crypto::ecdh::agree(host.secret(), &self.id));
try!(crypto::ec::sign(self.ecdhe.secret(), &(&shared ^ &self.nonce))).copy_to(sig);
self.ecdhe.public().sha3_into(hepubk);
host.id().copy_to(pubk);
self.nonce.copy_to(nonce);
}
let message = try!(crypto::ecies::encrypt(&self.id, &data));
self.auth_cipher = message.clone();
self.connection.send(message);
self.connection.expect(ACK_PACKET_SIZE);
self.state = HandshakeState::ReadingAck;
Ok(())
}
/// Sends ack message
fn write_ack(&mut self) -> Result<(), UtilError> {
trace!(target:"net", "Sending handshake ack to {:?}", self.connection.socket.peer_addr());
let mut data = [0u8; 1 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32]; //TODO: use associated constants
let len = data.len();
{
data[len - 1] = 0x0;
let (epubk, rest) = data.split_at_mut(64);
let (nonce, _) = rest.split_at_mut(32);
self.ecdhe.public().copy_to(epubk);
self.nonce.copy_to(nonce);
}
let message = try!(crypto::ecies::encrypt(&self.id, &data));
self.ack_cipher = message.clone();
self.connection.send(message);
self.state = HandshakeState::StartSession;
Ok(())
}
}

View File

@@ -1,651 +0,0 @@
use std::mem;
use std::net::{SocketAddr};
use std::collections::{HashMap};
use std::hash::{Hasher};
use std::str::{FromStr};
use mio::*;
use mio::tcp::*;
use mio::udp::*;
use hash::*;
use crypto::*;
use sha3::Hashable;
use rlp::*;
use network::handshake::Handshake;
use network::session::{Session, SessionData};
use error::*;
use io::*;
use network::NetworkProtocolHandler;
use network::node::*;
type Slab<T> = ::slab::Slab<T, usize>;
const _DEFAULT_PORT: u16 = 30304;
const MAX_CONNECTIONS: usize = 1024;
const IDEAL_PEERS: u32 = 10;
const MAINTENANCE_TIMEOUT: u64 = 1000;
#[derive(Debug)]
struct NetworkConfiguration {
listen_address: SocketAddr,
public_address: SocketAddr,
nat_enabled: bool,
discovery_enabled: bool,
pin: bool,
}
impl NetworkConfiguration {
fn new() -> NetworkConfiguration {
NetworkConfiguration {
listen_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(),
public_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(),
nat_enabled: true,
discovery_enabled: true,
pin: false,
}
}
}
// Tokens
//const TOKEN_BEGIN: usize = USER_TOKEN_START; // TODO: ICE in rustc 1.7.0-nightly (49c382779 2016-01-12)
const TOKEN_BEGIN: usize = 32;
const TCP_ACCEPT: usize = TOKEN_BEGIN + 1;
const IDLE: usize = TOKEN_BEGIN + 2;
const NODETABLE_RECEIVE: usize = TOKEN_BEGIN + 3;
const NODETABLE_MAINTAIN: usize = TOKEN_BEGIN + 4;
const NODETABLE_DISCOVERY: usize = TOKEN_BEGIN + 5;
const FIRST_CONNECTION: usize = TOKEN_BEGIN + 16;
const LAST_CONNECTION: usize = FIRST_CONNECTION + MAX_CONNECTIONS - 1;
/// Protocol handler level packet id
pub type PacketId = u8;
/// Protocol / handler id
pub type ProtocolId = &'static str;
/// Messages used to communitate with the event loop from other threads.
pub enum NetworkIoMessage<Message> where Message: Send {
/// Register a new protocol handler.
AddHandler {
handler: Option<Box<NetworkProtocolHandler<Message>+Send>>,
protocol: ProtocolId,
versions: Vec<u8>,
},
/// Send data over the network.
Send {
peer: PeerId,
packet_id: PacketId,
protocol: ProtocolId,
data: Vec<u8>,
},
/// User message
User(Message),
}
/// Local (temporary) peer session ID.
pub type PeerId = usize;
#[derive(Debug, PartialEq, Eq)]
/// Protocol info
pub struct CapabilityInfo {
pub protocol: ProtocolId,
pub version: u8,
/// Total number of packet IDs this protocol support.
pub packet_count: u8,
}
impl Encodable for CapabilityInfo {
fn encode<E>(&self, encoder: &mut E) -> () where E: Encoder {
encoder.emit_list(|e| {
self.protocol.encode(e);
(self.version as u32).encode(e);
});
}
}
/// IO access point. This is passed to all IO handlers and provides an interface to the IO subsystem.
pub struct NetworkContext<'s, 'io, Message> where Message: Send + 'static, 'io: 's {
io: &'s mut IoContext<'io, NetworkIoMessage<Message>>,
protocol: ProtocolId,
connections: &'s mut Slab<ConnectionEntry>,
timers: &'s mut HashMap<TimerToken, ProtocolId>,
session: Option<StreamToken>,
}
impl<'s, 'io, Message> NetworkContext<'s, 'io, Message> where Message: Send + 'static, {
/// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler.
fn new(io: &'s mut IoContext<'io, NetworkIoMessage<Message>>,
protocol: ProtocolId,
session: Option<StreamToken>, connections: &'s mut Slab<ConnectionEntry>,
timers: &'s mut HashMap<TimerToken, ProtocolId>) -> NetworkContext<'s, 'io, Message> {
NetworkContext {
io: io,
protocol: protocol,
session: session,
connections: connections,
timers: timers,
}
}
/// Send a packet over the network to another peer.
pub fn send(&mut self, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError> {
match self.connections.get_mut(peer) {
Some(&mut ConnectionEntry::Session(ref mut s)) => {
s.send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| {
warn!(target: "net", "Send error: {:?}", e);
}); //TODO: don't copy vector data
},
_ => {
warn!(target: "net", "Send: Peer does not exist");
}
}
Ok(())
}
/// Respond to a current network message. Panics if no there is no packet in the context.
pub fn respond(&mut self, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError> {
match self.session {
Some(session) => self.send(session, packet_id, data),
None => {
panic!("Respond: Session does not exist")
}
}
}
/// Disable current protocol capability for given peer. If no capabilities left peer gets disconnected.
pub fn disable_peer(&mut self, _peer: PeerId) {
//TODO: remove capability, disconnect if no capabilities left
}
/// Register a new IO timer. Returns a new timer token. 'NetworkProtocolHandler::timeout' will be called with the token.
pub fn register_timer(&mut self, ms: u64) -> Result<TimerToken, UtilError>{
match self.io.register_timer(ms) {
Ok(token) => {
self.timers.insert(token, self.protocol);
Ok(token)
},
e => e,
}
}
/// Returns peer identification string
pub fn peer_info(&self, peer: PeerId) -> String {
match self.connections.get(peer) {
Some(&ConnectionEntry::Session(ref s)) => {
s.info.client_version.clone()
},
_ => {
"unknown".to_string()
}
}
}
}
/// Shared host information
pub struct HostInfo {
/// Our private and public keys.
keys: KeyPair,
/// Current network configuration
config: NetworkConfiguration,
/// Connection nonce.
nonce: H256,
/// RLPx protocol version
pub protocol_version: u32,
/// Client identifier
pub client_version: String,
/// TCP connection port.
pub listen_port: u16,
/// Registered capabilities (handlers)
pub capabilities: Vec<CapabilityInfo>
}
impl HostInfo {
/// Returns public key
pub fn id(&self) -> &NodeId {
self.keys.public()
}
/// Returns secret key
pub fn secret(&self) -> &Secret {
self.keys.secret()
}
/// Increments and returns connection nonce.
pub fn next_nonce(&mut self) -> H256 {
self.nonce = self.nonce.sha3();
return self.nonce.clone();
}
}
enum ConnectionEntry {
Handshake(Handshake),
Session(Session)
}
/// Root IO handler. Manages protocol handlers, IO timers and network connections.
pub struct Host<Message> where Message: Send {
pub info: HostInfo,
udp_socket: UdpSocket,
listener: TcpListener,
connections: Slab<ConnectionEntry>,
timers: HashMap<TimerToken, ProtocolId>,
nodes: HashMap<NodeId, Node>,
handlers: HashMap<ProtocolId, Box<NetworkProtocolHandler<Message>>>,
}
impl<Message> Host<Message> where Message: Send {
pub fn new() -> Host<Message> {
let config = NetworkConfiguration::new();
let addr = config.listen_address;
// Setup the server socket
let listener = TcpListener::bind(&addr).unwrap();
let udp_socket = UdpSocket::bound(&addr).unwrap();
Host::<Message> {
info: HostInfo {
keys: KeyPair::create().unwrap(),
config: config,
nonce: H256::random(),
protocol_version: 4,
client_version: "parity".to_string(),
listen_port: 0,
capabilities: Vec::new(),
},
udp_socket: udp_socket,
listener: listener,
connections: Slab::new_starting_at(FIRST_CONNECTION, MAX_CONNECTIONS),
timers: HashMap::new(),
nodes: HashMap::new(),
handlers: HashMap::new(),
}
}
fn add_node(&mut self, id: &str) {
match Node::from_str(id) {
Err(e) => { warn!("Could not add node: {:?}", e); },
Ok(n) => {
self.nodes.insert(n.id.clone(), n);
}
}
}
fn maintain_network(&mut self, io: &mut IoContext<NetworkIoMessage<Message>>) {
self.connect_peers(io);
io.event_loop.timeout_ms(Token(IDLE), MAINTENANCE_TIMEOUT).unwrap();
}
fn have_session(&self, id: &NodeId) -> bool {
self.connections.iter().any(|e| match e { &ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false })
}
fn connecting_to(&self, id: &NodeId) -> bool {
self.connections.iter().any(|e| match e { &ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false })
}
fn connect_peers(&mut self, io: &mut IoContext<NetworkIoMessage<Message>>) {
struct NodeInfo {
id: NodeId,
peer_type: PeerType
}
let mut to_connect: Vec<NodeInfo> = Vec::new();
let mut req_conn = 0;
//TODO: use nodes from discovery here
//for n in self.node_buckets.iter().flat_map(|n| &n.nodes).map(|id| NodeInfo { id: id.clone(), peer_type: self.nodes.get(id).unwrap().peer_type}) {
for n in self.nodes.values().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) {
let connected = self.have_session(&n.id) || self.connecting_to(&n.id);
let required = n.peer_type == PeerType::Required;
if connected && required {
req_conn += 1;
}
else if !connected && (!self.info.config.pin || required) {
to_connect.push(n);
}
}
for n in to_connect.iter() {
if n.peer_type == PeerType::Required {
if req_conn < IDEAL_PEERS {
self.connect_peer(&n.id, io);
}
req_conn += 1;
}
}
if !self.info.config.pin
{
let pending_count = 0; //TODO:
let peer_count = 0;
let mut open_slots = IDEAL_PEERS - peer_count - pending_count + req_conn;
if open_slots > 0 {
for n in to_connect.iter() {
if n.peer_type == PeerType::Optional && open_slots > 0 {
open_slots -= 1;
self.connect_peer(&n.id, io);
}
}
}
}
}
fn connect_peer(&mut self, id: &NodeId, io: &mut IoContext<NetworkIoMessage<Message>>) {
if self.have_session(id)
{
warn!("Aborted connect. Node already connected.");
return;
}
if self.connecting_to(id)
{
warn!("Aborted connect. Node already connecting.");
return;
}
let socket = {
let node = self.nodes.get_mut(id).unwrap();
node.last_attempted = Some(::time::now());
match TcpStream::connect(&node.endpoint.address) {
Ok(socket) => socket,
Err(_) => {
warn!("Cannot connect to node");
return;
}
}
};
let nonce = self.info.next_nonce();
match self.connections.insert_with(|token| ConnectionEntry::Handshake(Handshake::new(Token(token), id, socket, &nonce).expect("Can't create handshake"))) {
Some(token) => {
match self.connections.get_mut(token) {
Some(&mut ConnectionEntry::Handshake(ref mut h)) => {
h.start(&self.info, true)
.and_then(|_| h.register(io.event_loop))
.unwrap_or_else (|e| {
debug!(target: "net", "Handshake create error: {:?}", e);
});
},
_ => {}
}
},
None => { warn!("Max connections reached") }
}
}
fn accept(&mut self, _io: &mut IoContext<NetworkIoMessage<Message>>) {
trace!(target: "net", "accept");
}
fn connection_writable<'s>(&'s mut self, token: StreamToken, io: &mut IoContext<'s, NetworkIoMessage<Message>>) {
let mut kill = false;
let mut create_session = false;
match self.connections.get_mut(token) {
Some(&mut ConnectionEntry::Handshake(ref mut h)) => {
h.writable(io.event_loop, &self.info).unwrap_or_else(|e| {
debug!(target: "net", "Handshake write error: {:?}", e);
kill = true;
});
create_session = h.done();
},
Some(&mut ConnectionEntry::Session(ref mut s)) => {
s.writable(io.event_loop, &self.info).unwrap_or_else(|e| {
debug!(target: "net", "Session write error: {:?}", e);
kill = true;
});
}
_ => {
warn!(target: "net", "Received event for unknown connection");
}
}
if kill {
self.kill_connection(token, io);
return;
} else if create_session {
self.start_session(token, io);
}
match self.connections.get_mut(token) {
Some(&mut ConnectionEntry::Session(ref mut s)) => {
s.reregister(io.event_loop).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e));
},
_ => (),
}
}
fn connection_closed<'s>(&'s mut self, token: TimerToken, io: &mut IoContext<'s, NetworkIoMessage<Message>>) {
self.kill_connection(token, io);
}
fn connection_readable<'s>(&'s mut self, token: StreamToken, io: &mut IoContext<'s, NetworkIoMessage<Message>>) {
let mut kill = false;
let mut create_session = false;
let mut ready_data: Vec<ProtocolId> = Vec::new();
let mut packet_data: Option<(ProtocolId, PacketId, Vec<u8>)> = None;
match self.connections.get_mut(token) {
Some(&mut ConnectionEntry::Handshake(ref mut h)) => {
h.readable(io.event_loop, &self.info).unwrap_or_else(|e| {
debug!(target: "net", "Handshake read error: {:?}", e);
kill = true;
});
create_session = h.done();
},
Some(&mut ConnectionEntry::Session(ref mut s)) => {
let sd = { s.readable(io.event_loop, &self.info).unwrap_or_else(|e| {
debug!(target: "net", "Session read error: {:?}", e);
kill = true;
SessionData::None
}) };
match sd {
SessionData::Ready => {
for (p, _) in self.handlers.iter_mut() {
if s.have_capability(p) {
ready_data.push(p);
}
}
},
SessionData::Packet {
data,
protocol,
packet_id,
} => {
match self.handlers.get_mut(protocol) {
None => { warn!(target: "net", "No handler found for protocol: {:?}", protocol) },
Some(_) => packet_data = Some((protocol, packet_id, data)),
}
},
SessionData::None => {},
}
}
_ => {
warn!(target: "net", "Received event for unknown connection");
}
}
if kill {
self.kill_connection(token, io);
return;
}
if create_session {
self.start_session(token, io);
}
for p in ready_data {
let mut h = self.handlers.get_mut(p).unwrap();
h.connected(&mut NetworkContext::new(io, p, Some(token), &mut self.connections, &mut self.timers), &token);
}
if let Some((p, packet_id, data)) = packet_data {
let mut h = self.handlers.get_mut(p).unwrap();
h.read(&mut NetworkContext::new(io, p, Some(token), &mut self.connections, &mut self.timers), &token, packet_id, &data[1..]);
}
match self.connections.get_mut(token) {
Some(&mut ConnectionEntry::Session(ref mut s)) => {
s.reregister(io.event_loop).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e));
},
_ => (),
}
}
fn start_session(&mut self, token: StreamToken, io: &mut IoContext<NetworkIoMessage<Message>>) {
let info = &self.info;
// TODO: use slab::replace_with (currently broken)
/*
match self.connections.remove(token) {
Some(ConnectionEntry::Handshake(h)) => {
match Session::new(h, io.event_loop, info) {
Ok(session) => {
assert!(token == self.connections.insert(ConnectionEntry::Session(session)).ok().unwrap());
},
Err(e) => {
debug!(target: "net", "Session construction error: {:?}", e);
}
}
},
_ => panic!("Error updating slab with session")
}*/
self.connections.replace_with(token, |c| {
match c {
ConnectionEntry::Handshake(h) => Session::new(h, io.event_loop, info)
.map(|s| Some(ConnectionEntry::Session(s)))
.unwrap_or_else(|e| {
debug!(target: "net", "Session construction error: {:?}", e);
None
}),
_ => { panic!("No handshake to create a session from"); }
}
}).expect("Error updating slab with session");
}
fn connection_timeout<'s>(&'s mut self, token: StreamToken, io: &mut IoContext<'s, NetworkIoMessage<Message>>) {
self.kill_connection(token, io)
}
fn kill_connection<'s>(&'s mut self, token: StreamToken, io: &mut IoContext<'s, NetworkIoMessage<Message>>) {
let mut to_disconnect: Vec<ProtocolId> = Vec::new();
let mut remove = true;
match self.connections.get_mut(token) {
Some(&mut ConnectionEntry::Handshake(_)) => (), // just abandon handshake
Some(&mut ConnectionEntry::Session(ref mut s)) if s.is_ready() => {
for (p, _) in self.handlers.iter_mut() {
if s.have_capability(p) {
to_disconnect.push(p);
}
}
},
_ => {
remove = false;
},
}
for p in to_disconnect {
let mut h = self.handlers.get_mut(p).unwrap();
h.disconnected(&mut NetworkContext::new(io, p, Some(token), &mut self.connections, &mut self.timers), &token);
}
if remove {
self.connections.remove(token);
}
}
}
impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Message: Send + 'static {
/// Initialize networking
fn initialize(&mut self, io: &mut IoContext<NetworkIoMessage<Message>>) {
/*
match ::ifaces::Interface::get_all().unwrap().into_iter().filter(|x| x.kind == ::ifaces::Kind::Packet && x.addr.is_some()).next() {
Some(iface) => config.public_address = iface.addr.unwrap(),
None => warn!("No public network interface"),
*/
// Start listening for incoming connections
io.event_loop.register(&self.listener, Token(TCP_ACCEPT), EventSet::readable(), PollOpt::edge()).unwrap();
io.event_loop.timeout_ms(Token(IDLE), MAINTENANCE_TIMEOUT).unwrap();
// open the udp socket
io.event_loop.register(&self.udp_socket, Token(NODETABLE_RECEIVE), EventSet::readable(), PollOpt::edge()).unwrap();
io.event_loop.timeout_ms(Token(NODETABLE_MAINTAIN), 7200).unwrap();
let port = self.info.config.listen_address.port();
self.info.listen_port = port;
// self.add_node("enode://a9a921de2ff09a9a4d38b623c67b2d6b477a8e654ae95d874750cbbcb31b33296496a7b4421934e2629269e180823e52c15c2b19fc59592ec51ffe4f2de76ed7@127.0.0.1:30303");
// GO bootnodes
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://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"); // SG
// ETH/DEV cpp-ethereum (poc-9.ethdev.com)
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) {
trace!(target: "net", "Hup: {}", stream);
match stream {
FIRST_CONNECTION ... LAST_CONNECTION => self.connection_closed(stream, io),
_ => warn!(target: "net", "Unexpected hup"),
};
}
fn stream_readable<'s>(&'s mut self, io: &mut IoContext<'s, NetworkIoMessage<Message>>, stream: StreamToken) {
match stream {
FIRST_CONNECTION ... LAST_CONNECTION => self.connection_readable(stream, io),
NODETABLE_RECEIVE => {},
TCP_ACCEPT => self.accept(io),
_ => panic!("Received unknown readable token"),
}
}
fn stream_writable<'s>(&'s mut self, io: &mut IoContext<'s, NetworkIoMessage<Message>>, stream: StreamToken) {
match stream {
FIRST_CONNECTION ... LAST_CONNECTION => self.connection_writable(stream, io),
_ => panic!("Received unknown writable token"),
}
}
fn timeout<'s>(&'s mut self, io: &mut IoContext<'s, NetworkIoMessage<Message>>, token: TimerToken) {
match token {
IDLE => self.maintain_network(io),
FIRST_CONNECTION ... LAST_CONNECTION => self.connection_timeout(token, io),
NODETABLE_DISCOVERY => {},
NODETABLE_MAINTAIN => {},
_ => match self.timers.get_mut(&token).map(|p| *p) {
Some(protocol) => match self.handlers.get_mut(protocol) {
None => { warn!(target: "net", "No handler found for protocol: {:?}", protocol) },
Some(h) => { h.timeout(&mut NetworkContext::new(io, protocol, Some(token), &mut self.connections, &mut self.timers), token); }
},
None => {} // time not registerd through us
}
}
}
fn message<'s>(&'s mut self, io: &mut IoContext<'s, NetworkIoMessage<Message>>, message: &'s mut NetworkIoMessage<Message>) {
match message {
&mut NetworkIoMessage::AddHandler {
ref mut handler,
ref protocol,
ref versions
} => {
let mut h = mem::replace(handler, None).unwrap();
h.initialize(&mut NetworkContext::new(io, protocol, None, &mut self.connections, &mut self.timers));
self.handlers.insert(protocol, h);
for v in versions {
self.info.capabilities.push(CapabilityInfo { protocol: protocol, version: *v, packet_count:0 });
}
},
&mut NetworkIoMessage::Send {
ref peer,
ref packet_id,
ref protocol,
ref data,
} => {
match self.connections.get_mut(*peer as usize) {
Some(&mut ConnectionEntry::Session(ref mut s)) => {
s.send_packet(protocol, *packet_id as u8, &data).unwrap_or_else(|e| {
warn!(target: "net", "Send error: {:?}", e);
}); //TODO: don't copy vector data
},
_ => {
warn!(target: "net", "Send: Peer does not exist");
}
}
},
&mut NetworkIoMessage::User(ref message) => {
for (p, h) in self.handlers.iter_mut() {
h.message(&mut NetworkContext::new(io, p, None, &mut self.connections, &mut self.timers), &message);
}
}
}
}
}

View File

@@ -1,86 +0,0 @@
/// Network and general IO module.
///
/// Example usage for craeting a network service and adding an IO handler:
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::*;
///
/// struct MyHandler;
///
/// struct MyMessage {
/// data: u32
/// }
///
/// impl NetworkProtocolHandler<MyMessage> for MyHandler {
/// fn initialize(&mut self, io: &mut NetworkContext<MyMessage>) {
/// io.register_timer(1000);
/// }
///
/// fn read(&mut self, io: &mut NetworkContext<MyMessage>, peer: &PeerId, packet_id: u8, data: &[u8]) {
/// println!("Received {} ({} bytes) from {}", packet_id, data.len(), peer);
/// }
///
/// fn connected(&mut self, io: &mut NetworkContext<MyMessage>, peer: &PeerId) {
/// println!("Connected {}", peer);
/// }
///
/// fn disconnected(&mut self, io: &mut NetworkContext<MyMessage>, peer: &PeerId) {
/// println!("Disconnected {}", peer);
/// }
///
/// fn timeout(&mut self, io: &mut NetworkContext<MyMessage>, timer: TimerToken) {
/// println!("Timeout {}", timer);
/// }
///
/// fn message(&mut self, io: &mut NetworkContext<MyMessage>, message: &MyMessage) {
/// println!("Message {}", message.data);
/// }
/// }
///
/// fn main () {
/// let mut service = NetworkService::<MyMessage>::start().expect("Error creating network service");
/// service.register_protocol(Box::new(MyHandler), "myproto", &[1u8]);
///
/// // Wait for quit condition
/// // ...
/// // Drop the service
/// }
/// ```
mod host;
mod connection;
mod handshake;
mod session;
mod discovery;
mod service;
mod error;
mod node;
pub type PeerId = host::PeerId;
pub type PacketId = host::PacketId;
pub type NetworkContext<'s,'io, Message> = host::NetworkContext<'s, 'io, Message>;
pub type NetworkService<Message> = service::NetworkService<Message>;
pub type NetworkIoMessage<Message> = host::NetworkIoMessage<Message>;
pub use network::host::NetworkIoMessage::User as UserMessage;
pub type NetworkError = error::NetworkError;
use io::*;
/// Network IO protocol handler. This needs to be implemented for each new subprotocol.
/// All the handler function are called from within IO event loop.
/// `Message` is the type for message data.
pub trait NetworkProtocolHandler<Message>: Send where Message: Send {
/// Initialize the handler
fn initialize(&mut self, _io: &mut NetworkContext<Message>) {}
/// Called when new network packet received.
fn read(&mut self, io: &mut NetworkContext<Message>, peer: &PeerId, packet_id: u8, data: &[u8]);
/// Called when new peer is connected. Only called when peer supports the same protocol.
fn connected(&mut self, io: &mut NetworkContext<Message>, peer: &PeerId);
/// Called when a previously connected peer disconnects.
fn disconnected(&mut self, io: &mut NetworkContext<Message>, peer: &PeerId);
/// Timer function called after a timeout created with `NetworkContext::timeout`.
fn timeout(&mut self, _io: &mut NetworkContext<Message>, _timer: TimerToken) {}
/// Called when a broadcasted message is received. The message can only be sent from a different IO handler.
fn message(&mut self, _io: &mut NetworkContext<Message>, _message: &Message) {}
}

View File

@@ -1,83 +0,0 @@
use std::net::{SocketAddr, ToSocketAddrs};
use std::hash::{Hash, Hasher};
use std::str::{FromStr};
use hash::*;
use rlp::*;
use time::Tm;
use error::*;
/// Node public key
pub type NodeId = H512;
#[derive(Debug)]
/// Noe address info
pub struct NodeEndpoint {
/// IP(V4 or V6) address
pub address: SocketAddr,
/// Address as string (can be host name).
pub address_str: String,
/// Conneciton port.
pub udp_port: u16
}
impl NodeEndpoint {
/// Create endpoint from string. Performs name resolution if given a host name.
fn from_str(s: &str) -> Result<NodeEndpoint, UtilError> {
let address = s.to_socket_addrs().map(|mut i| i.next());
match address {
Ok(Some(a)) => Ok(NodeEndpoint {
address: a,
address_str: s.to_string(),
udp_port: a.port()
}),
Ok(_) => Err(UtilError::AddressResolve(None)),
Err(e) => Err(UtilError::AddressResolve(Some(e)))
}
}
}
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum PeerType {
Required,
Optional
}
pub struct Node {
pub id: NodeId,
pub endpoint: NodeEndpoint,
pub peer_type: PeerType,
pub last_attempted: Option<Tm>,
}
impl FromStr for Node {
type Err = UtilError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (id, endpoint) = if &s[0..8] == "enode://" && s.len() > 136 && &s[136..137] == "@" {
(try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..])))
}
else {
(NodeId::new(), try!(NodeEndpoint::from_str(s)))
};
Ok(Node {
id: id,
endpoint: endpoint,
peer_type: PeerType::Optional,
last_attempted: None,
})
}
}
impl PartialEq for Node {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for Node { }
impl Hash for Node {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.id.hash(state)
}
}

View File

@@ -1,61 +0,0 @@
use error::*;
use network::{NetworkProtocolHandler};
use network::error::{NetworkError};
use network::host::{Host, NetworkIoMessage, PeerId, PacketId, ProtocolId};
use io::*;
/// IO Service with networking
/// `Message` defines a notification data type.
pub struct NetworkService<Message> where Message: Send + 'static {
io_service: IoService<NetworkIoMessage<Message>>,
host_info: String,
}
impl<Message> NetworkService<Message> where Message: Send + 'static {
/// Starts IO event loop
pub fn start() -> Result<NetworkService<Message>, UtilError> {
let mut io_service = try!(IoService::<NetworkIoMessage<Message>>::start());
let host = Box::new(Host::new());
let host_info = host.info.client_version.clone();
info!("NetworkService::start(): id={:?}", host.info.id());
try!(io_service.register_handler(host));
Ok(NetworkService {
io_service: io_service,
host_info: host_info,
})
}
/// Send a message over the network. Normaly `HostIo::send` should be used. This can be used from non-io threads.
pub fn send(&mut self, peer: &PeerId, packet_id: PacketId, protocol: ProtocolId, data: &[u8]) -> Result<(), NetworkError> {
try!(self.io_service.send_message(NetworkIoMessage::Send {
peer: *peer,
packet_id: packet_id,
protocol: protocol,
data: data.to_vec()
}));
Ok(())
}
/// Regiter a new protocol handler with the event loop.
pub fn register_protocol(&mut self, handler: Box<NetworkProtocolHandler<Message>+Send>, protocol: ProtocolId, versions: &[u8]) -> Result<(), NetworkError> {
try!(self.io_service.send_message(NetworkIoMessage::AddHandler {
handler: Some(handler),
protocol: protocol,
versions: versions.to_vec(),
}));
Ok(())
}
/// Returns host identifier string as advertised to other peers
pub fn host_info(&self) -> String {
self.host_info.clone()
}
/// Returns underlying io service.
pub fn io(&mut self) -> &mut IoService<NetworkIoMessage<Message>> {
&mut self.io_service
}
}

View File

@@ -1,282 +0,0 @@
use mio::*;
use hash::*;
use rlp::*;
use network::connection::{EncryptedConnection, Packet};
use network::handshake::Handshake;
use error::*;
use network::error::{NetworkError, DisconnectReason};
use network::host::*;
use network::node::NodeId;
/// Peer session over encrypted connection.
/// When created waits for Hello packet exchange and signals ready state.
/// Sends and receives protocol packets and handles basic packes such as ping/pong and disconnect.
pub struct Session {
/// Shared session information
pub info: SessionInfo,
/// Underlying connection
connection: EncryptedConnection,
/// Session ready flag. Set after successfull Hello packet exchange
had_hello: bool,
}
/// Structure used to report various session events.
pub enum SessionData {
None,
/// Session is ready to send/receive packets.
Ready,
/// A packet has been received
Packet {
/// Packet data
data: Vec<u8>,
/// Packet protocol ID
protocol: &'static str,
/// Zero based packet ID
packet_id: u8,
},
}
/// Shared session information
pub struct SessionInfo {
/// Peer public key
pub id: NodeId,
/// Peer client ID
pub client_version: String,
/// Peer RLPx protocol version
pub protocol_version: u32,
/// Peer protocol capabilities
capabilities: Vec<SessionCapabilityInfo>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct PeerCapabilityInfo {
pub protocol: String,
pub version: u8,
}
impl Decodable for PeerCapabilityInfo {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let c = try!(decoder.as_list());
let v: u32 = try!(Decodable::decode(&c[1]));
Ok(PeerCapabilityInfo {
protocol: try!(Decodable::decode(&c[0])),
version: v as u8,
})
}
}
#[derive(Debug, PartialEq, Eq)]
struct SessionCapabilityInfo {
pub protocol: &'static str,
pub version: u8,
pub packet_count: u8,
pub id_offset: u8,
}
const PACKET_HELLO: u8 = 0x80;
const PACKET_DISCONNECT: u8 = 0x01;
const PACKET_PING: u8 = 0x02;
const PACKET_PONG: u8 = 0x03;
const PACKET_GET_PEERS: u8 = 0x04;
const PACKET_PEERS: u8 = 0x05;
const PACKET_USER: u8 = 0x10;
const PACKET_LAST: u8 = 0x7f;
impl Session {
/// Create a new session out of comepleted handshake. Consumes handshake object.
pub fn new<Host:Handler<Timeout=Token>>(h: Handshake, event_loop: &mut EventLoop<Host>, host: &HostInfo) -> Result<Session, UtilError> {
let id = h.id.clone();
let connection = try!(EncryptedConnection::new(h));
let mut session = Session {
connection: connection,
had_hello: false,
info: SessionInfo {
id: id,
client_version: String::new(),
protocol_version: 0,
capabilities: Vec::new(),
},
};
try!(session.write_hello(host));
try!(session.write_ping());
try!(session.connection.register(event_loop));
Ok(session)
}
/// Check if session is ready to send/receive data
pub fn is_ready(&self) -> bool {
self.had_hello
}
/// Readable IO handler. Returns packet data if available.
pub fn readable<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>, host: &HostInfo) -> Result<SessionData, UtilError> {
match try!(self.connection.readable(event_loop)) {
Some(data) => Ok(try!(self.read_packet(data, host))),
None => Ok(SessionData::None)
}
}
/// Writable IO handler. Sends pending packets.
pub fn writable<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>, _host: &HostInfo) -> Result<(), UtilError> {
self.connection.writable(event_loop)
}
/// Checks if peer supports given capability
pub fn have_capability(&self, protocol: &str) -> bool {
self.info.capabilities.iter().any(|c| c.protocol == protocol)
}
/// Update registration with the event loop. Should be called at the end of the IO handler.
pub fn reregister<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>) -> Result<(), UtilError> {
self.connection.reregister(event_loop)
}
/// Send a protocol packet to peer.
pub fn send_packet(&mut self, protocol: &str, packet_id: u8, data: &[u8]) -> Result<(), UtilError> {
let mut i = 0usize;
while protocol != self.info.capabilities[i].protocol {
i += 1;
if i == self.info.capabilities.len() {
debug!(target: "net", "Unkown protocol: {:?}", protocol);
return Ok(())
}
}
let pid = self.info.capabilities[i].id_offset + packet_id;
let mut rlp = RlpStream::new();
rlp.append(&(pid as u32));
rlp.append_raw(data, 1);
self.connection.send_packet(&rlp.out())
}
fn read_packet(&mut self, packet: Packet, host: &HostInfo) -> Result<SessionData, UtilError> {
if packet.data.len() < 2 {
return Err(From::from(NetworkError::BadProtocol));
}
let packet_id = packet.data[0];
if packet_id != PACKET_HELLO && packet_id != PACKET_DISCONNECT && !self.had_hello {
return Err(From::from(NetworkError::BadProtocol));
}
match packet_id {
PACKET_HELLO => {
let rlp = UntrustedRlp::new(&packet.data[1..]); //TODO: validate rlp expected size
try!(self.read_hello(&rlp, host));
Ok(SessionData::Ready)
},
PACKET_DISCONNECT => Err(From::from(NetworkError::Disconnect(DisconnectReason::DisconnectRequested))),
PACKET_PING => {
try!(self.write_pong());
Ok(SessionData::None)
},
PACKET_GET_PEERS => Ok(SessionData::None), //TODO;
PACKET_PEERS => Ok(SessionData::None),
PACKET_USER ... PACKET_LAST => {
let mut i = 0usize;
while packet_id < self.info.capabilities[i].id_offset {
i += 1;
if i == self.info.capabilities.len() {
debug!(target: "net", "Unkown packet: {:?}", packet_id);
return Ok(SessionData::None)
}
}
// map to protocol
let protocol = self.info.capabilities[i].protocol;
let pid = packet_id - self.info.capabilities[i].id_offset;
return Ok(SessionData::Packet { data: packet.data, protocol: protocol, packet_id: pid } )
},
_ => {
debug!(target: "net", "Unkown packet: {:?}", packet_id);
Ok(SessionData::None)
}
}
}
fn write_hello(&mut self, host: &HostInfo) -> Result<(), UtilError> {
let mut rlp = RlpStream::new();
rlp.append_raw(&[PACKET_HELLO as u8], 0);
rlp.append_list(5)
.append(&host.protocol_version)
.append(&host.client_version)
.append(&host.capabilities)
.append(&host.listen_port)
.append(host.id());
self.connection.send_packet(&rlp.out())
}
fn read_hello(&mut self, rlp: &UntrustedRlp, host: &HostInfo) -> Result<(), UtilError> {
let protocol = try!(rlp.val_at::<u32>(0));
let client_version = try!(rlp.val_at::<String>(1));
let peer_caps = try!(rlp.val_at::<Vec<PeerCapabilityInfo>>(2));
let id = try!(rlp.val_at::<NodeId>(4));
// Intersect with host capabilities
// Leave only highset mutually supported capability version
let mut caps: Vec<SessionCapabilityInfo> = Vec::new();
for hc in host.capabilities.iter() {
if peer_caps.iter().any(|c| c.protocol == hc.protocol && c.version == hc.version) {
caps.push(SessionCapabilityInfo {
protocol: hc.protocol,
version: hc.version,
id_offset: 0,
packet_count: hc.packet_count,
});
}
}
caps.retain(|c| host.capabilities.iter().any(|hc| hc.protocol == c.protocol && hc.version == c.version));
let mut i = 0;
while i < caps.len() {
if caps.iter().any(|c| c.protocol == caps[i].protocol && c.version > caps[i].version) {
caps.remove(i);
}
else {
i += 1;
}
}
i = 0;
let mut offset: u8 = PACKET_USER;
while i < caps.len() {
caps[i].id_offset = offset;
offset += caps[i].packet_count;
i += 1;
}
trace!(target: "net", "Hello: {} v{} {} {:?}", client_version, protocol, id, caps);
self.info.client_version = client_version;
self.info.capabilities = caps;
if protocol != host.protocol_version {
return Err(From::from(self.disconnect(DisconnectReason::UselessPeer)));
}
self.had_hello = true;
Ok(())
}
fn write_ping(&mut self) -> Result<(), UtilError> {
self.send(try!(Session::prepare(PACKET_PING)))
}
fn write_pong(&mut self) -> Result<(), UtilError> {
self.send(try!(Session::prepare(PACKET_PONG)))
}
fn disconnect(&mut self, reason: DisconnectReason) -> NetworkError {
let mut rlp = RlpStream::new();
rlp.append(&(PACKET_DISCONNECT as u32));
rlp.append_list(1);
rlp.append(&(reason.clone() as u32));
self.connection.send_packet(&rlp.out()).ok();
NetworkError::Disconnect(reason)
}
fn prepare(packet_id: u8) -> Result<RlpStream, UtilError> {
let mut rlp = RlpStream::new();
rlp.append(&(packet_id as u32));
rlp.append_list(0);
Ok(rlp)
}
fn send(&mut self, rlp: RlpStream) -> Result<(), UtilError> {
self.connection.send_packet(&rlp.out())
}
}

View File

@@ -1,253 +0,0 @@
//! Nibble-orientated view onto byte-slice, allowing nibble-precision offsets.
use std::cmp::*;
use std::fmt;
use bytes::*;
/// Nibble-orientated view onto byte-slice, allowing nibble-precision offsets.
///
/// This is an immutable struct. No operations actually change it.
///
/// # Example
/// ```rust
/// extern crate ethcore_util;
/// use ethcore_util::nibbleslice::*;
/// fn main() {
/// let d1 = &[0x01u8, 0x23, 0x45];
/// let d2 = &[0x34u8, 0x50, 0x12];
/// let d3 = &[0x00u8, 0x12];
/// let n1 = NibbleSlice::new(d1); // 0,1,2,3,4,5
/// let n2 = NibbleSlice::new(d2); // 3,4,5,0,1,2
/// let n3 = NibbleSlice::new_offset(d3, 1); // 0,1,2
/// assert!(n1 > n3); // 0,1,2,... > 0,1,2
/// assert!(n1 < n2); // 0,... < 3,...
/// assert!(n2.mid(3) == n3); // 0,1,2 == 0,1,2
/// assert!(n1.starts_with(&n3));
/// assert_eq!(n1.common_prefix(&n3), 3);
/// assert_eq!(n2.mid(3).common_prefix(&n1), 3);
/// }
/// ```
#[derive(Copy, Clone, Eq, Ord)]
pub struct NibbleSlice<'a> {
data: &'a [u8],
offset: usize,
data_encode_suffix: &'a [u8],
offset_encode_suffix: usize,
}
impl<'a, 'view> NibbleSlice<'a> where 'a: 'view {
/// Create a new nibble slice with the given byte-slice.
pub fn new(data: &[u8]) -> NibbleSlice { NibbleSlice::new_offset(data, 0) }
/// 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_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) {
let r: Vec<u8>::with_capacity((a.len() + b.len() + 1) / 2);
let mut i = (a.len() + b.len()) % 2;
while i < a.len() {
match i % 2 {
0 => ,
1 => ,
}
i += 1;
}
while i < a.len() + b.len() {
i += 1;
}
(r, a.len() + b.len())
}*/
/// 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) {
(Self::new_offset(data, if data[0] & 16 == 16 {1} else {2}), data[0] & 32 == 32)
}
/// Is this an empty slice?
pub fn is_empty(&self) -> bool { self.len() == 0 }
/// Get the length (in nibbles, naturally) of this slice.
pub fn len(&self) -> usize { (self.data.len() + self.data_encode_suffix.len()) * 2 - self.offset - self.offset_encode_suffix }
/// Get the nibble at position `i`.
pub fn at(&self, i: usize) -> u8 {
let l = self.data.len() * 2 - self.offset;
if i < l {
if (self.offset + i) & 1 == 1 {
self.data[(self.offset + i) / 2] & 15u8
}
else {
self.data[(self.offset + i) / 2] >> 4
}
}
else {
let i = i - l;
if (self.offset_encode_suffix + i) & 1 == 1 {
self.data_encode_suffix[(self.offset_encode_suffix + i) / 2] & 15u8
}
else {
self.data_encode_suffix[(self.offset_encode_suffix + i) / 2] >> 4
}
}
}
/// Return object which represents a view on to this slice (further) offset by `i` nibbles.
pub fn mid(&'view self, i: usize) -> NibbleSlice<'a> { NibbleSlice{ data: self.data, offset: self.offset + i, data_encode_suffix: &b""[..], offset_encode_suffix: 0 } }
/// Do we start with the same nibbles as the whole of `them`?
pub fn starts_with(&self, them: &Self) -> bool { self.common_prefix(them) == them.len() }
/// How many of the same nibbles at the beginning do we match with `them`?
pub fn common_prefix(&self, them: &Self) -> usize {
let s = min(self.len(), them.len());
let mut i = 0usize;
while i < s {
if self.at(i) != them.at(i) { break; }
i += 1;
}
i
}
pub fn encoded(&self, is_leaf: bool) -> Bytes {
let l = self.len();
let mut r = Bytes::with_capacity(l / 2 + 1);
let mut i = l % 2;
r.push(if i == 1 {0x10 + self.at(0)} else {0} + if is_leaf {0x20} else {0});
while i < l {
r.push(self.at(i) * 16 + self.at(i + 1));
i += 2;
}
r
}
pub fn encoded_leftmost(&self, n: usize, is_leaf: bool) -> Bytes {
let l = min(self.len(), n);
let mut r = Bytes::with_capacity(l / 2 + 1);
let mut i = l % 2;
r.push(if i == 1 {0x10 + self.at(0)} else {0} + if is_leaf {0x20} else {0});
while i < l {
r.push(self.at(i) * 16 + self.at(i + 1));
i += 2;
}
r
}
}
impl<'a> PartialEq for NibbleSlice<'a> {
fn eq(&self, them: &Self) -> bool {
self.len() == them.len() && self.starts_with(them)
}
}
impl<'a> PartialOrd for NibbleSlice<'a> {
fn partial_cmp(&self, them: &Self) -> Option<Ordering> {
let s = min(self.len(), them.len());
let mut i = 0usize;
while i < s {
match self.at(i).partial_cmp(&them.at(i)).unwrap() {
Ordering::Less => return Some(Ordering::Less),
Ordering::Greater => return Some(Ordering::Greater),
_ => i += 1,
}
}
self.len().partial_cmp(&them.len())
}
}
impl<'a> fmt::Debug for NibbleSlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.len() {
match i {
0 => try!(write!(f, "{:01x}", self.at(i))),
_ => try!(write!(f, "'{:01x}", self.at(i))),
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::NibbleSlice;
static D: &'static [u8;3] = &[0x01u8, 0x23, 0x45];
#[test]
fn basics() {
let n = NibbleSlice::new(D);
assert_eq!(n.len(), 6);
assert!(!n.is_empty());
let n = NibbleSlice::new_offset(D, 6);
assert!(n.is_empty());
let n = NibbleSlice::new_offset(D, 3);
assert_eq!(n.len(), 3);
for i in 0..3 {
assert_eq!(n.at(i), i as u8 + 3);
}
}
#[test]
fn mid() {
let n = NibbleSlice::new(D);
let m = n.mid(2);
for i in 0..4 {
assert_eq!(m.at(i), i as u8 + 2);
}
let m = n.mid(3);
for i in 0..3 {
assert_eq!(m.at(i), i as u8 + 3);
}
}
#[test]
fn encoded() {
let n = NibbleSlice::new(D);
assert_eq!(n.encoded(false), &[0x00, 0x01, 0x23, 0x45]);
assert_eq!(n.encoded(true), &[0x20, 0x01, 0x23, 0x45]);
assert_eq!(n.mid(1).encoded(false), &[0x11, 0x23, 0x45]);
assert_eq!(n.mid(1).encoded(true), &[0x31, 0x23, 0x45]);
}
#[test]
fn from_encoded() {
let n = NibbleSlice::new(D);
assert_eq!((n, false), NibbleSlice::from_encoded(&[0x00, 0x01, 0x23, 0x45]));
assert_eq!((n, true), NibbleSlice::from_encoded(&[0x20, 0x01, 0x23, 0x45]));
assert_eq!((n.mid(1), false), NibbleSlice::from_encoded(&[0x11, 0x23, 0x45]));
assert_eq!((n.mid(1), true), NibbleSlice::from_encoded(&[0x31, 0x23, 0x45]));
}
#[test]
fn shared() {
let n = NibbleSlice::new(D);
let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45, 0x67];
let m = NibbleSlice::new(other);
assert_eq!(n.common_prefix(&m), 4);
assert_eq!(m.common_prefix(&n), 4);
assert_eq!(n.mid(1).common_prefix(&m.mid(1)), 3);
assert_eq!(n.mid(1).common_prefix(&m.mid(2)), 0);
assert_eq!(n.common_prefix(&m.mid(4)), 6);
assert!(!n.starts_with(&m.mid(4)));
assert!(m.mid(4).starts_with(&n));
}
#[test]
fn compare() {
let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45];
let n = NibbleSlice::new(D);
let m = NibbleSlice::new(other);
assert!(n != m);
assert!(n > m);
assert!(m < n);
assert!(n == m.mid(4));
assert!(n >= m.mid(4));
assert!(n <= m.mid(4));
}
}

30
src/null_engine.rs Normal file
View File

@@ -0,0 +1,30 @@
use engine::Engine;
use spec::Spec;
use evm::Schedule;
use evm::Factory;
use env_info::EnvInfo;
/// An engine which does not provide any consensus mechanism.
pub struct NullEngine {
spec: Spec,
factory: Factory
}
impl NullEngine {
pub fn new_boxed(spec: Spec) -> Box<Engine> {
Box::new(NullEngine{
spec: spec,
// TODO [todr] should this return any specific factory?
factory: Factory::default()
})
}
}
impl Engine for NullEngine {
fn vm_factory(&self) -> &Factory {
&self.factory
}
fn name(&self) -> &str { "NullEngine" }
fn spec(&self) -> &Spec { &self.spec }
fn schedule(&self, _env_info: &EnvInfo) -> Schedule { Schedule::new_frontier() }
}

View File

@@ -1,310 +0,0 @@
//! Disk-backed HashDB implementation.
use error::*;
use hash::*;
use bytes::*;
use rlp::*;
use hashdb::*;
use memorydb::*;
use std::ops::*;
use std::sync::*;
use std::env;
use std::collections::HashMap;
use rocksdb::{DB, Writable, IteratorMode};
#[derive(Clone)]
/// Implementation of the HashDB trait for a disk-backed database with a memory overlay.
///
/// The operations `insert()` and `kill()` take place on the memory overlay; batches of
/// such operations may be flushed to the disk-backed DB with `commit()` or discarded with
/// `revert()`.
///
/// `lookup()` and `exists()` maintain normal behaviour - all `insert()` and `kill()`
/// queries have an immediate effect in terms of these functions.
pub struct OverlayDB {
overlay: MemoryDB,
backing: Arc<DB>,
}
impl OverlayDB {
/// Create a new instance of OverlayDB given a `backing` database.
pub fn new(backing: DB) -> OverlayDB {
OverlayDB{ overlay: MemoryDB::new(), backing: Arc::new(backing) }
}
/// Create a new instance of OverlayDB with an anonymous temporary database.
pub fn new_temp() -> OverlayDB {
let mut dir = env::temp_dir();
dir.push(H32::random().hex());
Self::new(DB::open_default(dir.to_str().unwrap()).unwrap())
}
/// Commit all memory operations to the backing database.
///
/// Returns either an error or the number of items changed in the backing database.
///
/// Will return an error if the number of `kill()`s ever exceeds the number of
/// `insert()`s for any key. This will leave the database in an undeterminate
/// state. Don't ever let it happen.
///
/// # Example
/// ```
/// extern crate ethcore_util;
/// use ethcore_util::hashdb::*;
/// use ethcore_util::overlaydb::*;
/// fn main() {
/// let mut m = OverlayDB::new_temp();
/// let key = m.insert(b"foo"); // insert item.
/// assert!(m.exists(&key)); // key exists (in memory).
/// assert_eq!(m.commit().unwrap(), 1); // 1 item changed.
/// assert!(m.exists(&key)); // key still exists (in backing).
/// m.kill(&key); // delete item.
/// assert!(!m.exists(&key)); // key "doesn't exist" (though still does in backing).
/// m.kill(&key); // oh dear... more kills than inserts for the key...
/// //m.commit().unwrap(); // this commit/unwrap would cause a panic.
/// m.revert(); // revert both kills.
/// assert!(m.exists(&key)); // key now still exists.
/// }
/// ```
pub fn commit(&mut self) -> Result<u32, UtilError> {
let mut ret = 0u32;
for i in self.overlay.drain().into_iter() {
let (key, (value, rc)) = i;
if rc != 0 {
match self.payload(&key) {
Some(x) => {
let (back_value, back_rc) = x;
let total_rc: i32 = back_rc as i32 + rc;
if total_rc < 0 {
return Err(From::from(BaseDataError::NegativelyReferencedHash));
}
self.put_payload(&key, (back_value, total_rc as u32));
}
None => {
if rc < 0 {
return Err(From::from(BaseDataError::NegativelyReferencedHash));
}
self.put_payload(&key, (value, rc as u32));
}
};
ret += 1;
}
}
Ok(ret)
}
/// Revert all operations on this object (i.e. `insert()`s and `kill()`s) since the
/// last `commit()`.
///
/// # Example
/// ```
/// extern crate ethcore_util;
/// use ethcore_util::hashdb::*;
/// use ethcore_util::overlaydb::*;
/// fn main() {
/// let mut m = OverlayDB::new_temp();
/// let foo = m.insert(b"foo"); // insert foo.
/// m.commit().unwrap(); // commit - new operations begin here...
/// let bar = m.insert(b"bar"); // insert bar.
/// m.kill(&foo); // kill foo.
/// assert!(!m.exists(&foo)); // foo is gone.
/// assert!(m.exists(&bar)); // bar is here.
/// m.revert(); // revert the last two operations.
/// assert!(m.exists(&foo)); // foo is here.
/// assert!(!m.exists(&bar)); // bar is gone.
/// }
/// ```
pub fn revert(&mut self) { self.overlay.clear(); }
/// Get the refs and value of the given key.
fn payload(&self, key: &H256) -> Option<(Bytes, u32)> {
self.backing.get(&key.bytes())
.expect("Low-level database error. Some issue with your hard disk?")
.map(|d| {
let r = Rlp::new(d.deref());
(r.at(1).as_val(), r.at(0).as_val())
})
}
/// Get the refs and value of the given key.
fn put_payload(&self, key: &H256, payload: (Bytes, u32)) {
let mut s = RlpStream::new_list(2);
s.append(&payload.1);
s.append(&payload.0);
self.backing.put(&key.bytes(), &s.out()).expect("Low-level database error. Some issue with your hard disk?");
}
}
impl HashDB for OverlayDB {
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = HashMap::new();
for (key, _) in self.backing.iterator(IteratorMode::Start) {
let h = H256::from_slice(key.deref());
let r = self.payload(&h).unwrap().1;
ret.insert(h, r as i32);
}
for (key, refs) in self.overlay.keys().into_iter() {
let refs = *ret.get(&key).unwrap_or(&0) + refs;
ret.insert(key, refs);
}
ret
}
fn lookup(&self, key: &H256) -> Option<&[u8]> {
// return ok if positive; if negative, check backing - might be enough references there to make
// it positive again.
let k = self.overlay.raw(key);
match k {
Some(&(ref d, rc)) if rc > 0 => Some(d),
_ => {
let memrc = k.map(|&(_, rc)| rc).unwrap_or(0);
match self.payload(key) {
Some(x) => {
let (d, rc) = x;
if rc as i32 + memrc > 0 {
Some(&self.overlay.denote(key, d).0)
}
else {
None
}
}
// Replace above match arm with this once https://github.com/rust-lang/rust/issues/15287 is done.
//Some((d, rc)) if rc + memrc > 0 => Some(d),
_ => None,
}
}
}
}
fn exists(&self, key: &H256) -> bool {
// return ok if positive; if negative, check backing - might be enough references there to make
// it positive again.
let k = self.overlay.raw(key);
match k {
Some(&(_, rc)) if rc > 0 => true,
_ => {
let memrc = k.map(|&(_, rc)| rc).unwrap_or(0);
match self.payload(key) {
Some(x) => {
let (_, rc) = x;
if rc as i32 + memrc > 0 {
true
}
else {
false
}
}
// Replace above match arm with this once https://github.com/rust-lang/rust/issues/15287 is done.
//Some((d, rc)) if rc + memrc > 0 => true,
_ => false,
}
}
}
}
fn insert(&mut self, value: &[u8]) -> H256 { self.overlay.insert(value) }
fn emplace(&mut self, key: H256, value: Bytes) { self.overlay.emplace(key, value); }
fn kill(&mut self, key: &H256) { self.overlay.kill(key); }
}
#[test]
fn overlaydb_overlay_insert_and_kill() {
let mut trie = OverlayDB::new_temp();
let h = trie.insert(b"hello world");
assert_eq!(trie.lookup(&h).unwrap(), b"hello world");
trie.kill(&h);
assert_eq!(trie.lookup(&h), None);
}
#[test]
fn overlaydb_backing_insert_revert() {
let mut trie = OverlayDB::new_temp();
let h = trie.insert(b"hello world");
assert_eq!(trie.lookup(&h).unwrap(), b"hello world");
trie.commit().unwrap();
assert_eq!(trie.lookup(&h).unwrap(), b"hello world");
trie.revert();
assert_eq!(trie.lookup(&h).unwrap(), b"hello world");
}
#[test]
fn overlaydb_backing_kill() {
let mut trie = OverlayDB::new_temp();
let h = trie.insert(b"hello world");
trie.commit().unwrap();
trie.kill(&h);
assert_eq!(trie.lookup(&h), None);
trie.commit().unwrap();
assert_eq!(trie.lookup(&h), None);
trie.revert();
assert_eq!(trie.lookup(&h), None);
}
#[test]
fn overlaydb_backing_kill_revert() {
let mut trie = OverlayDB::new_temp();
let h = trie.insert(b"hello world");
trie.commit().unwrap();
trie.kill(&h);
assert_eq!(trie.lookup(&h), None);
trie.revert();
assert_eq!(trie.lookup(&h).unwrap(), b"hello world");
}
#[test]
fn overlaydb_negative() {
let mut trie = OverlayDB::new_temp();
let h = trie.insert(b"hello world");
trie.commit().unwrap();
trie.kill(&h);
trie.kill(&h); //bad - sends us into negative refs.
assert_eq!(trie.lookup(&h), None);
assert!(trie.commit().is_err());
}
#[test]
fn overlaydb_complex() {
let mut trie = OverlayDB::new_temp();
let hfoo = trie.insert(b"foo");
assert_eq!(trie.lookup(&hfoo).unwrap(), b"foo");
let hbar = trie.insert(b"bar");
assert_eq!(trie.lookup(&hbar).unwrap(), b"bar");
trie.commit().unwrap();
assert_eq!(trie.lookup(&hfoo).unwrap(), b"foo");
assert_eq!(trie.lookup(&hbar).unwrap(), b"bar");
trie.insert(b"foo"); // two refs
assert_eq!(trie.lookup(&hfoo).unwrap(), b"foo");
trie.commit().unwrap();
assert_eq!(trie.lookup(&hfoo).unwrap(), b"foo");
assert_eq!(trie.lookup(&hbar).unwrap(), b"bar");
trie.kill(&hbar); // zero refs - delete
assert_eq!(trie.lookup(&hbar), None);
trie.kill(&hfoo); // one ref - keep
assert_eq!(trie.lookup(&hfoo).unwrap(), b"foo");
trie.commit().unwrap();
assert_eq!(trie.lookup(&hfoo).unwrap(), b"foo");
trie.kill(&hfoo); // zero ref - would delete, but...
assert_eq!(trie.lookup(&hfoo), None);
trie.insert(b"foo"); // one ref - keep after all.
assert_eq!(trie.lookup(&hfoo).unwrap(), b"foo");
trie.commit().unwrap();
assert_eq!(trie.lookup(&hfoo).unwrap(), b"foo");
trie.kill(&hfoo); // zero ref - delete
assert_eq!(trie.lookup(&hfoo), None);
trie.commit().unwrap(); //
assert_eq!(trie.lookup(&hfoo), None);
}
#[test]
fn playpen() {
use std::fs;
{
let db: DB = DB::open_default("/tmp/test").unwrap();
db.put(b"test", b"test2").unwrap();
match db.get(b"test") {
Ok(Some(value)) => println!("Got value {:?}", value.deref()),
Ok(None) => println!("No value for that key"),
Err(..) => println!("Gah"),
}
db.delete(b"test").unwrap();
}
fs::remove_dir_all("/tmp/test").unwrap();
}

115
src/pod_account.rs Normal file
View File

@@ -0,0 +1,115 @@
use util::*;
use account::*;
#[derive(Debug,Clone,PartialEq,Eq)]
/// Genesis account data. Does not have a DB overlay cache.
pub struct PodAccount {
pub balance: U256,
pub nonce: U256,
pub code: Bytes,
pub storage: BTreeMap<H256, H256>,
}
impl PodAccount {
/// Construct new object.
pub fn new(balance: U256, nonce: U256, code: Bytes, storage: BTreeMap<H256, H256>) -> PodAccount {
PodAccount { balance: balance, nonce: nonce, code: code, storage: storage }
}
/// Convert Account to a PodAccount.
/// NOTE: This will silently fail unless the account is fully cached.
pub fn from_account(acc: &Account) -> PodAccount {
PodAccount {
balance: acc.balance().clone(),
nonce: acc.nonce().clone(),
storage: acc.storage_overlay().iter().fold(BTreeMap::new(), |mut m, (k, &(_, ref v))| {m.insert(k.clone(), v.clone()); m}),
code: acc.code().unwrap().to_vec(),
}
}
pub fn rlp(&self) -> Bytes {
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(), encode(&U256::from(v.as_slice())))).collect()));
stream.append(&self.code.sha3());
stream.out()
}
}
impl fmt::Display for PodAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(bal={}; nonce={}; code={} bytes, #{}; storage={} items)", self.balance, self.nonce, self.code.len(), self.code.sha3(), self.storage.len())
}
}
#[cfg(test)]
mod test {
use common::*;
use account_diff::*;
use super::*;
#[test]
fn existence() {
let a = PodAccount{balance: x!(69), nonce: x!(0), code: vec![], storage: map![]};
assert_eq!(AccountDiff::diff_pod(Some(&a), Some(&a)), None);
assert_eq!(AccountDiff::diff_pod(None, Some(&a)), Some(AccountDiff{
balance: Diff::Born(x!(69)),
nonce: Diff::Born(x!(0)),
code: Diff::Born(vec![]),
storage: map![],
}));
}
#[test]
fn basic() {
let a = PodAccount{balance: x!(69), nonce: x!(0), code: vec![], storage: map![]};
let b = PodAccount{balance: x!(42), nonce: x!(1), code: vec![], storage: map![]};
assert_eq!(AccountDiff::diff_pod(Some(&a), Some(&b)), Some(AccountDiff {
balance: Diff::Changed(x!(69), x!(42)),
nonce: Diff::Changed(x!(0), x!(1)),
code: Diff::Same,
storage: map![],
}));
}
#[test]
fn code() {
let a = PodAccount{balance: x!(0), nonce: x!(0), code: vec![], storage: map![]};
let b = PodAccount{balance: x!(0), nonce: x!(1), code: vec![0], storage: map![]};
assert_eq!(AccountDiff::diff_pod(Some(&a), Some(&b)), Some(AccountDiff {
balance: Diff::Same,
nonce: Diff::Changed(x!(0), x!(1)),
code: Diff::Changed(vec![], vec![0]),
storage: map![],
}));
}
#[test]
fn storage() {
let a = PodAccount {
balance: x!(0),
nonce: x!(0),
code: vec![],
storage: mapx![1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 0, 6 => 0, 7 => 0]
};
let b = PodAccount {
balance: x!(0),
nonce: x!(0),
code: vec![],
storage: mapx![1 => 1, 2 => 3, 3 => 0, 5 => 0, 7 => 7, 8 => 0, 9 => 9]
};
assert_eq!(AccountDiff::diff_pod(Some(&a), Some(&b)), Some(AccountDiff {
balance: Diff::Same,
nonce: Diff::Same,
code: Diff::Same,
storage: map![
x!(2) => Diff::new(x!(2), x!(3)),
x!(3) => Diff::new(x!(3), x!(0)),
x!(4) => Diff::new(x!(4), x!(0)),
x!(7) => Diff::new(x!(0), x!(7)),
x!(9) => Diff::new(x!(0), x!(9))
],
}));
}
}

46
src/pod_state.rs Normal file
View File

@@ -0,0 +1,46 @@
use util::*;
use pod_account::*;
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct PodState (BTreeMap<Address, PodAccount>);
impl PodState {
/// Contruct a new object from the `m`.
pub fn new(m: BTreeMap<Address, PodAccount>) -> PodState { PodState(m) }
/// Get the underlying map.
pub fn get(&self) -> &BTreeMap<Address, PodAccount> { &self.0 }
/// Drain object to get the underlying map.
pub fn drain(self) -> BTreeMap<Address, PodAccount> { self.0 }
}
impl FromJson for PodState {
/// Translate the JSON object into a hash map of account information ready for insertion into State.
fn from_json(json: &Json) -> PodState {
PodState(json.as_object().unwrap().iter().fold(BTreeMap::new(), |mut state, (address, acc)| {
let balance = acc.find("balance").map(&U256::from_json);
let nonce = acc.find("nonce").map(&U256::from_json);
let storage = acc.find("storage").map(&BTreeMap::from_json);
let code = acc.find("code").map(&Bytes::from_json);
if balance.is_some() || nonce.is_some() || storage.is_some() || code.is_some() {
state.insert(address_from_hex(address), PodAccount{
balance: balance.unwrap_or(U256::zero()),
nonce: nonce.unwrap_or(U256::zero()),
storage: storage.unwrap_or(BTreeMap::new()),
code: code.unwrap_or(Vec::new())
});
}
state
}))
}
}
impl fmt::Display for PodState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (add, acc) in &self.0 {
try!(writeln!(f, "{} => {}", add, acc));
}
Ok(())
}
}

59
src/queue.rs Normal file
View File

@@ -0,0 +1,59 @@
use util::*;
use verification::*;
use error::*;
use engine::Engine;
use sync::*;
use views::*;
/// A queue of blocks. Sits between network or other I/O and the BlockChain.
/// Sorts them ready for blockchain insertion.
pub struct BlockQueue {
engine: Arc<Box<Engine>>,
message_channel: IoChannel<NetSyncMessage>,
bad: HashSet<H256>,
}
impl BlockQueue {
/// Creates a new queue instance.
pub fn new(engine: Arc<Box<Engine>>, message_channel: IoChannel<NetSyncMessage>) -> BlockQueue {
BlockQueue {
engine: engine,
message_channel: message_channel,
bad: HashSet::new(),
}
}
/// Clear the queue and stop verification activity.
pub fn clear(&mut self) {
}
/// Add a block to the queue.
pub fn import_block(&mut self, bytes: &[u8]) -> ImportResult {
let header = BlockView::new(bytes).header();
if self.bad.contains(&header.hash()) {
return Err(ImportError::Bad(None));
}
if self.bad.contains(&header.parent_hash) {
self.bad.insert(header.hash());
return Err(ImportError::Bad(None));
}
try!(verify_block_basic(&header, bytes, self.engine.deref().deref()).map_err(|e| {
warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), e);
e
}));
try!(verify_block_unordered(&header, bytes, self.engine.deref().deref()).map_err(|e| {
warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), e);
e
}));
try!(self.message_channel.send(UserMessage(SyncMessage::BlockVerified(bytes.to_vec()))).map_err(|e| Error::from(e)));
Ok(())
}
pub fn mark_as_bad(&mut self, hash: &H256) {
self.bad.insert(hash.clone());
//TODO: walk the queue
}
}

38
src/receipt.rs Normal file
View File

@@ -0,0 +1,38 @@
use util::*;
use basic_types::LogBloom;
use log_entry::LogEntry;
/// Information describing execution of a transaction.
#[derive(Debug)]
pub struct Receipt {
pub state_root: H256,
pub gas_used: U256,
pub log_bloom: LogBloom,
pub logs: Vec<LogEntry>,
}
impl Receipt {
pub fn new(state_root: H256, gas_used: U256, logs: Vec<LogEntry>) -> Receipt {
Receipt {
state_root: state_root,
gas_used: gas_used,
log_bloom: logs.iter().fold(LogBloom::new(), |mut b, l| { b |= &l.bloom(); b }),
logs: logs,
}
}
}
impl RlpStandard for Receipt {
fn rlp_append(&self, s: &mut RlpStream) {
s.append_list(4);
s.append(&self.state_root);
s.append(&self.gas_used);
s.append(&self.log_bloom);
// TODO: make work:
//s.append(&self.logs);
s.append_list(self.logs.len());
for l in self.logs.iter() {
l.rlp_append(s);
}
}
}

View File

@@ -1,87 +0,0 @@
//! Rlp serialization module
//!
//! Allows encoding, decoding, and view onto rlp-slice
//!
//!# What should you use when?
//!
//!### Use `encode` function when:
//! * You want to encode something inline.
//! * You do not work on big set of data.
//! * You want to encode whole data structure at once.
//!
//!### Use `decode` function when:
//! * You want to decode something inline.
//! * You do not work on big set of data.
//! * You want to decode whole rlp at once.
//!
//!### Use `RlpStream` when:
//! * You want to encode something in portions.
//! * You encode a big set of data.
//!
//!### Use `Rlp` when:
//! * You are working on trusted data (not corrupted).
//! * You want to get view onto rlp-slice.
//! * You don't want to decode whole rlp at once.
//!
//!### Use `UntrustedRlp` when:
//! * You are working on untrusted data (~corrupted).
//! * You need to handle data corruption errors.
//! * You are working on input data.
//! * You want to get view onto rlp-slice.
//! * You don't want to decode whole rlp at once.
pub mod rlptraits;
pub mod rlperrors;
pub mod rlpin;
pub mod untrusted_rlp;
pub mod rlpstream;
#[cfg(test)]
mod tests;
pub use self::rlperrors::DecoderError;
pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder};
pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype};
pub use self::rlpin::{Rlp, RlpIterator};
pub use self::rlpstream::{RlpStream,RlpStandard};
use super::hash::H256;
pub const NULL_RLP: [u8; 1] = [0x80; 1];
pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1];
pub const SHA3_NULL_RLP: H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21] );
pub const SHA3_EMPTY_LIST_RLP: H256 = H256( [0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45, 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47] );
/// Shortcut function to decode trusted rlp
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
/// let animals: Vec<String> = decode(&data);
/// assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]);
/// }
/// ```
pub fn decode<T>(bytes: &[u8]) -> T where T: Decodable {
let rlp = Rlp::new(bytes);
rlp.as_val()
}
/// Shortcut function to encode structure into rlp.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let animals = vec!["cat", "dog"];
/// let out = encode(&animals);
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
/// }
/// ```
pub fn encode<E>(object: &E) -> Vec<u8> where E: Encodable {
let mut stream = RlpStream::new();
stream.append(object);
stream.out()
}

View File

@@ -1,33 +0,0 @@
use std::fmt;
use std::error::Error as StdError;
use bytes::FromBytesError;
#[derive(Debug, PartialEq, Eq)]
pub enum DecoderError {
FromBytesError(FromBytesError),
RlpIsTooShort,
RlpExpectedToBeList,
RlpExpectedToBeData,
RlpIncorrectListLen,
RlpDataLenWithZeroPrefix,
RlpListLenWithZeroPrefix,
RlpInvalidIndirection,
}
impl StdError for DecoderError {
fn description(&self) -> &str {
"builder error"
}
}
impl fmt::Display for DecoderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self, f)
}
}
impl From<FromBytesError> for DecoderError {
fn from(err: FromBytesError) -> DecoderError {
DecoderError::FromBytesError(err)
}
}

View File

@@ -1,151 +0,0 @@
use std::fmt;
use rlp::{View, Decodable, DecoderError, UntrustedRlp, PayloadInfo, Prototype};
impl<'a> From<UntrustedRlp<'a>> for Rlp<'a> {
fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> {
Rlp { rlp: rlp }
}
}
/// Data-oriented view onto trusted rlp-slice.
///
/// Unlikely to `UntrustedRlp` doesn't bother you with error
/// handling. It assumes that you know what you are doing.
#[derive(Debug)]
pub struct Rlp<'a> {
rlp: UntrustedRlp<'a>
}
impl<'a> fmt::Display for Rlp<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.rlp)
}
}
impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view {
type Prototype = Prototype;
type PayloadInfo = PayloadInfo;
type Data = &'a [u8];
type Item = Rlp<'a>;
type Iter = RlpIterator<'a, 'view>;
/// Create a new instance of `Rlp`
fn new(bytes: &'a [u8]) -> Rlp<'a> {
Rlp {
rlp: UntrustedRlp::new(bytes)
}
}
fn as_raw(&'view self) -> &'a [u8] {
self.rlp.as_raw()
}
fn prototype(&self) -> Self::Prototype {
self.rlp.prototype().unwrap()
}
fn payload_info(&self) -> Self::PayloadInfo {
self.rlp.payload_info().unwrap()
}
fn data(&'view self) -> Self::Data {
self.rlp.data().unwrap()
}
fn item_count(&self) -> usize {
self.rlp.item_count()
}
fn size(&self) -> usize {
self.rlp.size()
}
fn at(&'view self, index: usize) -> Self::Item {
From::from(self.rlp.at(index).unwrap())
}
fn is_null(&self) -> bool {
self.rlp.is_null()
}
fn is_empty(&self) -> bool {
self.rlp.is_empty()
}
fn is_list(&self) -> bool {
self.rlp.is_list()
}
fn is_data(&self) -> bool {
self.rlp.is_data()
}
fn is_int(&self) -> bool {
self.rlp.is_int()
}
fn iter(&'view self) -> Self::Iter {
self.into_iter()
}
fn as_val<T>(&self) -> Result<T, DecoderError> where T: Decodable {
self.rlp.as_val()
}
fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: Decodable {
self.at(index).rlp.as_val()
}
}
impl <'a, 'view> Rlp<'a> where 'a: 'view {
fn view_as_val<T, R>(r: &R) -> T where R: View<'a, 'view>, T: Decodable {
let res: Result<T, DecoderError> = r.as_val();
res.unwrap_or_else(|_| panic!())
}
pub fn as_val<T>(&self) -> T where T: Decodable {
Self::view_as_val(self)
}
pub fn val_at<T>(&self, index: usize) -> T where T: Decodable {
Self::view_as_val(&self.at(index))
}
}
/// Iterator over trusted rlp-slice list elements.
pub struct RlpIterator<'a, 'view> where 'a: 'view {
rlp: &'view Rlp<'a>,
index: usize
}
impl<'a, 'view> IntoIterator for &'view Rlp<'a> where 'a: 'view {
type Item = Rlp<'a>;
type IntoIter = RlpIterator<'a, 'view>;
fn into_iter(self) -> Self::IntoIter {
RlpIterator {
rlp: self,
index: 0,
}
}
}
impl<'a, 'view> Iterator for RlpIterator<'a, 'view> {
type Item = Rlp<'a>;
fn next(&mut self) -> Option<Rlp<'a>> {
let index = self.index;
let result = self.rlp.rlp.at(index).ok().map(| iter | { From::from(iter) });
self.index += 1;
result
}
}
#[test]
fn break_it() {
use common::*;
let h: Bytes = FromHex::from_hex("f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap();
let r: Rlp = Rlp::new(&h);
let u: U256 = r.val_at(1);
assert_eq!(format!("{}", u), "19526463837540678066");
}

View File

@@ -1,279 +0,0 @@
use elastic_array::*;
use bytes::{Bytes, ToBytes};
use rlp::{Stream, Encoder, Encodable};
use hash::H256;
use sha3::*;
#[derive(Debug, Copy, Clone)]
struct ListInfo {
position: usize,
current: usize,
max: usize,
}
impl ListInfo {
fn new(position: usize, max: usize) -> ListInfo {
ListInfo {
position: position,
current: 0,
max: max,
}
}
}
/// Appendable rlp encoder.
pub struct RlpStream {
unfinished_lists: ElasticArray16<ListInfo>,
encoder: BasicEncoder,
}
impl Stream for RlpStream {
fn new() -> Self {
RlpStream {
unfinished_lists: ElasticArray16::new(),
encoder: BasicEncoder::new(),
}
}
fn new_list(len: usize) -> Self {
let mut stream = RlpStream::new();
stream.append_list(len);
stream
}
fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable {
// encode given value and add it at the end of the stream
object.encode(&mut self.encoder);
// if list is finished, prepend the length
self.note_appended(1);
// return chainable self
self
}
fn append_list<'a>(&'a mut self, len: usize) -> &'a mut RlpStream {
match len {
0 => {
// we may finish, if the appended list len is equal 0
self.encoder.bytes.push(0xc0u8);
self.note_appended(1);
},
_ => {
let position = self.encoder.bytes.len();
self.unfinished_lists.push(ListInfo::new(position, len));
},
}
// return chainable self
self
}
fn append_empty_data<'a>(&'a mut self) -> &'a mut RlpStream {
// self push raw item
self.encoder.bytes.push(0x80);
// try to finish and prepend the length
self.note_appended(1);
// return chainable self
self
}
fn append_raw<'a>(&'a mut self, bytes: &[u8], item_count: usize) -> &'a mut RlpStream {
// push raw items
self.encoder.bytes.append_slice(bytes);
// try to finish and prepend the length
self.note_appended(item_count);
// return chainable self
self
}
fn clear(&mut self) {
// clear bytes
self.encoder.bytes.clear();
// clear lists
self.unfinished_lists.clear();
}
fn is_finished(&self) -> bool {
self.unfinished_lists.len() == 0
}
fn as_raw(&self) -> &[u8] {
&self.encoder.bytes
}
fn out(self) -> Vec<u8> {
match self.is_finished() {
true => self.encoder.out().to_vec(),
false => panic!()
}
}
}
impl RlpStream {
/// Try to finish lists
fn note_appended(&mut self, inserted_items: usize) -> () {
if self.unfinished_lists.len() == 0 {
return;
}
let back = self.unfinished_lists.len() - 1;
let should_finish = match self.unfinished_lists.get_mut(back) {
None => false,
Some(ref mut x) => {
x.current += inserted_items;
if x.current > x.max {
panic!("You cannot append more items then you expect!");
}
x.current == x.max
}
};
if should_finish {
let x = self.unfinished_lists.pop().unwrap();
let len = self.encoder.bytes.len() - x.position;
self.encoder.insert_list_len_at_pos(len, x.position);
self.note_appended(1);
}
}
}
struct BasicEncoder {
bytes: ElasticArray1024<u8>,
}
impl BasicEncoder {
fn new() -> BasicEncoder {
BasicEncoder { bytes: ElasticArray1024::new() }
}
/// inserts list prefix at given position
/// TODO: optimise it further?
fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> () {
let mut res = vec![];
match len {
0...55 => res.push(0xc0u8 + len as u8),
_ => {
res.push(0xf7u8 + len.to_bytes_len() as u8);
res.extend(len.to_bytes());
}
};
self.bytes.insert_slice(pos, &res);
}
/// get encoded value
fn out(self) -> ElasticArray1024<u8> {
self.bytes
}
}
impl Encoder for BasicEncoder {
fn emit_value(&mut self, bytes: &[u8]) -> () {
match bytes.len() {
// just 0
0 => self.bytes.push(0x80u8),
// byte is its own encoding
1 if bytes[0] < 0x80 => self.bytes.append_slice(bytes),
// (prefix + length), followed by the string
len @ 1 ... 55 => {
self.bytes.push(0x80u8 + len as u8);
self.bytes.append_slice(bytes);
}
// (prefix + length of length), followed by the length, followd by the string
len => {
self.bytes.push(0xb7 + len.to_bytes_len() as u8);
self.bytes.append_slice(&len.to_bytes());
self.bytes.append_slice(bytes);
}
}
}
fn emit_raw(&mut self, bytes: &[u8]) -> () {
self.bytes.append_slice(bytes);
}
fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () {
// get len before inserting a list
let before_len = self.bytes.len();
// insert all list elements
f(self);
// get len after inserting a list
let after_len = self.bytes.len();
// diff is list len
let list_len = after_len - before_len;
self.insert_list_len_at_pos(list_len, before_len);
}
}
pub trait RlpStandard {
fn rlp_append(&self, s: &mut RlpStream);
fn rlp_bytes(&self) -> Bytes {
let mut s = RlpStream::new();
self.rlp_append(&mut s);
s.out()
}
fn rlp_sha3(&self) -> H256 { self.rlp_bytes().sha3() }
}
// @debris TODO: implement Encoder for RlpStandard.
impl<T> Encodable for T where T: ToBytes {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
encoder.emit_value(&self.to_bytes())
}
}
impl<'a, T> Encodable for &'a [T] where T: Encodable + 'a {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
encoder.emit_list(|e| {
// insert all list elements
for el in self.iter() {
el.encode(e);
}
})
}
}
impl<T> Encodable for Vec<T> where T: Encodable {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
let r: &[T] = self.as_ref();
r.encode(encoder)
}
}
/// lets treat bytes differently than other lists
/// they are a single value
impl<'a> Encodable for &'a [u8] {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
encoder.emit_value(self)
}
}
/// lets treat bytes differently than other lists
/// they are a single value
impl Encodable for Vec<u8> {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
encoder.emit_value(self)
}
}
impl<T> Encodable for Option<T> where T: Encodable {
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
match *self {
Some(ref x) => x.encode(encoder),
None => encoder.emit_value(&[])
}
}
}

View File

@@ -1,293 +0,0 @@
use rlp::{DecoderError, UntrustedRlp};
pub trait Decoder: Sized {
fn read_value<T, F>(&self, f: F) -> Result<T, DecoderError>
where F: FnOnce(&[u8]) -> Result<T, DecoderError>;
fn as_list(&self) -> Result<Vec<Self>, DecoderError>;
fn as_rlp<'a>(&'a self) -> &'a UntrustedRlp<'a>;
fn as_raw(&self) -> &[u8];
}
pub trait Decodable: Sized {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder;
}
pub trait View<'a, 'view>: Sized {
type Prototype;
type PayloadInfo;
type Data;
type Item;
type Iter;
/// Creates a new instance of `Rlp` reader
fn new(bytes: &'a [u8]) -> Self;
/// The raw data of the RLP.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
/// let rlp = Rlp::new(&data);
/// let dog = rlp.at(1).as_raw();
/// assert_eq!(dog, &[0x83, b'd', b'o', b'g']);
/// }
/// ```
fn as_raw(&'view self) -> &'a [u8];
/// Get the prototype of the RLP.
fn prototype(&self) -> Self::Prototype;
fn payload_info(&self) -> Self::PayloadInfo;
fn data(&'view self) -> Self::Data;
/// Returns number of RLP items.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
/// let rlp = Rlp::new(&data);
/// assert_eq!(rlp.item_count(), 2);
/// let view = rlp.at(1);
/// assert_eq!(view.item_count(), 0);
/// }
/// ```
fn item_count(&self) -> usize;
/// Returns the number of bytes in the data, or zero if it isn't data.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
/// let rlp = Rlp::new(&data);
/// assert_eq!(rlp.size(), 0);
/// let view = rlp.at(1);
/// assert_eq!(view.size(), 3);
/// }
/// ```
fn size(&self) -> usize;
/// Get view onto RLP-slice at index.
///
/// Caches offset to given index, so access to successive
/// slices is faster.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
/// let rlp = Rlp::new(&data);
/// let dog: String = rlp.at(1).as_val();
/// assert_eq!(dog, "dog".to_string());
/// }
fn at(&'view self, index: usize) -> Self::Item;
/// No value
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![];
/// let rlp = Rlp::new(&data);
/// assert!(rlp.is_null());
/// }
/// ```
fn is_null(&self) -> bool;
/// Contains a zero-length string or zero-length list.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc0];
/// let rlp = Rlp::new(&data);
/// assert!(rlp.is_empty());
/// }
/// ```
fn is_empty(&self) -> bool;
/// List value
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
/// let rlp = Rlp::new(&data);
/// assert!(rlp.is_list());
/// }
/// ```
fn is_list(&self) -> bool;
/// String value
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
/// let rlp = Rlp::new(&data);
/// assert!(rlp.at(1).is_data());
/// }
/// ```
fn is_data(&self) -> bool;
/// Int value
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc1, 0x10];
/// let rlp = Rlp::new(&data);
/// assert_eq!(rlp.is_int(), false);
/// assert_eq!(rlp.at(0).is_int(), true);
/// }
/// ```
fn is_int(&self) -> bool;
/// Get iterator over rlp-slices
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
/// let rlp = Rlp::new(&data);
/// let strings: Vec<String> = rlp.iter().map(| i | i.as_val()).collect();
/// }
/// ```
fn iter(&'view self) -> Self::Iter;
fn as_val<T>(&self) -> Result<T, DecoderError> where T: Decodable;
fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: Decodable;
}
pub trait Encoder {
fn emit_value(&mut self, bytes: &[u8]) -> ();
fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> ();
fn emit_raw(&mut self, bytes: &[u8]) -> ();
}
pub trait Encodable {
fn encode<E>(&self, encoder: &mut E) -> () where E: Encoder;
}
pub trait Stream: Sized {
/// Initializes instance of empty `Stream`.
fn new() -> Self;
/// Initializes the `Stream` as a list.
fn new_list(len: usize) -> Self;
/// Apends value to the end of stream, chainable.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let mut stream = RlpStream::new_list(2);
/// stream.append(&"cat").append(&"dog");
/// let out = stream.out();
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
/// }
/// ```
fn append<'a, E>(&'a mut self, object: &E) -> &'a mut Self where E: Encodable;
/// Declare appending the list of given size, chainable.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let mut stream = RlpStream::new_list(2);
/// stream.append_list(2).append(&"cat").append(&"dog");
/// stream.append(&"");
/// let out = stream.out();
/// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]);
/// }
/// ```
fn append_list<'a>(&'a mut self, len: usize) -> &'a mut Self;
/// Apends null to the end of stream, chainable.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let mut stream = RlpStream::new_list(2);
/// stream.append_empty_data().append_empty_data();
/// let out = stream.out();
/// assert_eq!(out, vec![0xc2, 0x80, 0x80]);
/// }
/// ```
fn append_empty_data<'a>(&'a mut self) -> &'a mut Self;
/// Appends raw (pre-serialised) RLP data. Use with caution. Chainable.
fn append_raw<'a>(&'a mut self, bytes: &[u8], item_count: usize) -> &'a mut Self;
/// Clear the output stream so far.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let mut stream = RlpStream::new_list(3);
/// stream.append(&"cat");
/// stream.clear();
/// stream.append(&"dog");
/// let out = stream.out();
/// assert_eq!(out, vec![0x83, b'd', b'o', b'g']);
/// }
fn clear(&mut self);
/// Returns true if stream doesnt expect any more items.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::rlp::*;
///
/// fn main () {
/// let mut stream = RlpStream::new_list(2);
/// stream.append(&"cat");
/// assert_eq!(stream.is_finished(), false);
/// stream.append(&"dog");
/// assert_eq!(stream.is_finished(), true);
/// let out = stream.out();
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
/// }
fn is_finished(&self) -> bool;
fn as_raw(&self) -> &[u8];
/// Streams out encoded bytes.
///
/// panic! if stream is not finished.
fn out(self) -> Vec<u8>;
}

View File

@@ -1,353 +0,0 @@
extern crate json_tests;
use self::json_tests::execute_tests_from_directory;
use self::json_tests::rlp as rlptest;
use std::{fmt, cmp};
use std::str::FromStr;
use rlp;
use rlp::{UntrustedRlp, RlpStream, View, Stream};
use uint::U256;
#[test]
fn rlp_at() {
let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
{
let rlp = UntrustedRlp::new(&data);
assert!(rlp.is_list());
//let animals = <Vec<String> as rlp::Decodable>::decode_untrusted(&rlp).unwrap();
let animals: Vec<String> = rlp.as_val().unwrap();
assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]);
let cat = rlp.at(0).unwrap();
assert!(cat.is_data());
assert_eq!(cat.as_raw(), &[0x83, b'c', b'a', b't']);
//assert_eq!(String::decode_untrusted(&cat).unwrap(), "cat".to_string());
assert_eq!(cat.as_val::<String>().unwrap(), "cat".to_string());
let dog = rlp.at(1).unwrap();
assert!(dog.is_data());
assert_eq!(dog.as_raw(), &[0x83, b'd', b'o', b'g']);
//assert_eq!(String::decode_untrusted(&dog).unwrap(), "dog".to_string());
assert_eq!(dog.as_val::<String>().unwrap(), "dog".to_string());
let cat_again = rlp.at(0).unwrap();
assert!(cat_again.is_data());
assert_eq!(cat_again.as_raw(), &[0x83, b'c', b'a', b't']);
//assert_eq!(String::decode_untrusted(&cat_again).unwrap(), "cat".to_string());
assert_eq!(cat_again.as_val::<String>().unwrap(), "cat".to_string());
}
}
#[test]
fn rlp_at_err() {
let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o'];
{
let rlp = UntrustedRlp::new(&data);
assert!(rlp.is_list());
let cat_err = rlp.at(0).unwrap_err();
assert_eq!(cat_err, rlp::DecoderError::RlpIsTooShort);
let dog_err = rlp.at(1).unwrap_err();
assert_eq!(dog_err, rlp::DecoderError::RlpIsTooShort);
}
}
#[test]
fn rlp_iter() {
let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
{
let rlp = UntrustedRlp::new(&data);
let mut iter = rlp.iter();
let cat = iter.next().unwrap();
assert!(cat.is_data());
assert_eq!(cat.as_raw(), &[0x83, b'c', b'a', b't']);
let dog = iter.next().unwrap();
assert!(dog.is_data());
assert_eq!(dog.as_raw(), &[0x83, b'd', b'o', b'g']);
let none = iter.next();
assert!(none.is_none());
let cat_again = rlp.at(0).unwrap();
assert!(cat_again.is_data());
assert_eq!(cat_again.as_raw(), &[0x83, b'c', b'a', b't']);
}
}
struct ETestPair<T>(T, Vec<u8>) where T: rlp::Encodable;
fn run_encode_tests<T>(tests: Vec<ETestPair<T>>)
where T: rlp::Encodable
{
for t in &tests {
let res = rlp::encode(&t.0);
assert_eq!(res, &t.1[..]);
}
}
#[test]
fn encode_u16() {
let tests = vec![
ETestPair(0u16, vec![0x80u8]),
ETestPair(0x100, vec![0x82, 0x01, 0x00]),
ETestPair(0xffff, vec![0x82, 0xff, 0xff]),
];
run_encode_tests(tests);
}
#[test]
fn encode_u32() {
let tests = vec![
ETestPair(0u32, vec![0x80u8]),
ETestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]),
ETestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]),
];
run_encode_tests(tests);
}
#[test]
fn encode_u64() {
let tests = vec![
ETestPair(0u64, vec![0x80u8]),
ETestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]),
ETestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]),
];
run_encode_tests(tests);
}
#[test]
fn encode_u256() {
let tests = vec![ETestPair(U256::from(0u64), vec![0x80u8]),
ETestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]),
ETestPair(U256::from(0xffffffffu64),
vec![0x84, 0xff, 0xff, 0xff, 0xff]),
ETestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\
000100000000000012f0")
.unwrap(),
vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])];
run_encode_tests(tests);
}
#[test]
fn encode_str() {
let tests = vec![ETestPair("cat", vec![0x83, b'c', b'a', b't']),
ETestPair("dog", vec![0x83, b'd', b'o', b'g']),
ETestPair("Marek", vec![0x85, b'M', b'a', b'r', b'e', b'k']),
ETestPair("", vec![0x80]),
ETestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit",
vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i',
b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o',
b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e',
b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c',
b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i',
b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ',
b'e', b'l', b'i', b't'])];
run_encode_tests(tests);
}
#[test]
fn encode_address() {
use hash::*;
let tests = vec![
ETestPair(Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(),
vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde,
0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46,
0xb3, 0x7d, 0x11, 0x06])
];
run_encode_tests(tests);
}
/// Vec<u8> (Bytes) is treated as a single value
#[test]
fn encode_vector_u8() {
let tests = vec![
ETestPair(vec![], vec![0x80]),
ETestPair(vec![0u8], vec![0]),
ETestPair(vec![0x15], vec![0x15]),
ETestPair(vec![0x40, 0x00], vec![0x82, 0x40, 0x00]),
];
run_encode_tests(tests);
}
#[test]
fn encode_vector_u64() {
let tests = vec![
ETestPair(vec![], vec![0xc0]),
ETestPair(vec![15u64], vec![0xc1, 0x0f]),
ETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]),
ETestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]),
];
run_encode_tests(tests);
}
#[test]
fn encode_vector_str() {
let tests = vec![ETestPair(vec!["cat", "dog"],
vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])];
run_encode_tests(tests);
}
#[test]
fn encode_vector_of_vectors_str() {
let tests = vec![ETestPair(vec![vec!["cat"]], vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])];
run_encode_tests(tests);
}
struct DTestPair<T>(T, Vec<u8>) where T: rlp::Decodable + fmt::Debug + cmp::Eq;
fn run_decode_tests<T>(tests: Vec<DTestPair<T>>) where T: rlp::Decodable + fmt::Debug + cmp::Eq {
for t in &tests {
let res: T = rlp::decode(&t.1);
assert_eq!(res, t.0);
}
}
/// Vec<u8> (Bytes) is treated as a single value
#[test]
fn decode_vector_u8() {
let tests = vec![
DTestPair(vec![], vec![0x80]),
DTestPair(vec![0u8], vec![0]),
DTestPair(vec![0x15], vec![0x15]),
DTestPair(vec![0x40, 0x00], vec![0x82, 0x40, 0x00]),
];
run_decode_tests(tests);
}
#[test]
fn decode_untrusted_u16() {
let tests = vec![
DTestPair(0u16, vec![0u8]),
DTestPair(0x100, vec![0x82, 0x01, 0x00]),
DTestPair(0xffff, vec![0x82, 0xff, 0xff]),
];
run_decode_tests(tests);
}
#[test]
fn decode_untrusted_u32() {
let tests = vec![
DTestPair(0u32, vec![0u8]),
DTestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]),
DTestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]),
];
run_decode_tests(tests);
}
#[test]
fn decode_untrusted_u64() {
let tests = vec![
DTestPair(0u64, vec![0u8]),
DTestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]),
DTestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]),
];
run_decode_tests(tests);
}
#[test]
fn decode_untrusted_u256() {
let tests = vec![DTestPair(U256::from(0u64), vec![0x80u8]),
DTestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]),
DTestPair(U256::from(0xffffffffu64),
vec![0x84, 0xff, 0xff, 0xff, 0xff]),
DTestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\
000100000000000012f0")
.unwrap(),
vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])];
run_decode_tests(tests);
}
#[test]
fn decode_untrusted_str() {
let tests = vec![DTestPair("cat".to_string(), vec![0x83, b'c', b'a', b't']),
DTestPair("dog".to_string(), vec![0x83, b'd', b'o', b'g']),
DTestPair("Marek".to_string(),
vec![0x85, b'M', b'a', b'r', b'e', b'k']),
DTestPair("".to_string(), vec![0x80]),
DTestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit"
.to_string(),
vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i',
b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o',
b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e',
b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c',
b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i',
b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ',
b'e', b'l', b'i', b't'])];
run_decode_tests(tests);
}
#[test]
fn decode_untrusted_address() {
use hash::*;
let tests = vec![
DTestPair(Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(),
vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde,
0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46,
0xb3, 0x7d, 0x11, 0x06])
];
run_decode_tests(tests);
}
#[test]
fn decode_untrusted_vector_u64() {
let tests = vec![
DTestPair(vec![], vec![0xc0]),
DTestPair(vec![15u64], vec![0xc1, 0x0f]),
DTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]),
DTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]),
];
run_decode_tests(tests);
}
#[test]
fn decode_untrusted_vector_str() {
let tests = vec![DTestPair(vec!["cat".to_string(), "dog".to_string()],
vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])];
run_decode_tests(tests);
}
#[test]
fn decode_untrusted_vector_of_vectors_str() {
let tests = vec![DTestPair(vec![vec!["cat".to_string()]],
vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])];
run_decode_tests(tests);
}
#[test]
fn test_rlp_json() {
println!("Json rlp test: ");
execute_tests_from_directory::<rlptest::RlpStreamTest, _>("json-tests/json/rlp/stream/*.json", &mut | file, input, output | {
println!("file: {}", file);
let mut stream = RlpStream::new();
for operation in input.into_iter() {
match operation {
rlptest::Operation::Append(ref v) => stream.append(v),
rlptest::Operation::AppendList(len) => stream.append_list(len),
rlptest::Operation::AppendRaw(ref raw, len) => stream.append_raw(raw, len),
rlptest::Operation::AppendEmpty => stream.append_empty_data()
};
}
assert_eq!(stream.out(), output);
});
}
#[test]
fn test_decoding_array() {
let v = vec![5u16, 2u16];
let res = rlp::encode(&v);
let arr: [u16; 2] = rlp::decode(&res);
assert_eq!(arr[0], 5);
assert_eq!(arr[1], 2);
}

View File

@@ -1,441 +0,0 @@
use std::cell::Cell;
use std::fmt;
use rustc_serialize::hex::ToHex;
use bytes::{FromBytes};
use rlp::{View, Decoder, Decodable, DecoderError};
/// rlp offset
#[derive(Copy, Clone, Debug)]
struct OffsetCache {
index: usize,
offset: usize,
}
impl OffsetCache {
fn new(index: usize, offset: usize) -> OffsetCache {
OffsetCache {
index: index,
offset: offset,
}
}
}
#[derive(Debug)]
pub enum Prototype {
Null,
Data(usize),
List(usize),
}
/// Stores basic information about item
pub struct PayloadInfo {
pub header_len: usize,
pub value_len: usize,
}
impl PayloadInfo {
fn new(header_len: usize, value_len: usize) -> PayloadInfo {
PayloadInfo {
header_len: header_len,
value_len: value_len,
}
}
}
/// Data-oriented view onto rlp-slice.
///
/// This is immutable structere. No operations change it.
///
/// Should be used in places where, error handling is required,
/// eg. on input
#[derive(Debug)]
pub struct UntrustedRlp<'a> {
bytes: &'a [u8],
offset_cache: Cell<OffsetCache>,
count_cache: Cell<Option<usize>>,
}
impl<'a> Clone for UntrustedRlp<'a> {
fn clone(&self) -> UntrustedRlp<'a> {
UntrustedRlp {
bytes: self.bytes,
offset_cache: self.offset_cache.clone(),
count_cache: self.count_cache.clone(),
}
}
}
impl<'a> fmt::Display for UntrustedRlp<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self.prototype() {
Ok(Prototype::Null) => write!(f, "null"),
Ok(Prototype::Data(_)) => write!(f, "\"0x{}\"", self.data().unwrap().to_hex()),
Ok(Prototype::List(len)) => {
try!(write!(f, "["));
for i in 0..len-1 {
try!(write!(f, "{}, ", self.at(i).unwrap()));
}
try!(write!(f, "{}", self.at(len - 1).unwrap()));
write!(f, "]")
},
Err(err) => write!(f, "{:?}", err)
}
}
}
impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
type Prototype = Result<Prototype, DecoderError>;
type PayloadInfo = Result<PayloadInfo, DecoderError>;
type Data = Result<&'a [u8], DecoderError>;
type Item = Result<UntrustedRlp<'a>, DecoderError>;
type Iter = UntrustedRlpIterator<'a, 'view>;
//returns new instance of `UntrustedRlp`
fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> {
UntrustedRlp {
bytes: bytes,
offset_cache: Cell::new(OffsetCache::new(usize::max_value(), 0)),
count_cache: Cell::new(None)
}
}
fn as_raw(&'view self) -> &'a [u8] {
self.bytes
}
fn prototype(&self) -> Self::Prototype {
// optimize? && return appropriate errors
if self.is_data() {
Ok(Prototype::Data(self.size()))
} else if self.is_list() {
Ok(Prototype::List(self.item_count()))
} else {
Ok(Prototype::Null)
}
}
fn payload_info(&self) -> Self::PayloadInfo {
BasicDecoder::payload_info(self.bytes)
}
fn data(&'view self) -> Self::Data {
let pi = try!(BasicDecoder::payload_info(self.bytes));
Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)])
}
fn item_count(&self) -> usize {
match self.is_list() {
true => match self.count_cache.get() {
Some(c) => c,
None => {
let c = self.iter().count();
self.count_cache.set(Some(c));
c
}
},
false => 0
}
}
fn size(&self) -> usize {
match self.is_data() {
// we can safely unwrap (?) cause its data
true => BasicDecoder::payload_info(self.bytes).unwrap().value_len,
false => 0
}
}
fn at(&'view self, index: usize) -> Self::Item {
if !self.is_list() {
return Err(DecoderError::RlpExpectedToBeList);
}
// move to cached position if it's index is less or equal to
// current search index, otherwise move to beginning of list
let c = self.offset_cache.get();
let (mut bytes, to_skip) = match c.index <= index {
true => (try!(UntrustedRlp::consume(self.bytes, c.offset)), index - c.index),
false => (try!(self.consume_list_prefix()), index),
};
// skip up to x items
bytes = try!(UntrustedRlp::consume_items(bytes, to_skip));
// update the cache
self.offset_cache.set(OffsetCache::new(index, self.bytes.len() - bytes.len()));
// construct new rlp
let found = try!(BasicDecoder::payload_info(bytes));
Ok(UntrustedRlp::new(&bytes[0..found.header_len + found.value_len]))
}
fn is_null(&self) -> bool {
self.bytes.len() == 0
}
fn is_empty(&self) -> bool {
!self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80)
}
fn is_list(&self) -> bool {
!self.is_null() && self.bytes[0] >= 0xc0
}
fn is_data(&self) -> bool {
!self.is_null() && self.bytes[0] < 0xc0
}
fn is_int(&self) -> bool {
if self.is_null() {
return false;
}
match self.bytes[0] {
0...0x80 => true,
0x81...0xb7 => self.bytes[1] != 0,
b @ 0xb8...0xbf => self.bytes[1 + b as usize - 0xb7] != 0,
_ => false
}
}
fn iter(&'view self) -> Self::Iter {
self.into_iter()
}
fn as_val<T>(&self) -> Result<T, DecoderError> where T: Decodable {
// optimize, so it doesn't use clone (although This clone is cheap)
T::decode(&BasicDecoder::new(self.clone()))
}
fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: Decodable {
try!(self.at(index)).as_val()
}
}
impl<'a> UntrustedRlp<'a> {
/// consumes first found prefix
fn consume_list_prefix(&self) -> Result<&'a [u8], DecoderError> {
let item = try!(BasicDecoder::payload_info(self.bytes));
let bytes = try!(UntrustedRlp::consume(self.bytes, item.header_len));
Ok(bytes)
}
/// consumes fixed number of items
fn consume_items(bytes: &'a [u8], items: usize) -> Result<&'a [u8], DecoderError> {
let mut result = bytes;
for _ in 0..items {
let i = try!(BasicDecoder::payload_info(result));
result = try!(UntrustedRlp::consume(result, (i.header_len + i.value_len)));
}
Ok(result)
}
/// consumes slice prefix of length `len`
fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> {
match bytes.len() >= len {
true => Ok(&bytes[len..]),
false => Err(DecoderError::RlpIsTooShort),
}
}
}
/// Iterator over rlp-slice list elements.
pub struct UntrustedRlpIterator<'a, 'view> where 'a: 'view {
rlp: &'view UntrustedRlp<'a>,
index: usize,
}
impl<'a, 'view> IntoIterator for &'view UntrustedRlp<'a> where 'a: 'view {
type Item = UntrustedRlp<'a>;
type IntoIter = UntrustedRlpIterator<'a, 'view>;
fn into_iter(self) -> Self::IntoIter {
UntrustedRlpIterator {
rlp: self,
index: 0,
}
}
}
impl<'a, 'view> Iterator for UntrustedRlpIterator<'a, 'view> {
type Item = UntrustedRlp<'a>;
fn next(&mut self) -> Option<UntrustedRlp<'a>> {
let index = self.index;
let result = self.rlp.at(index).ok();
self.index += 1;
result
}
}
struct BasicDecoder<'a> {
rlp: UntrustedRlp<'a>
}
impl<'a> BasicDecoder<'a> {
pub fn new(rlp: UntrustedRlp<'a>) -> BasicDecoder<'a> {
BasicDecoder {
rlp: rlp
}
}
/// Return first item info
fn payload_info(bytes: &[u8]) -> Result<PayloadInfo, DecoderError> {
let item = match bytes.first().map(|&x| x) {
None => return Err(DecoderError::RlpIsTooShort),
Some(0...0x7f) => PayloadInfo::new(0, 1),
Some(l @ 0x80...0xb7) => PayloadInfo::new(1, l as usize - 0x80),
Some(l @ 0xb8...0xbf) => {
let len_of_len = l as usize - 0xb7;
let header_len = 1 + len_of_len;
if bytes[1] == 0 { return Err(DecoderError::RlpDataLenWithZeroPrefix); }
let value_len = try!(usize::from_bytes(&bytes[1..header_len]));
PayloadInfo::new(header_len, value_len)
}
Some(l @ 0xc0...0xf7) => PayloadInfo::new(1, l as usize - 0xc0),
Some(l @ 0xf8...0xff) => {
let len_of_len = l as usize - 0xf7;
let header_len = 1 + len_of_len;
let value_len = try!(usize::from_bytes(&bytes[1..header_len]));
if bytes[1] == 0 { return Err(DecoderError::RlpListLenWithZeroPrefix); }
PayloadInfo::new(header_len, value_len)
},
// we cant reach this place, but rust requires _ to be implemented
_ => { unreachable!(); }
};
match item.header_len + item.value_len <= bytes.len() {
true => Ok(item),
false => Err(DecoderError::RlpIsTooShort),
}
}
}
impl<'a> Decoder for BasicDecoder<'a> {
fn read_value<T, F>(&self, f: F) -> Result<T, DecoderError>
where F: FnOnce(&[u8]) -> Result<T, DecoderError> {
let bytes = self.rlp.as_raw();
match bytes.first().map(|&x| x) {
// rlp is too short
None => Err(DecoderError::RlpIsTooShort),
// single byt value
Some(l @ 0...0x7f) => Ok(try!(f(&[l]))),
// 0-55 bytes
Some(l @ 0x80...0xb7) => {
let d = &bytes[1..(1 + l as usize - 0x80)];
if l == 0x81 && d[0] < 0x80 {
return Err(DecoderError::RlpInvalidIndirection);
}
Ok(try!(f(d)))
},
// longer than 55 bytes
Some(l @ 0xb8...0xbf) => {
let len_of_len = l as usize - 0xb7;
let begin_of_value = 1 as usize + len_of_len;
let len = try!(usize::from_bytes(&bytes[1..begin_of_value]));
Ok(try!(f(&bytes[begin_of_value..begin_of_value + len])))
}
// we are reading value, not a list!
_ => Err(DecoderError::RlpExpectedToBeData)
}
}
fn as_raw(&self) -> &[u8] {
self.rlp.as_raw()
}
fn as_list(&self) -> Result<Vec<Self>, DecoderError> {
let v: Vec<BasicDecoder<'a>> = self.rlp.iter()
.map(| i | BasicDecoder::new(i))
.collect();
Ok(v)
}
fn as_rlp<'s>(&'s self) -> &'s UntrustedRlp<'s> {
&self.rlp
}
}
impl<T> Decodable for T where T: FromBytes {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
decoder.read_value(| bytes | {
Ok(try!(T::from_bytes(bytes)))
})
}
}
impl<T> Decodable for Vec<T> where T: Decodable {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let decoders = try!(decoder.as_list());
decoders.iter().map(|d| T::decode(d)).collect()
}
}
impl Decodable for Vec<u8> {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
decoder.read_value(| bytes | {
let mut res = vec![];
res.extend(bytes);
Ok(res)
})
}
}
impl<T> Decodable for Option<T> where T: Decodable {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
decoder.read_value(| bytes | {
let res = match bytes.len() {
0 => None,
_ => Some(try!(T::decode(decoder)))
};
Ok(res)
})
}
}
macro_rules! impl_array_decodable {
($index_type:ty, $len:expr ) => (
impl<T> Decodable for [T; $len] where T: Decodable {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let decoders = try!(decoder.as_list());
let mut result: [T; $len] = unsafe { ::std::mem::uninitialized() };
if decoders.len() != $len {
return Err(DecoderError::RlpIncorrectListLen);
}
for i in 0..decoders.len() {
result[i] = try!(T::decode(&decoders[i]));
}
Ok(result)
}
}
)
}
macro_rules! impl_array_decodable_recursive {
($index_type:ty, ) => ();
($index_type:ty, $len:expr, $($more:expr,)*) => (
impl_array_decodable!($index_type, $len);
impl_array_decodable_recursive!($index_type, $($more,)*);
);
}
impl_array_decodable_recursive!(
u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224,
);
#[test]
fn test_rlp_display() {
use rustc_serialize::hex::FromHex;
let data = "f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470".from_hex().unwrap();
let rlp = UntrustedRlp::new(&data);
assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]");
}

View File

@@ -1,29 +0,0 @@
/// A version value with strict meaning. Use `to_u32` to convert to a simple integer.
///
/// # Example
/// ```
/// extern crate ethcore_util as util;
/// use util::semantic_version::*;
///
/// fn main() {
/// assert_eq!(SemanticVersion::new(1, 2, 3).as_u32(), 0x010203);
/// }
/// ```
pub struct SemanticVersion {
/// Major version - API/feature removals & breaking changes.
pub major: u8,
/// Minor version - API/feature additions.
pub minor: u8,
/// Tiny version - bug fixes.
pub tiny: u8,
}
impl SemanticVersion {
/// Create a new object.
pub fn new(major: u8, minor: u8, tiny: u8) -> SemanticVersion { SemanticVersion{major: major, minor: minor, tiny: tiny} }
/// Convert to a `u32` representation.
pub fn as_u32(&self) -> u32 { ((self.major as u32) << 16) + ((self.minor as u32) << 8) + self.tiny as u32 }
}
// TODO: implement Eq, Comparison and Debug/Display for SemanticVersion.

70
src/service.rs Normal file
View File

@@ -0,0 +1,70 @@
use util::*;
use sync::*;
use spec::Spec;
use error::*;
use std::env;
use client::Client;
/// Client service setup. Creates and registers client and network services with the IO subsystem.
pub struct ClientService {
net_service: NetworkService<SyncMessage>,
client: Arc<RwLock<Client>>,
}
impl ClientService {
/// Start the service in a separate thread.
pub fn start(spec: Spec) -> Result<ClientService, Error> {
let mut net_service = try!(NetworkService::start());
info!("Starting {}", net_service.host_info());
info!("Configured for {} using {} engine", spec.name, spec.engine_name);
let mut dir = env::home_dir().unwrap();
dir.push(".parity");
dir.push(H64::from(spec.genesis_header().hash()).hex());
let client = Arc::new(RwLock::new(try!(Client::new(spec, &dir, net_service.io().channel()))));
EthSync::register(&mut net_service, client.clone());
let client_io = Box::new(ClientIoHandler {
client: client.clone()
});
try!(net_service.io().register_handler(client_io));
Ok(ClientService {
net_service: net_service,
client: client,
})
}
pub fn io(&mut self) -> &mut IoService<NetSyncMessage> {
self.net_service.io()
}
pub fn client(&self) -> Arc<RwLock<Client>> {
self.client.clone()
}
}
/// IO interface for the Client handler
struct ClientIoHandler {
client: Arc<RwLock<Client>>
}
impl IoHandler<NetSyncMessage> for ClientIoHandler {
fn initialize<'s>(&'s mut self, _io: &mut IoContext<'s, NetSyncMessage>) {
}
fn message<'s>(&'s mut self, _io: &mut IoContext<'s, NetSyncMessage>, net_message: &'s mut NetSyncMessage) {
match net_message {
&mut UserMessage(ref mut message) => {
match message {
&mut SyncMessage::BlockVerified(ref mut bytes) => {
self.client.write().unwrap().import_verified_block(mem::replace(bytes, Bytes::new()));
},
_ => {}, // ignore other messages
}
}
_ => {}, // ignore other messages
}
}
}

View File

@@ -1,59 +0,0 @@
//! Wrapper around tiny-keccak crate.
use std::mem::uninitialized;
use bytes::{BytesConvertable, Populatable};
use hash::{H256, FixedHash};
pub const SHA3_EMPTY: H256 = H256( [0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70] );
extern {
fn sha3_256(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) -> i32;
}
/// Types implementing this trait are sha3able.
///
/// ```
/// extern crate ethcore_util as util;
/// use std::str::FromStr;
/// use util::sha3::*;
/// use util::hash::*;
///
/// fn main() {
/// assert_eq!([0u8; 0].sha3(), H256::from_str("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap());
/// }
/// ```
pub trait Hashable {
/// Calculate SHA3 of this object.
fn sha3(&self) -> H256;
/// Calculate SHA3 of this object and place result into dest.
fn sha3_into(&self, dest: &mut [u8]) {
self.sha3().copy_to(dest);
}
}
impl<T> Hashable for T where T: BytesConvertable {
fn sha3(&self) -> H256 {
unsafe {
let mut ret: H256 = uninitialized();
self.sha3_into(ret.as_slice_mut());
ret
}
}
fn sha3_into(&self, dest: &mut [u8]) {
unsafe {
let input: &[u8] = self.bytes();
sha3_256(dest.as_mut_ptr(), dest.len(), input.as_ptr(), input.len());
}
}
}
#[test]
fn sha3_empty() {
assert_eq!([0u8; 0].sha3(), SHA3_EMPTY);
}
#[test]
fn sha3_as() {
assert_eq!([0x41u8; 32].sha3(), From::from("59cad5948673622c1d64e2322488bf01619f7ff45789741b15a9f782ce9290a8"));
}

269
src/spec.rs Normal file
View File

@@ -0,0 +1,269 @@
use common::*;
use flate2::read::GzDecoder;
use engine::*;
use null_engine::*;
/// Converts file from base64 gzipped bytes to json
pub fn gzip64res_to_json(source: &[u8]) -> Json {
// there is probably no need to store genesis in based64 gzip,
// but that's what go does, and it was easy to load it this way
let data = source.from_base64().expect("Genesis block is malformed!");
let data_ref: &[u8] = &data;
let mut decoder = GzDecoder::new(data_ref).expect("Gzip is invalid");
let mut s: String = "".to_string();
decoder.read_to_string(&mut s).expect("Gzip is invalid");
Json::from_str(&s).expect("Json is invalid")
}
/// Convert JSON value to equivlaent RLP representation.
// TODO: handle container types.
fn json_to_rlp(json: &Json) -> Bytes {
match json {
&Json::Boolean(o) => encode(&(if o {1u64} else {0})),
&Json::I64(o) => encode(&(o as u64)),
&Json::U64(o) => encode(&o),
&Json::String(ref s) if s.len() >= 2 && &s[0..2] == "0x" && U256::from_str(&s[2..]).is_ok() => {
encode(&U256::from_str(&s[2..]).unwrap())
},
&Json::String(ref s) => {
encode(s)
},
_ => panic!()
}
}
/// Convert JSON to a string->RLP map.
fn json_to_rlp_map(json: &Json) -> HashMap<String, Bytes> {
json.as_object().unwrap().iter().map(|(k, v)| (k, json_to_rlp(v))).fold(HashMap::new(), |mut acc, kv| {
acc.insert(kv.0.clone(), kv.1);
acc
})
}
//TODO: add code and data
#[derive(Debug)]
/// Genesis account data. Does no thave a DB overlay cache
pub struct GenesisAccount {
// Balance of the account.
balance: U256,
// Nonce of the account.
nonce: U256,
}
impl GenesisAccount {
pub fn rlp(&self) -> Bytes {
let mut stream = RlpStream::new_list(4);
stream.append(&self.nonce);
stream.append(&self.balance);
stream.append(&SHA3_NULL_RLP);
stream.append(&SHA3_EMPTY);
stream.out()
}
}
/// Parameters for a block chain; includes both those intrinsic to the design of the
/// chain and those to be interpreted by the active chain engine.
#[derive(Debug)]
pub struct Spec {
// User friendly spec name
pub name: String,
// What engine are we using for this?
pub engine_name: String,
// Parameters concerning operation of the specific engine we're using.
// Name -> RLP-encoded value
pub engine_params: HashMap<String, Bytes>,
// Builtin-contracts are here for now but would like to abstract into Engine API eventually.
pub builtins: HashMap<Address, Builtin>,
// Genesis params.
pub parent_hash: H256,
pub author: Address,
pub difficulty: U256,
pub gas_limit: U256,
pub gas_used: U256,
pub timestamp: u64,
pub extra_data: Bytes,
pub genesis_state: HashMap<Address, GenesisAccount>,
pub seal_fields: usize,
pub seal_rlp: Bytes,
// May be prepopulated if we know this in advance.
state_root_memo: RwLock<Option<H256>>,
}
impl Spec {
/// Convert this object into a boxed Engine of the right underlying type.
// TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead.
pub fn to_engine(self) -> Result<Box<Engine>, Error> {
match self.engine_name.as_ref() {
"NullEngine" => Ok(NullEngine::new_boxed(self)),
"Ethash" => Ok(super::ethereum::Ethash::new_boxed(self)),
_ => Err(Error::UnknownEngineName(self.engine_name.clone()))
}
}
/// Return the state root for the genesis state, memoising accordingly.
pub fn state_root(&self) -> H256 {
if self.state_root_memo.read().unwrap().is_none() {
*self.state_root_memo.write().unwrap() = Some(sec_trie_root(self.genesis_state.iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect()));
}
self.state_root_memo.read().unwrap().as_ref().unwrap().clone()
}
pub fn genesis_header(&self) -> Header {
Header {
parent_hash: self.parent_hash.clone(),
timestamp: self.timestamp,
number: 0,
author: self.author.clone(),
transactions_root: SHA3_NULL_RLP.clone(),
uncles_hash: RlpStream::new_list(0).out().sha3(),
extra_data: self.extra_data.clone(),
state_root: self.state_root().clone(),
receipts_root: SHA3_NULL_RLP.clone(),
log_bloom: H2048::new().clone(),
gas_used: self.gas_used.clone(),
gas_limit: self.gas_limit.clone(),
difficulty: self.difficulty.clone(),
seal: {
let seal = {
let mut s = RlpStream::new_list(self.seal_fields);
s.append_raw(&self.seal_rlp, self.seal_fields);
s.out()
};
let r = Rlp::new(&seal);
(0..self.seal_fields).map(|i| r.at(i).as_raw().to_vec()).collect()
},
hash: RefCell::new(None),
}
}
/// Compose the genesis block for this chain.
pub fn genesis_block(&self) -> Bytes {
let empty_list = RlpStream::new_list(0).out();
let header = self.genesis_header();
let mut ret = RlpStream::new_list(3);
ret.append(&header);
ret.append_raw(&empty_list, 1);
ret.append_raw(&empty_list, 1);
ret.out()
}
}
impl FromJson for Spec {
/// Loads a chain-specification from a json data structure
fn from_json(json: &Json) -> Spec {
// once we commit ourselves to some json parsing library (serde?)
// move it to proper data structure
let mut state = HashMap::new();
let mut builtins = HashMap::new();
if let Some(&Json::Object(ref accounts)) = json.find("accounts") {
for (address, acc) in accounts.iter() {
let addr = Address::from_str(address).unwrap();
if let Some(ref builtin_json) = acc.find("builtin") {
if let Some(builtin) = Builtin::from_json(builtin_json) {
builtins.insert(addr.clone(), builtin);
}
}
let balance = acc.find("balance").and_then(|x| match x { &Json::String(ref b) => U256::from_dec_str(b).ok(), _ => None });
let nonce = acc.find("nonce").and_then(|x| match x { &Json::String(ref b) => U256::from_dec_str(b).ok(), _ => None });
// let balance = if let Some(&Json::String(ref b)) = acc.find("balance") {U256::from_dec_str(b).unwrap_or(U256::from(0))} else {U256::from(0)};
// let nonce = if let Some(&Json::String(ref n)) = acc.find("nonce") {U256::from_dec_str(n).unwrap_or(U256::from(0))} else {U256::from(0)};
// TODO: handle code & data if they exist.
if balance.is_some() || nonce.is_some() {
state.insert(addr, GenesisAccount { balance: balance.unwrap_or(U256::from(0)), nonce: nonce.unwrap_or(U256::from(0)) });
}
}
}
let genesis = &json["genesis"];//.as_object().expect("No genesis object in JSON");
let (seal_fields, seal_rlp) = {
if genesis.find("mixHash").is_some() && genesis.find("nonce").is_some() {
let mut s = RlpStream::new();
s.append(&H256::from_str(&genesis["mixHash"].as_string().expect("mixHash not a string.")[2..]).expect("Invalid mixHash string value"));
s.append(&H64::from_str(&genesis["nonce"].as_string().expect("nonce not a string.")[2..]).expect("Invalid nonce string value"));
(2, s.out())
} else {
// backup algo that will work with sealFields/sealRlp (and without).
(
usize::from_str(&genesis["sealFields"].as_string().unwrap_or("0x")[2..]).expect("Invalid sealFields integer data"),
genesis["sealRlp"].as_string().unwrap_or("0x")[2..].from_hex().expect("Invalid sealRlp hex data")
)
}
};
Spec {
name: json.find("name").map(|j| j.as_string().unwrap()).unwrap_or("unknown").to_string(),
engine_name: json["engineName"].as_string().unwrap().to_string(),
engine_params: json_to_rlp_map(&json["params"]),
builtins: builtins,
parent_hash: H256::from_str(&genesis["parentHash"].as_string().unwrap()[2..]).unwrap(),
author: Address::from_str(&genesis["author"].as_string().unwrap()[2..]).unwrap(),
difficulty: U256::from_str(&genesis["difficulty"].as_string().unwrap()[2..]).unwrap(),
gas_limit: U256::from_str(&genesis["gasLimit"].as_string().unwrap()[2..]).unwrap(),
gas_used: U256::from(0u8),
timestamp: u64::from_str(&genesis["timestamp"].as_string().unwrap()[2..]).unwrap(),
extra_data: genesis["extraData"].as_string().unwrap()[2..].from_hex().unwrap(),
genesis_state: state,
seal_fields: seal_fields,
seal_rlp: seal_rlp,
state_root_memo: RwLock::new(genesis.find("stateRoot").and_then(|_| genesis["stateRoot"].as_string()).map(|s| H256::from_str(&s[2..]).unwrap())),
}
}
}
impl Spec {
/// Ensure that the given state DB has the trie nodes in for the genesis state.
pub fn ensure_db_good(&self, db: &mut HashDB) {
if !db.contains(&self.state_root()) {
info!("Populating genesis state...");
let mut root = H256::new();
{
let mut t = SecTrieDBMut::new(db, &mut root);
for (address, account) in self.genesis_state.iter() {
t.insert(address.as_slice(), &account.rlp());
}
}
assert!(db.contains(&self.state_root()));
info!("Genesis state is ready");
}
}
/// Create a new Spec from a JSON UTF-8 data resource `data`.
pub fn from_json_utf8(data: &[u8]) -> Spec {
Self::from_json_str(::std::str::from_utf8(data).unwrap())
}
/// Create a new Spec from a JSON string.
pub fn from_json_str(s: &str) -> Spec {
Self::from_json(&Json::from_str(s).expect("Json is invalid"))
}
/// Create a new Spec which conforms to the Morden chain except that it's a NullEngine consensus.
pub fn new_test() -> Spec { Self::from_json_utf8(include_bytes!("../res/null_morden.json")) }
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use util::hash::*;
use util::sha3::*;
use views::*;
use super::*;
#[test]
fn test_chain() {
let test_spec = Spec::new_test();
assert_eq!(test_spec.state_root(), H256::from_str("f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9").unwrap());
let genesis = test_spec.genesis_block();
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap());
let _ = test_spec.to_engine();
}
}

View File

@@ -1,67 +0,0 @@
//! Helper module that should be used to randomly squeeze
//! caches to a given size in bytes
//!
//! ```
//! extern crate heapsize;
//! extern crate ethcore_util as util;
//! use std::collections::HashMap;
//! use std::mem::size_of;
//! use heapsize::HeapSizeOf;
//! use util::squeeze::Squeeze;
//!
//! fn main() {
//! let initial_size = 60;
//! let mut map: HashMap<u8, u8> = HashMap::with_capacity(initial_size);
//! assert!(map.capacity() >= initial_size);
//! for i in 0..initial_size {
//! map.insert(i as u8, i as u8);
//! }
//!
//! assert_eq!(map.heap_size_of_children(), map.capacity() * 2 * size_of::<u8>());
//! assert_eq!(map.len(), initial_size);
//! let initial_heap_size = map.heap_size_of_children();
//!
//! // squeeze it to size of key and value
//! map.squeeze(2 * size_of::<u8>());
//! assert_eq!(map.len(), 1);
//!
//! // its likely that heap size was reduced, but we can't be 100% sure
//! assert!(initial_heap_size >= map.heap_size_of_children());
//! }
//! ```
use std::collections::HashMap;
use std::hash::Hash;
use heapsize::HeapSizeOf;
/// Should be used to squeeze collections to certain size in bytes
pub trait Squeeze {
fn squeeze(&mut self, size: usize);
}
impl<K, T> Squeeze for HashMap<K, T> where K: Eq + Hash + Clone + HeapSizeOf, T: HeapSizeOf {
fn squeeze(&mut self, size: usize) {
if self.len() == 0 {
return
}
let size_of_entry = self.heap_size_of_children() / self.capacity();
let all_entries = size_of_entry * self.len();
let mut shrinked_size = all_entries;
while self.len() > 0 && shrinked_size > size {
// could be optimized
let key = self.keys().next().unwrap().clone();
self.remove(&key);
shrinked_size -= size_of_entry;
}
self.shrink_to_fit();
// if we squeezed something, but not enough, squeeze again
if all_entries != shrinked_size && self.heap_size_of_children() > size {
self.squeeze(size);
}
}
}

View File

@@ -1,29 +0,0 @@
pub use std::io;
pub use std::str;
pub use std::fmt;
pub use std::slice;
pub use std::cmp;
pub use std::ptr;
pub use std::result;
pub use std::option;
pub use std::mem;
pub use std::ops;
pub use std::path::Path;
pub use std::str::{FromStr};
pub use std::io::{Read,Write};
pub use std::hash::{Hash, Hasher};
pub use std::error::Error as StdError;
pub use std::sync::*;
pub use std::ops::*;
pub use std::cmp::*;
pub use std::cell::*;
pub use std::collections::*;
pub use rustc_serialize::json::Json;
pub use rustc_serialize::base64::FromBase64;
pub use rustc_serialize::hex::{FromHex, FromHexError};
pub use heapsize::HeapSizeOf;
pub use itertools::Itertools;

439
src/state.rs Normal file
View File

@@ -0,0 +1,439 @@
use common::*;
use engine::Engine;
use executive::Executive;
use pod_account::*;
use pod_state::*;
use state_diff::*;
pub type ApplyResult = Result<Receipt, Error>;
/// Representation of the entire state of all accounts in the system.
#[derive(Clone)]
pub struct State {
db: OverlayDB,
root: H256,
cache: RefCell<HashMap<Address, Option<Account>>>,
account_start_nonce: U256,
}
impl State {
/// Creates new state with empty state root
pub fn new(mut db: OverlayDB, account_start_nonce: U256) -> State {
let mut root = H256::new();
{
// init trie and reset root too null
let _ = SecTrieDBMut::new(&mut db, &mut root);
}
State {
db: db,
root: root,
cache: RefCell::new(HashMap::new()),
account_start_nonce: account_start_nonce,
}
}
/// Creates new state with existing state root
pub fn from_existing(db: OverlayDB, root: H256, account_start_nonce: U256) -> State {
{
// trie should panic! if root does not exist
let _ = SecTrieDB::new(&db, &root);
}
State {
db: db,
root: root,
cache: RefCell::new(HashMap::new()),
account_start_nonce: account_start_nonce,
}
}
/// Create temporary state object
pub fn new_temp() -> State {
Self::new(OverlayDB::new_temp(), U256::from(0u8))
}
/// Destroy the current object and return root and database.
pub fn drop(self) -> (H256, OverlayDB) {
(self.root, self.db)
}
/// Return reference to root
pub fn root(&self) -> &H256 {
&self.root
}
/// Expose the underlying database; good to use for calling `state.db().commit()`.
pub fn db(&mut self) -> &mut OverlayDB {
&mut self.db
}
/// Create a new contract at address `contract`. If there is already an account at the address
/// it will have its code reset, ready for `init_code()`.
pub fn new_contract(&mut self, contract: &Address) {
self.require_or_from(contract, false, || Account::new_contract(U256::from(0u8)), |r| r.reset_code());
}
/// Remove an existing account.
pub fn kill_account(&mut self, account: &Address) {
self.cache.borrow_mut().insert(account.clone(), None);
}
/// Determine whether an account exists.
pub fn exists(&self, a: &Address) -> bool {
self.cache.borrow().get(&a).unwrap_or(&None).is_some() || SecTrieDB::new(&self.db, &self.root).contains(&a)
}
/// Get the balance of account `a`.
pub fn balance(&self, a: &Address) -> U256 {
self.get(a, false).as_ref().map(|account| account.balance().clone()).unwrap_or(U256::from(0u8))
}
/// Get the nonce of account `a`.
pub fn nonce(&self, a: &Address) -> U256 {
self.get(a, false).as_ref().map(|account| account.nonce().clone()).unwrap_or(U256::from(0u8))
}
/// Mutate storage of account `a` so that it is `value` for `key`.
pub fn storage_at(&self, a: &Address, key: &H256) -> H256 {
self.get(a, false).as_ref().map(|a|a.storage_at(&self.db, key)).unwrap_or(H256::new())
}
/// Mutate storage of account `a` so that it is `value` for `key`.
pub fn code(&self, a: &Address) -> Option<Bytes> {
self.get(a, true).as_ref().map(|a|a.code().map(|x|x.to_vec())).unwrap_or(None)
}
/// Add `incr` to the balance of account `a`.
pub fn add_balance(&mut self, a: &Address, incr: &U256) {
let old = self.balance(a);
self.require(a, false).add_balance(incr);
trace!("state: add_balance({}, {}): {} -> {}\n", a, incr, old, self.balance(a));
}
/// Subtract `decr` from the balance of account `a`.
pub fn sub_balance(&mut self, a: &Address, decr: &U256) {
let old = self.balance(a);
self.require(a, false).sub_balance(decr);
trace!("state: sub_balance({}, {}): {} -> {}\n", a, decr, old, self.balance(a));
}
/// Subtracts `by` from the balance of `from` and adds it to that of `to`.
pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256) {
self.sub_balance(from, by);
self.add_balance(to, by);
}
/// Increment the nonce of account `a` by 1.
pub fn inc_nonce(&mut self, a: &Address) {
self.require(a, false).inc_nonce()
}
/// Mutate storage of account `a` so that it is `value` for `key`.
pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) {
self.require(a, false).set_storage(key, value)
}
/// Initialise the code of account `a` so that it is `value` for `key`.
/// NOTE: Account should have been created with `new_contract`.
pub fn init_code(&mut self, a: &Address, code: Bytes) {
self.require_or_from(a, true, || Account::new_contract(U256::from(0u8)), |_|{}).init_code(code);
}
/// Execute a given transaction.
/// This will change the state accordingly.
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult {
let old = self.to_pod();
let e = try!(Executive::new(self, env_info, engine).transact(t));
//println!("Executed: {:?}", e);
debug!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));
self.commit();
let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs);
debug!("Transaction receipt: {:?}", receipt);
Ok(receipt)
}
pub fn revert(&mut self, backup: State) {
self.cache = backup.cache;
}
/// Convert into a JSON representation.
pub fn as_json(&self) -> String {
unimplemented!();
}
/// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit.
/// `accounts` is mutable because we may need to commit the code or storage and record that.
pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap<Address, Option<Account>>) {
// first, commit the sub trees.
// TODO: is this necessary or can we dispense with the `ref mut a` for just `a`?
for (_, ref mut a) in accounts.iter_mut() {
match a {
&mut&mut Some(ref mut account) => {
account.commit_storage(db);
account.commit_code(db);
}
&mut&mut None => {}
}
}
{
let mut trie = SecTrieDBMut::from_existing(db, root);
for (address, ref a) in accounts.iter() {
match a {
&&Some(ref account) => trie.insert(address, &account.rlp()),
&&None => trie.remove(address),
}
}
}
}
/// Commits our cached account changes into the trie.
pub fn commit(&mut self) {
Self::commit_into(&mut self.db, &mut self.root, self.cache.borrow_mut().deref_mut());
}
/// Populate the state from `accounts`.
pub fn populate_from(&mut self, accounts: PodState) {
for (add, acc) in accounts.drain().into_iter() {
self.cache.borrow_mut().insert(add, Some(Account::from_pod(acc)));
}
}
/// Populate a PodAccount map from this state.
pub fn to_hashmap_pod(&self) -> HashMap<Address, PodAccount> {
// TODO: handle database rather than just the cache.
self.cache.borrow().iter().fold(HashMap::new(), |mut m, (add, opt)| {
if let &Some(ref acc) = opt {
m.insert(add.clone(), PodAccount::from_account(acc));
}
m
})
}
/// Populate a PodAccount map from this state.
pub fn to_pod(&self) -> PodState {
// TODO: handle database rather than just the cache.
PodState::new(self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| {
if let &Some(ref acc) = opt {
m.insert(add.clone(), PodAccount::from_account(acc));
}
m
}))
}
/// Pull account `a` in our cache from the trie DB and return it.
/// `require_code` requires that the code be cached, too.
fn get(&self, a: &Address, require_code: bool) -> Ref<Option<Account>> {
self.cache.borrow_mut().entry(a.clone()).or_insert_with(|| {
SecTrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))
});
if require_code {
if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() {
account.cache_code(&self.db);
}
}
Ref::map(self.cache.borrow(), |m| m.get(a).unwrap())
}
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
fn require(&self, a: &Address, require_code: bool) -> RefMut<Account> {
self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8), self.account_start_nonce), |_|{})
}
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
/// If it doesn't exist, make account equal the evaluation of `default`.
fn require_or_from<F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> RefMut<Account> {
self.cache.borrow_mut().entry(a.clone()).or_insert_with(||
SecTrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp)));
let preexists = self.cache.borrow().get(a).unwrap().is_none();
if preexists {
self.cache.borrow_mut().insert(a.clone(), Some(default()));
} else {
not_default(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().unwrap());
}
let b = self.cache.borrow_mut();
RefMut::map(b, |m| m.get_mut(a).unwrap().as_mut().map(|account| {
if require_code {
account.cache_code(&self.db);
}
account
}).unwrap())
}
}
impl fmt::Debug for State {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.cache.borrow())
}
}
#[cfg(test)]
mod tests {
use super::*;
use util::hash::*;
use util::trie::*;
use util::rlp::*;
use util::uint::*;
use account::*;
#[test]
fn code_from_database() {
let a = Address::zero();
let (r, db) = {
let mut s = State::new_temp();
s.require_or_from(&a, false, ||Account::new_contract(U256::from(42u32)), |_|{});
s.init_code(&a, vec![1, 2, 3]);
assert_eq!(s.code(&a), Some([1u8, 2, 3].to_vec()));
s.commit();
assert_eq!(s.code(&a), Some([1u8, 2, 3].to_vec()));
s.drop()
};
let s = State::from_existing(db, r, U256::from(0u8));
assert_eq!(s.code(&a), Some([1u8, 2, 3].to_vec()));
}
#[test]
fn storage_at_from_database() {
let a = Address::zero();
let (r, db) = {
let mut s = State::new_temp();
s.set_storage(&a, H256::from(&U256::from(01u64)), H256::from(&U256::from(69u64)));
s.commit();
s.drop()
};
let s = State::from_existing(db, r, U256::from(0u8));
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64)));
}
#[test]
fn get_from_database() {
let a = Address::zero();
let (r, db) = {
let mut s = State::new_temp();
s.inc_nonce(&a);
s.add_balance(&a, &U256::from(69u64));
s.commit();
assert_eq!(s.balance(&a), U256::from(69u64));
s.drop()
};
let s = State::from_existing(db, r, U256::from(0u8));
assert_eq!(s.balance(&a), U256::from(69u64));
assert_eq!(s.nonce(&a), U256::from(1u64));
}
#[test]
fn remove() {
let a = Address::zero();
let mut s = State::new_temp();
assert_eq!(s.exists(&a), false);
s.inc_nonce(&a);
assert_eq!(s.exists(&a), true);
assert_eq!(s.nonce(&a), U256::from(1u64));
s.kill_account(&a);
assert_eq!(s.exists(&a), false);
assert_eq!(s.nonce(&a), U256::from(0u64));
}
#[test]
fn remove_from_database() {
let a = Address::zero();
let (r, db) = {
let mut s = State::new_temp();
s.inc_nonce(&a);
s.commit();
assert_eq!(s.exists(&a), true);
assert_eq!(s.nonce(&a), U256::from(1u64));
s.drop()
};
let (r, db) = {
let mut s = State::from_existing(db, r, U256::from(0u8));
assert_eq!(s.exists(&a), true);
assert_eq!(s.nonce(&a), U256::from(1u64));
s.kill_account(&a);
s.commit();
assert_eq!(s.exists(&a), false);
assert_eq!(s.nonce(&a), U256::from(0u64));
s.drop()
};
let s = State::from_existing(db, r, U256::from(0u8));
assert_eq!(s.exists(&a), false);
assert_eq!(s.nonce(&a), U256::from(0u64));
}
#[test]
fn alter_balance() {
let mut s = State::new_temp();
let a = Address::zero();
let b = address_from_u64(1u64);
s.add_balance(&a, &U256::from(69u64));
assert_eq!(s.balance(&a), U256::from(69u64));
s.commit();
assert_eq!(s.balance(&a), U256::from(69u64));
s.sub_balance(&a, &U256::from(42u64));
assert_eq!(s.balance(&a), U256::from(27u64));
s.commit();
assert_eq!(s.balance(&a), U256::from(27u64));
s.transfer_balance(&a, &b, &U256::from(18u64));
assert_eq!(s.balance(&a), U256::from(9u64));
assert_eq!(s.balance(&b), U256::from(18u64));
s.commit();
assert_eq!(s.balance(&a), U256::from(9u64));
assert_eq!(s.balance(&b), U256::from(18u64));
}
#[test]
fn alter_nonce() {
let mut s = State::new_temp();
let a = Address::zero();
s.inc_nonce(&a);
assert_eq!(s.nonce(&a), U256::from(1u64));
s.inc_nonce(&a);
assert_eq!(s.nonce(&a), U256::from(2u64));
s.commit();
assert_eq!(s.nonce(&a), U256::from(2u64));
s.inc_nonce(&a);
assert_eq!(s.nonce(&a), U256::from(3u64));
s.commit();
assert_eq!(s.nonce(&a), U256::from(3u64));
}
#[test]
fn balance_nonce() {
let mut s = State::new_temp();
let a = Address::zero();
assert_eq!(s.balance(&a), U256::from(0u64));
assert_eq!(s.nonce(&a), U256::from(0u64));
s.commit();
assert_eq!(s.balance(&a), U256::from(0u64));
assert_eq!(s.nonce(&a), U256::from(0u64));
}
#[test]
fn ensure_cached() {
let mut s = State::new_temp();
let a = Address::zero();
s.require(&a, false);
s.commit();
assert_eq!(s.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785");
}
#[test]
fn create_empty() {
let mut s = State::new_temp();
s.commit();
assert_eq!(s.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421");
}
}

98
src/state_diff.rs Normal file
View File

@@ -0,0 +1,98 @@
use util::*;
use pod_state::*;
use account_diff::*;
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct StateDiff (BTreeMap<Address, AccountDiff>);
impl StateDiff {
/// Calculate and return diff between `pre` state and `post` state.
pub fn diff_pod(pre: &PodState, post: &PodState) -> StateDiff {
StateDiff(pre.get().keys().merge(post.get().keys()).filter_map(|acc| AccountDiff::diff_pod(pre.get().get(acc), post.get().get(acc)).map(|d|(acc.clone(), d))).collect())
}
}
impl fmt::Display for StateDiff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (add, acc) in self.0.iter() {
try!(write!(f, "{} {}: {}", acc.existance(), add, acc));
}
Ok(())
}
}
#[cfg(test)]
mod test {
use common::*;
use pod_state::*;
use account_diff::*;
use pod_account::*;
use super::*;
#[test]
fn create_delete() {
let a = PodState::new(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]);
assert_eq!(StateDiff::diff_pod(&a, &PodState::new(map![])), StateDiff(map![
x!(1) => AccountDiff{
balance: Diff::Died(x!(69)),
nonce: Diff::Died(x!(0)),
code: Diff::Died(vec![]),
storage: map![],
}
]));
assert_eq!(StateDiff::diff_pod(&PodState::new(map![]), &a), StateDiff(map![
x!(1) => AccountDiff{
balance: Diff::Born(x!(69)),
nonce: Diff::Born(x!(0)),
code: Diff::Born(vec![]),
storage: map![],
}
]));
}
#[test]
fn create_delete_with_unchanged() {
let a = PodState::new(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]);
let b = PodState::new(map![
x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]),
x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![])
]);
assert_eq!(StateDiff::diff_pod(&a, &b), StateDiff(map![
x!(2) => AccountDiff{
balance: Diff::Born(x!(69)),
nonce: Diff::Born(x!(0)),
code: Diff::Born(vec![]),
storage: map![],
}
]));
assert_eq!(StateDiff::diff_pod(&b, &a), StateDiff(map![
x!(2) => AccountDiff{
balance: Diff::Died(x!(69)),
nonce: Diff::Died(x!(0)),
code: Diff::Died(vec![]),
storage: map![],
}
]));
}
#[test]
fn change_with_unchanged() {
let a = PodState::new(map![
x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]),
x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![])
]);
let b = PodState::new(map![
x!(1) => PodAccount::new(x!(69), x!(1), vec![], map![]),
x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![])
]);
assert_eq!(StateDiff::diff_pod(&a, &b), StateDiff(map![
x!(1) => AccountDiff{
balance: Diff::Same,
nonce: Diff::Changed(x!(0), x!(1)),
code: Diff::Same,
storage: map![],
}
]));
}
}

34
src/substate.rs Normal file
View File

@@ -0,0 +1,34 @@
use common::*;
/// State changes which should be applied in finalize,
/// after transaction is fully executed.
#[derive(Debug)]
pub struct Substate {
/// Any accounts that have suicided.
pub suicides: HashSet<Address>,
/// Any logs.
pub logs: Vec<LogEntry>,
/// Refund counter of SSTORE nonzero -> zero.
pub sstore_clears_count: U256,
/// Created contracts.
pub contracts_created: Vec<Address>
}
impl Substate {
/// Creates new substate.
pub fn new() -> Self {
Substate {
suicides: HashSet::new(),
logs: vec![],
sstore_clears_count: U256::zero(),
contracts_created: vec![]
}
}
pub fn accrue(&mut self, s: Substate) {
self.suicides.extend(s.suicides.into_iter());
self.logs.extend(s.logs.into_iter());
self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count;
self.contracts_created.extend(s.contracts_created.into_iter());
}
}

973
src/sync/chain.rs Normal file
View File

@@ -0,0 +1,973 @@
///
/// BlockChain synchronization strategy.
/// Syncs to peers and keeps up to date.
/// This implementation uses ethereum protocol v63
///
/// Syncing strategy.
///
/// 1. A peer arrives with a total difficulty better than ours
/// 2. Find a common best block between our an peer chain.
/// Start with out best block and request headers from peer backwards until a common block is found
/// 3. Download headers and block bodies from peers in parallel.
/// As soon as a set of the blocks is fully downloaded at the head of the queue it is fed to the blockchain
/// 4. Maintain sync by handling NewBlocks/NewHashes messages
///
use util::*;
use std::mem::{replace};
use views::{HeaderView};
use header::{BlockNumber, Header as BlockHeader};
use client::{BlockChainClient, BlockStatus};
use sync::range_collection::{RangeCollection, ToUsize, FromUsize};
use error::*;
use sync::io::SyncIo;
impl ToUsize for BlockNumber {
fn to_usize(&self) -> usize {
*self as usize
}
}
impl FromUsize for BlockNumber {
fn from_usize(s: usize) -> BlockNumber {
s as BlockNumber
}
}
type PacketDecodeError = DecoderError;
const PROTOCOL_VERSION: u8 = 63u8;
const MAX_BODIES_TO_SEND: usize = 256;
const MAX_HEADERS_TO_SEND: usize = 512;
const MAX_NODE_DATA_TO_SEND: usize = 1024;
const MAX_RECEIPTS_TO_SEND: usize = 1024;
const MAX_HEADERS_TO_REQUEST: usize = 512;
const MAX_BODIES_TO_REQUEST: usize = 256;
const STATUS_PACKET: u8 = 0x00;
const NEW_BLOCK_HASHES_PACKET: u8 = 0x01;
const TRANSACTIONS_PACKET: u8 = 0x02;
const GET_BLOCK_HEADERS_PACKET: u8 = 0x03;
const BLOCK_HEADERS_PACKET: u8 = 0x04;
const GET_BLOCK_BODIES_PACKET: u8 = 0x05;
const BLOCK_BODIES_PACKET: u8 = 0x06;
const NEW_BLOCK_PACKET: u8 = 0x07;
const GET_NODE_DATA_PACKET: u8 = 0x0d;
const NODE_DATA_PACKET: u8 = 0x0e;
const GET_RECEIPTS_PACKET: u8 = 0x0f;
const RECEIPTS_PACKET: u8 = 0x10;
const NETWORK_ID: U256 = ONE_U256; //TODO: get this from parent
struct Header {
/// Header data
data: Bytes,
/// Block hash
hash: H256,
/// Parent hash
parent: H256,
}
/// Used to identify header by transactions and uncles hashes
#[derive(Eq, PartialEq, Hash)]
struct HeaderId {
transactions_root: H256,
uncles: H256
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
/// Sync state
pub enum SyncState {
/// Initial chain sync has not started yet
NotSynced,
/// Initial chain sync complete. Waiting for new packets
Idle,
/// Block downloading paused. Waiting for block queue to process blocks and free some space
Waiting,
/// Downloading blocks
Blocks,
/// Downloading blocks learned from NewHashes packet
NewBlocks,
}
/// Syncing status and statistics
pub struct SyncStatus {
/// State
pub state: SyncState,
/// Syncing protocol version. That's the maximum protocol version we connect to.
pub protocol_version: u8,
/// BlockChain height for the moment the sync started.
pub start_block_number: BlockNumber,
/// Last fully downloaded and imported block number.
pub last_imported_block_number: BlockNumber,
/// Highest block number in the download queue.
pub highest_block_number: BlockNumber,
/// Total number of blocks for the sync process.
pub blocks_total: usize,
/// Number of blocks downloaded so far.
pub blocks_received: usize,
}
#[derive(PartialEq, Eq, Debug)]
/// Peer data type requested
enum PeerAsking {
Nothing,
BlockHeaders,
BlockBodies,
}
/// Syncing peer information
struct PeerInfo {
/// eth protocol version
protocol_version: u32,
/// Peer chain genesis hash
genesis: H256,
/// Peer network id
network_id: U256,
/// Peer best block hash
latest: H256,
/// Peer total difficulty
difficulty: U256,
/// Type of data currenty being requested from peer.
asking: PeerAsking,
/// A set of block numbers being requested
asking_blocks: Vec<BlockNumber>,
}
/// Blockchain sync handler.
/// See module documentation for more details.
pub struct ChainSync {
/// Sync state
state: SyncState,
/// Last block number for the start of sync
starting_block: BlockNumber,
/// Highest block number seen
highest_block: BlockNumber,
/// Set of block header numbers being downloaded
downloading_headers: HashSet<BlockNumber>,
/// Set of block body numbers being downloaded
downloading_bodies: HashSet<BlockNumber>,
/// Downloaded headers.
headers: Vec<(BlockNumber, Vec<Header>)>, //TODO: use BTreeMap once range API is sable. For now it is a vector sorted in descending order
/// Downloaded bodies
bodies: Vec<(BlockNumber, Vec<Bytes>)>, //TODO: use BTreeMap once range API is sable. For now it is a vector sorted in descending order
/// Peer info
peers: HashMap<PeerId, PeerInfo>,
/// Used to map body to header
header_ids: HashMap<HeaderId, BlockNumber>,
/// Last impoted block number
last_imported_block: BlockNumber,
/// Last impoted block hash
last_imported_hash: H256,
/// Syncing total difficulty
syncing_difficulty: U256,
/// True if common block for our and remote chain has been found
have_common_block: bool,
}
impl ChainSync {
/// Create a new instance of syncing strategy.
pub fn new() -> ChainSync {
ChainSync {
state: SyncState::NotSynced,
starting_block: 0,
highest_block: 0,
downloading_headers: HashSet::new(),
downloading_bodies: HashSet::new(),
headers: Vec::new(),
bodies: Vec::new(),
peers: HashMap::new(),
header_ids: HashMap::new(),
last_imported_block: 0,
last_imported_hash: H256::new(),
syncing_difficulty: U256::from(0u64),
have_common_block: false,
}
}
/// @returns Synchonization status
pub fn status(&self) -> SyncStatus {
SyncStatus {
state: self.state.clone(),
protocol_version: 63,
start_block_number: self.starting_block,
last_imported_block_number: self.last_imported_block,
highest_block_number: self.highest_block,
blocks_total: (self.last_imported_block - self.starting_block) as usize,
blocks_received: (self.highest_block - self.starting_block) as usize,
}
}
/// Abort all sync activity
pub fn abort(&mut self, io: &mut SyncIo) {
self.restart(io);
self.peers.clear();
}
/// Rest sync. Clear all downloaded data but keep the queue
fn reset(&mut self) {
self.downloading_headers.clear();
self.downloading_bodies.clear();
self.headers.clear();
self.bodies.clear();
for (_, ref mut p) in self.peers.iter_mut() {
p.asking_blocks.clear();
}
self.header_ids.clear();
self.syncing_difficulty = From::from(0u64);
self.state = SyncState::Idle;
}
/// Restart sync
pub fn restart(&mut self, io: &mut SyncIo) {
self.reset();
self.last_imported_block = 0;
self.last_imported_hash = H256::new();
self.starting_block = 0;
self.highest_block = 0;
self.have_common_block = false;
io.chain().clear_queue();
self.starting_block = io.chain().chain_info().best_block_number;
self.state = SyncState::NotSynced;
}
/// Called by peer to report status
fn on_peer_status(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
let peer = PeerInfo {
protocol_version: try!(r.val_at(0)),
network_id: try!(r.val_at(1)),
difficulty: try!(r.val_at(2)),
latest: try!(r.val_at(3)),
genesis: try!(r.val_at(4)),
asking: PeerAsking::Nothing,
asking_blocks: Vec::new(),
};
trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{})", peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest, peer.genesis);
let chain_info = io.chain().chain_info();
if peer.genesis != chain_info.genesis_hash {
io.disable_peer(peer_id);
trace!(target: "sync", "Peer {} genesis hash not matched", peer_id);
return Ok(());
}
if peer.network_id != NETWORK_ID {
io.disable_peer(peer_id);
trace!(target: "sync", "Peer {} network id not matched", peer_id);
return Ok(());
}
let old = self.peers.insert(peer_id.clone(), peer);
if old.is_some() {
panic!("ChainSync: new peer already exists");
}
info!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id));
self.sync_peer(io, peer_id, false);
Ok(())
}
/// Called by peer once it has new block headers during sync
fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
self.reset_peer_asking(peer_id, PeerAsking::BlockHeaders);
let item_count = r.item_count();
trace!(target: "sync", "{} -> BlockHeaders ({} entries)", peer_id, item_count);
self.clear_peer_download(peer_id);
if self.state != SyncState::Blocks && self.state != SyncState::NewBlocks && self.state != SyncState::Waiting {
trace!(target: "sync", "Ignored unexpected block headers");
return Ok(());
}
if self.state == SyncState::Waiting {
trace!(target: "sync", "Ignored block headers while waiting");
return Ok(());
}
for i in 0..item_count {
let info: BlockHeader = try!(r.val_at(i));
let number = BlockNumber::from(info.number);
if number <= self.last_imported_block || self.headers.have_item(&number) {
trace!(target: "sync", "Skipping existing block header");
continue;
}
if number > self.highest_block {
self.highest_block = number;
}
let hash = info.hash();
match io.chain().block_status(&hash) {
BlockStatus::InChain => {
self.have_common_block = true;
self.last_imported_block = number;
self.last_imported_hash = hash.clone();
trace!(target: "sync", "Found common header {} ({})", number, hash);
},
_ => {
if self.have_common_block {
//validate chain
if self.have_common_block && number == self.last_imported_block + 1 && info.parent_hash != self.last_imported_hash {
// TODO: lower peer rating
debug!(target: "sync", "Mismatched block header {} {}", number, hash);
continue;
}
if self.headers.find_item(&(number - 1)).map_or(false, |p| p.hash != info.parent_hash) {
// mismatching parent id, delete the previous block and don't add this one
// TODO: lower peer rating
debug!(target: "sync", "Mismatched block header {} {}", number, hash);
self.remove_downloaded_blocks(number - 1);
continue;
}
if self.headers.find_item(&(number + 1)).map_or(false, |p| p.parent != hash) {
// mismatching parent id for the next block, clear following headers
debug!(target: "sync", "Mismatched block header {}", number + 1);
self.remove_downloaded_blocks(number + 1);
}
}
let hdr = Header {
data: try!(r.at(i)).as_raw().to_vec(),
hash: hash.clone(),
parent: info.parent_hash,
};
self.headers.insert_item(number, hdr);
let header_id = HeaderId {
transactions_root: info.transactions_root,
uncles: info.uncles_hash
};
trace!(target: "sync", "Got header {} ({})", number, hash);
if header_id.transactions_root == rlp::SHA3_NULL_RLP && header_id.uncles == rlp::SHA3_EMPTY_LIST_RLP {
//empty body, just mark as downloaded
let mut body_stream = RlpStream::new_list(2);
body_stream.append_raw(&rlp::NULL_RLP, 1);
body_stream.append_raw(&rlp::EMPTY_LIST_RLP, 1);
self.bodies.insert_item(number, body_stream.out());
}
else {
self.header_ids.insert(header_id, number);
}
}
}
}
self.collect_blocks(io);
self.continue_sync(io);
Ok(())
}
/// Called by peer once it has new block bodies
fn on_peer_block_bodies(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
use util::triehash::ordered_trie_root;
self.reset_peer_asking(peer_id, PeerAsking::BlockBodies);
let item_count = r.item_count();
trace!(target: "sync", "{} -> BlockBodies ({} entries)", peer_id, item_count);
self.clear_peer_download(peer_id);
if self.state != SyncState::Blocks && self.state != SyncState::NewBlocks && self.state != SyncState::Waiting {
trace!(target: "sync", "Ignored unexpected block bodies");
return Ok(());
}
if self.state == SyncState::Waiting {
trace!(target: "sync", "Ignored block bodies while waiting");
return Ok(());
}
for i in 0..item_count {
let body = try!(r.at(i));
let tx = try!(body.at(0));
let tx_root = ordered_trie_root(tx.iter().map(|r| r.as_raw().to_vec()).collect()); //TODO: get rid of vectors here
let uncles = try!(body.at(1)).as_raw().sha3();
let header_id = HeaderId {
transactions_root: tx_root,
uncles: uncles
};
match self.header_ids.get(&header_id).map(|n| *n) {
Some(n) => {
self.header_ids.remove(&header_id);
self.bodies.insert_item(n, body.as_raw().to_vec());
trace!(target: "sync", "Got body {}", n);
}
None => {
debug!(target: "sync", "Ignored unknown block body");
}
}
}
self.collect_blocks(io);
self.continue_sync(io);
Ok(())
}
/// Called by peer once it has new block bodies
fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
let block_rlp = try!(r.at(0));
let header_rlp = try!(block_rlp.at(0));
let h = header_rlp.as_raw().sha3();
trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h);
let header_view = HeaderView::new(header_rlp.as_raw());
// TODO: Decompose block and add to self.headers and self.bodies instead
if header_view.number() == From::from(self.last_imported_block + 1) {
match io.chain().import_block(block_rlp.as_raw()) {
Err(ImportError::AlreadyInChain) => {
trace!(target: "sync", "New block already in chain {:?}", h);
},
Err(ImportError::AlreadyQueued) => {
trace!(target: "sync", "New block already queued {:?}", h);
},
Ok(()) => {
trace!(target: "sync", "New block queued {:?}", h);
},
Err(e) => {
debug!(target: "sync", "Bad new block {:?} : {:?}", h, e);
io.disable_peer(peer_id);
}
};
}
else {
trace!(target: "sync", "New block unknown {:?}", h);
//TODO: handle too many unknown blocks
let difficulty: U256 = try!(r.val_at(1));
let peer_difficulty = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer").difficulty;
if difficulty > peer_difficulty {
trace!(target: "sync", "Received block {:?} with no known parent. Peer needs syncing...", h);
self.sync_peer(io, peer_id, true);
}
}
Ok(())
}
/// Handles NewHashes packet. Initiates headers download for any unknown hashes.
fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
if self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer").asking != PeerAsking::Nothing {
trace!(target: "sync", "Ignoring new hashes since we're already downloading.");
return Ok(());
}
trace!(target: "sync", "{} -> NewHashes ({} entries)", peer_id, r.item_count());
let hashes = r.iter().map(|item| (item.val_at::<H256>(0), item.val_at::<U256>(1)));
let mut max_height: U256 = From::from(0);
for (rh, rd) in hashes {
let h = try!(rh);
let d = try!(rd);
match io.chain().block_status(&h) {
BlockStatus::InChain => {
trace!(target: "sync", "New block hash already in chain {:?}", h);
},
BlockStatus::Queued => {
trace!(target: "sync", "New hash block already queued {:?}", h);
},
BlockStatus::Unknown => {
trace!(target: "sync", "New unknown block hash {:?}", h);
if d > max_height {
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
peer.latest = h.clone();
max_height = d;
}
},
BlockStatus::Bad =>{
debug!(target: "sync", "Bad new block hash {:?}", h);
io.disable_peer(peer_id);
return Ok(());
}
}
};
Ok(())
}
/// Called by peer when it is disconnecting
pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) {
trace!(target: "sync", "== Disconnecting {}", peer);
if self.peers.contains_key(&peer) {
info!(target: "sync", "Disconneced {}:{}", peer, io.peer_info(peer));
self.clear_peer_download(peer);
self.peers.remove(&peer);
self.continue_sync(io);
}
}
/// Called when a new peer is connected
pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) {
trace!(target: "sync", "== Connected {}", peer);
self.send_status(io, peer);
}
/// Resume downloading
fn continue_sync(&mut self, io: &mut SyncIo) {
let mut peers: Vec<(PeerId, U256)> = self.peers.iter().map(|(k, p)| (*k, p.difficulty)).collect();
peers.sort_by(|&(_, d1), &(_, d2)| d1.cmp(&d2).reverse()); //TODO: sort by rating
for (p, _) in peers {
self.sync_peer(io, p, false);
}
}
/// Called after all blocks have been donloaded
fn complete_sync(&mut self) {
trace!(target: "sync", "Sync complete");
self.reset();
self.state = SyncState::Idle;
}
/// Enter waiting state
fn pause_sync(&mut self) {
trace!(target: "sync", "Block queue full, pausing sync");
self.state = SyncState::Waiting;
}
/// Find something to do for a peer. Called for a new peer or when a peer is done with it's task.
fn sync_peer(&mut self, io: &mut SyncIo, peer_id: PeerId, force: bool) {
let (peer_latest, peer_difficulty) = {
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
if peer.asking != PeerAsking::Nothing {
return;
}
if self.state == SyncState::Waiting {
trace!(target: "sync", "Waiting for block queue");
return;
}
(peer.latest.clone(), peer.difficulty.clone())
};
let td = io.chain().chain_info().pending_total_difficulty;
let syncing_difficulty = max(self.syncing_difficulty, td);
if force || peer_difficulty > syncing_difficulty {
// start sync
self.syncing_difficulty = peer_difficulty;
if self.state == SyncState::Idle || self.state == SyncState::NotSynced {
self.state = SyncState::Blocks;
}
trace!(target: "sync", "Starting sync with better chain");
self.request_headers_by_hash(io, peer_id, &peer_latest, 1, 0, false);
}
else if self.state == SyncState::Blocks {
self.request_blocks(io, peer_id);
}
}
/// Find some headers or blocks to download for a peer.
fn request_blocks(&mut self, io: &mut SyncIo, peer_id: PeerId) {
self.clear_peer_download(peer_id);
if io.chain().queue_status().full {
self.pause_sync();
return;
}
// check to see if we need to download any block bodies first
let mut needed_bodies: Vec<H256> = Vec::new();
let mut needed_numbers: Vec<BlockNumber> = Vec::new();
if self.have_common_block && !self.headers.is_empty() && self.headers.range_iter().next().unwrap().0 == self.last_imported_block + 1 {
for (start, ref items) in self.headers.range_iter() {
if needed_bodies.len() > MAX_BODIES_TO_REQUEST {
break;
}
let mut index: BlockNumber = 0;
while index != items.len() as BlockNumber && needed_bodies.len() < MAX_BODIES_TO_REQUEST {
let block = start + index;
if !self.downloading_bodies.contains(&block) && !self.bodies.have_item(&block) {
needed_bodies.push(items[index as usize].hash.clone());
needed_numbers.push(block);
self.downloading_bodies.insert(block);
}
index += 1;
}
}
}
if !needed_bodies.is_empty() {
replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, needed_numbers);
self.request_bodies(io, peer_id, needed_bodies);
}
else {
// check if need to download headers
let mut start = 0usize;
if !self.have_common_block {
// download backwards until common block is found 1 header at a time
let chain_info = io.chain().chain_info();
start = chain_info.best_block_number as usize;
if !self.headers.is_empty() {
start = min(start, self.headers.range_iter().next().unwrap().0 as usize - 1);
}
if start == 0 {
self.have_common_block = true; //reached genesis
self.last_imported_hash = chain_info.genesis_hash;
}
}
if self.have_common_block {
let mut headers: Vec<BlockNumber> = Vec::new();
let mut prev = self.last_imported_block + 1;
for (next, ref items) in self.headers.range_iter() {
if !headers.is_empty() {
break;
}
if next <= prev {
prev = next + items.len() as BlockNumber;
continue;
}
let mut block = prev;
while block < next && headers.len() <= MAX_HEADERS_TO_REQUEST {
if !self.downloading_headers.contains(&(block as BlockNumber)) {
headers.push(block as BlockNumber);
self.downloading_headers.insert(block as BlockNumber);
}
block += 1;
}
prev = next + items.len() as BlockNumber;
}
if !headers.is_empty() {
start = headers[0] as usize;
let count = headers.len();
replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, headers);
assert!(!self.headers.have_item(&(start as BlockNumber)));
self.request_headers_by_number(io, peer_id, start as BlockNumber, count, 0, false);
}
}
else {
self.request_headers_by_number(io, peer_id, start as BlockNumber, 1, 0, false);
}
}
}
/// Clear all blocks/headers marked as being downloaded by a peer.
fn clear_peer_download(&mut self, peer_id: PeerId) {
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
for b in &peer.asking_blocks {
self.downloading_headers.remove(&b);
self.downloading_bodies.remove(&b);
}
peer.asking_blocks.clear();
}
/// Checks if there are blocks fully downloaded that can be imported into the blockchain and does the import.
fn collect_blocks(&mut self, io: &mut SyncIo) {
if !self.have_common_block || self.headers.is_empty() || self.bodies.is_empty() {
return;
}
let mut restart = false;
// merge headers and bodies
{
let headers = self.headers.range_iter().next().unwrap();
let bodies = self.bodies.range_iter().next().unwrap();
if headers.0 != bodies.0 || headers.0 != self.last_imported_block + 1 {
return;
}
let count = min(headers.1.len(), bodies.1.len());
let mut imported = 0;
for i in 0..count {
let mut block_rlp = RlpStream::new_list(3);
block_rlp.append_raw(&headers.1[i].data, 1);
let body = Rlp::new(&bodies.1[i]);
block_rlp.append_raw(body.at(0).as_raw(), 1);
block_rlp.append_raw(body.at(1).as_raw(), 1);
let h = &headers.1[i].hash;
match io.chain().import_block(&block_rlp.out()) {
Err(ImportError::AlreadyInChain) => {
trace!(target: "sync", "Block already in chain {:?}", h);
self.last_imported_block = headers.0 + i as BlockNumber;
self.last_imported_hash = h.clone();
},
Err(ImportError::AlreadyQueued) => {
trace!(target: "sync", "Block already queued {:?}", h);
self.last_imported_block = headers.0 + i as BlockNumber;
self.last_imported_hash = h.clone();
},
Ok(()) => {
trace!(target: "sync", "Block queued {:?}", h);
self.last_imported_block = headers.0 + i as BlockNumber;
self.last_imported_hash = h.clone();
imported += 1;
},
Err(e) => {
debug!(target: "sync", "Bad block {:?} : {:?}", h, e);
restart = true;
}
}
}
trace!(target: "sync", "Imported {} of {}", imported, count);
}
if restart {
self.restart(io);
return;
}
self.headers.remove_head(&(self.last_imported_block + 1));
self.bodies.remove_head(&(self.last_imported_block + 1));
if self.headers.is_empty() {
assert!(self.bodies.is_empty());
self.complete_sync();
}
}
/// Remove downloaded bocks/headers starting from specified number.
/// Used to recover from an error and re-download parts of the chain detected as bad.
fn remove_downloaded_blocks(&mut self, start: BlockNumber) {
for n in self.headers.get_tail(&start) {
match self.headers.find_item(&n) {
Some(ref header_data) => {
let header_to_delete = HeaderView::new(&header_data.data);
let header_id = HeaderId {
transactions_root: header_to_delete.transactions_root(),
uncles: header_to_delete.uncles_hash()
};
self.header_ids.remove(&header_id);
},
None => {}
}
self.downloading_bodies.remove(&n);
self.downloading_headers.remove(&n);
}
self.headers.remove_tail(&start);
self.bodies.remove_tail(&start);
}
/// Request headers from a peer by block hash
fn request_headers_by_hash(&mut self, sync: &mut SyncIo, peer_id: PeerId, h: &H256, count: usize, skip: usize, reverse: bool) {
trace!(target: "sync", "{} <- GetBlockHeaders: {} entries starting from {}", peer_id, count, h);
let mut rlp = RlpStream::new_list(4);
rlp.append(h);
rlp.append(&count);
rlp.append(&skip);
rlp.append(&if reverse {1u32} else {0u32});
self.send_request(sync, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out());
}
/// Request headers from a peer by block number
fn request_headers_by_number(&mut self, sync: &mut SyncIo, peer_id: PeerId, n: BlockNumber, count: usize, skip: usize, reverse: bool) {
let mut rlp = RlpStream::new_list(4);
trace!(target: "sync", "{} <- GetBlockHeaders: {} entries starting from {}", peer_id, count, n);
rlp.append(&n);
rlp.append(&count);
rlp.append(&skip);
rlp.append(&if reverse {1u32} else {0u32});
self.send_request(sync, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out());
}
/// Request block bodies from a peer
fn request_bodies(&mut self, sync: &mut SyncIo, peer_id: PeerId, hashes: Vec<H256>) {
let mut rlp = RlpStream::new_list(hashes.len());
trace!(target: "sync", "{} <- GetBlockBodies: {} entries", peer_id, hashes.len());
for h in hashes {
rlp.append(&h);
}
self.send_request(sync, peer_id, PeerAsking::BlockBodies, GET_BLOCK_BODIES_PACKET, rlp.out());
}
/// Reset peer status after request is complete.
fn reset_peer_asking(&mut self, peer_id: PeerId, asking: PeerAsking) {
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
if peer.asking != asking {
warn!(target:"sync", "Asking {:?} while expected {:?}", peer.asking, asking);
}
else {
peer.asking = PeerAsking::Nothing;
}
}
/// Generic request sender
fn send_request(&mut self, sync: &mut SyncIo, peer_id: PeerId, asking: PeerAsking, packet_id: PacketId, packet: Bytes) {
{
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
if peer.asking != PeerAsking::Nothing {
warn!(target:"sync", "Asking {:?} while requesting {:?}", asking, peer.asking);
}
}
match sync.send(peer_id, packet_id, packet) {
Err(e) => {
warn!(target:"sync", "Error sending request: {:?}", e);
sync.disable_peer(peer_id);
self.on_peer_aborting(sync, peer_id);
}
Ok(_) => {
let mut peer = self.peers.get_mut(&peer_id).unwrap();
peer.asking = asking;
}
}
}
/// Called when peer sends us new transactions
fn on_peer_transactions(&mut self, _io: &mut SyncIo, _peer_id: PeerId, _r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
Ok(())
}
/// Send Status message
fn send_status(&mut self, io: &mut SyncIo, peer_id: PeerId) {
let mut packet = RlpStream::new_list(5);
let chain = io.chain().chain_info();
packet.append(&(PROTOCOL_VERSION as u32));
packet.append(&NETWORK_ID); //TODO: network id
packet.append(&chain.total_difficulty);
packet.append(&chain.best_block_hash);
packet.append(&chain.genesis_hash);
//TODO: handle timeout for status request
match io.send(peer_id, STATUS_PACKET, packet.out()) {
Err(e) => {
warn!(target:"sync", "Error sending status request: {:?}", e);
io.disable_peer(peer_id);
}
Ok(_) => ()
}
}
/// Respond to GetBlockHeaders request
fn return_block_headers(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
// Packet layout:
// [ block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ]
let max_headers: usize = try!(r.val_at(1));
let skip: usize = try!(r.val_at(2));
let reverse: bool = try!(r.val_at(3));
let last = io.chain().chain_info().best_block_number;
let mut number = if try!(r.at(0)).size() == 32 {
// id is a hash
let hash: H256 = try!(r.val_at(0));
trace!(target: "sync", "-> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", hash, max_headers, skip, reverse);
match io.chain().block_header(&hash) {
Some(hdr) => From::from(HeaderView::new(&hdr).number()),
None => last
}
}
else {
trace!(target: "sync", "-> GetBlockHeaders (number: {}, max: {}, skip: {}, reverse:{})", try!(r.val_at::<BlockNumber>(0)), max_headers, skip, reverse);
try!(r.val_at(0))
};
if reverse {
number = min(last, number);
} else {
number = max(1, number);
}
let max_count = min(MAX_HEADERS_TO_SEND, max_headers);
let mut count = 0;
let mut data = Bytes::new();
let inc = (skip + 1) as BlockNumber;
while number <= last && number > 0 && count < max_count {
match io.chain().block_header_at(number) {
Some(mut hdr) => {
data.append(&mut hdr);
count += 1;
}
None => {}
}
if reverse {
if number <= inc {
break;
}
number -= inc;
}
else {
number += inc;
}
}
let mut rlp = RlpStream::new_list(count as usize);
rlp.append_raw(&data, count as usize);
io.respond(BLOCK_HEADERS_PACKET, rlp.out()).unwrap_or_else(|e|
debug!(target: "sync", "Error sending headers: {:?}", e));
trace!(target: "sync", "-> GetBlockHeaders: returned {} entries", count);
Ok(())
}
/// Respond to GetBlockBodies request
fn return_block_bodies(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
let mut count = r.item_count();
if count == 0 {
debug!(target: "sync", "Empty GetBlockBodies request, ignoring.");
return Ok(());
}
trace!(target: "sync", "-> GetBlockBodies: {} entries", count);
count = min(count, MAX_BODIES_TO_SEND);
let mut added = 0usize;
let mut data = Bytes::new();
for i in 0..count {
match io.chain().block_body(&try!(r.val_at::<H256>(i))) {
Some(mut hdr) => {
data.append(&mut hdr);
added += 1;
}
None => {}
}
}
let mut rlp = RlpStream::new_list(added);
rlp.append_raw(&data, added);
io.respond(BLOCK_BODIES_PACKET, rlp.out()).unwrap_or_else(|e|
debug!(target: "sync", "Error sending headers: {:?}", e));
trace!(target: "sync", "-> GetBlockBodies: returned {} entries", added);
Ok(())
}
/// Respond to GetNodeData request
fn return_node_data(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
let mut count = r.item_count();
if count == 0 {
debug!(target: "sync", "Empty GetNodeData request, ignoring.");
return Ok(());
}
count = min(count, MAX_NODE_DATA_TO_SEND);
let mut added = 0usize;
let mut data = Bytes::new();
for i in 0..count {
match io.chain().state_data(&try!(r.val_at::<H256>(i))) {
Some(mut hdr) => {
data.append(&mut hdr);
added += 1;
}
None => {}
}
}
let mut rlp = RlpStream::new_list(added);
rlp.append_raw(&data, added);
io.respond(NODE_DATA_PACKET, rlp.out()).unwrap_or_else(|e|
debug!(target: "sync", "Error sending headers: {:?}", e));
Ok(())
}
/// Respond to GetReceipts request
fn return_receipts(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
let mut count = r.item_count();
if count == 0 {
debug!(target: "sync", "Empty GetReceipts request, ignoring.");
return Ok(());
}
count = min(count, MAX_RECEIPTS_TO_SEND);
let mut added = 0usize;
let mut data = Bytes::new();
for i in 0..count {
match io.chain().block_receipts(&try!(r.val_at::<H256>(i))) {
Some(mut hdr) => {
data.append(&mut hdr);
added += 1;
}
None => {}
}
}
let mut rlp = RlpStream::new_list(added);
rlp.append_raw(&data, added);
io.respond(RECEIPTS_PACKET, rlp.out()).unwrap_or_else(|e|
debug!(target: "sync", "Error sending headers: {:?}", e));
Ok(())
}
/// Dispatch incoming requests and responses
pub fn on_packet(&mut self, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) {
let rlp = UntrustedRlp::new(data);
let result = match packet_id {
STATUS_PACKET => self.on_peer_status(io, peer, &rlp),
TRANSACTIONS_PACKET => self.on_peer_transactions(io, peer, &rlp),
GET_BLOCK_HEADERS_PACKET => self.return_block_headers(io, &rlp),
BLOCK_HEADERS_PACKET => self.on_peer_block_headers(io, peer, &rlp),
GET_BLOCK_BODIES_PACKET => self.return_block_bodies(io, &rlp),
BLOCK_BODIES_PACKET => self.on_peer_block_bodies(io, peer, &rlp),
NEW_BLOCK_PACKET => self.on_peer_new_block(io, peer, &rlp),
NEW_BLOCK_HASHES_PACKET => self.on_peer_new_hashes(io, peer, &rlp),
GET_NODE_DATA_PACKET => self.return_node_data(io, &rlp),
GET_RECEIPTS_PACKET => self.return_receipts(io, &rlp),
_ => {
debug!(target: "sync", "Unknown packet {}", packet_id);
Ok(())
}
};
result.unwrap_or_else(|e| {
debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e);
})
}
/// Maintain other peers. Send out any new blocks and transactions
pub fn maintain_sync(&mut self, _io: &mut SyncIo) {
}
}

62
src/sync/io.rs Normal file
View File

@@ -0,0 +1,62 @@
use client::BlockChainClient;
use util::{NetworkContext, PeerId, PacketId,};
use util::error::UtilError;
use sync::SyncMessage;
/// IO interface for the syning handler.
/// Provides peer connection management and an interface to the blockchain client.
// TODO: ratings
pub trait SyncIo {
/// Disable a peer
fn disable_peer(&mut self, peer_id: PeerId);
/// Respond to current request with a packet. Can be called from an IO handler for incoming packet.
fn respond(&mut self, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError>;
/// Send a packet to a peer.
fn send(&mut self, peer_id: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError>;
/// Get the blockchain
fn chain<'s>(&'s mut self) -> &'s mut BlockChainClient;
/// Returns peer client identifier string
fn peer_info(&self, peer_id: PeerId) -> String {
peer_id.to_string()
}
}
/// Wraps `NetworkContext` and the blockchain client
pub struct NetSyncIo<'s, 'h, 'io> where 'h: 's, 'io: 'h {
network: &'s mut NetworkContext<'h, 'io, SyncMessage>,
chain: &'s mut BlockChainClient
}
impl<'s, 'h, 'io> NetSyncIo<'s, 'h, 'io> {
/// Creates a new instance from the `NetworkContext` and the blockchain client reference.
pub fn new(network: &'s mut NetworkContext<'h, 'io, SyncMessage>, chain: &'s mut BlockChainClient) -> NetSyncIo<'s,'h,'io> {
NetSyncIo {
network: network,
chain: chain,
}
}
}
impl<'s, 'h, 'op> SyncIo for NetSyncIo<'s, 'h, 'op> {
fn disable_peer(&mut self, peer_id: PeerId) {
self.network.disable_peer(peer_id);
}
fn respond(&mut self, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError>{
self.network.respond(packet_id, data)
}
fn send(&mut self, peer_id: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError>{
self.network.send(peer_id, packet_id, data)
}
fn chain<'a>(&'a mut self) -> &'a mut BlockChainClient {
self.chain
}
fn peer_info(&self, peer_id: PeerId) -> String {
self.network.peer_info(peer_id)
}
}

113
src/sync/mod.rs Normal file
View File

@@ -0,0 +1,113 @@
/// Blockchain sync module
/// Implements ethereum protocol version 63 as specified here:
/// https://github.com/ethereum/wiki/wiki/Ethereum-Wire-Protocol
///
/// Usage example:
///
/// ```rust
/// extern crate ethcore_util as util;
/// extern crate ethcore;
/// use std::env;
/// use std::sync::Arc;
/// use util::network::NetworkService;
/// use ethcore::client::Client;
/// use ethcore::sync::EthSync;
/// use ethcore::ethereum;
///
/// fn main() {
/// let mut service = NetworkService::start().unwrap();
/// let dir = env::temp_dir();
/// let client = Arc::new(Client::new(ethereum::new_frontier(), &dir).unwrap());
/// EthSync::register(&mut service, client);
/// }
/// ```
use std::ops::*;
use std::sync::*;
use client::Client;
use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId, NetworkIoMessage};
use util::TimerToken;
use util::Bytes;
use sync::chain::ChainSync;
use sync::io::NetSyncIo;
mod chain;
mod io;
mod range_collection;
#[cfg(test)]
mod tests;
/// Message type for external events
pub enum SyncMessage {
/// New block has been imported into the blockchain
NewChainBlock(Bytes),
/// A block is ready
BlockVerified(Bytes),
}
pub type NetSyncMessage = NetworkIoMessage<SyncMessage>;
/// Ethereum network protocol handler
pub struct EthSync {
/// Shared blockchain client. TODO: this should evetually become an IPC endpoint
chain: Arc<RwLock<Client>>,
/// Sync strategy
sync: ChainSync
}
pub use self::chain::SyncStatus;
impl EthSync {
/// Creates and register protocol with the network service
pub fn register(service: &mut NetworkService<SyncMessage>, chain: Arc<RwLock<Client>>) {
let sync = Box::new(EthSync {
chain: chain,
sync: ChainSync::new(),
});
service.register_protocol(sync, "eth", &[62u8, 63u8]).expect("Error registering eth protocol handler");
}
/// Get sync status
pub fn status(&self) -> SyncStatus {
self.sync.status()
}
/// Stop sync
pub fn stop(&mut self, io: &mut NetworkContext<SyncMessage>) {
self.sync.abort(&mut NetSyncIo::new(io, self.chain.write().unwrap().deref_mut()));
}
/// Restart sync
pub fn restart(&mut self, io: &mut NetworkContext<SyncMessage>) {
self.sync.restart(&mut NetSyncIo::new(io, self.chain.write().unwrap().deref_mut()));
}
}
impl NetworkProtocolHandler<SyncMessage> for EthSync {
fn initialize(&mut self, io: &mut NetworkContext<SyncMessage>) {
self.sync.restart(&mut NetSyncIo::new(io, self.chain.write().unwrap().deref_mut()));
io.register_timer(1000).unwrap();
}
fn read(&mut self, io: &mut NetworkContext<SyncMessage>, peer: &PeerId, packet_id: u8, data: &[u8]) {
self.sync.on_packet(&mut NetSyncIo::new(io, self.chain.write().unwrap().deref_mut()) , *peer, packet_id, data);
}
fn connected(&mut self, io: &mut NetworkContext<SyncMessage>, peer: &PeerId) {
self.sync.on_peer_connected(&mut NetSyncIo::new(io, self.chain.write().unwrap().deref_mut()), *peer);
}
fn disconnected(&mut self, io: &mut NetworkContext<SyncMessage>, peer: &PeerId) {
self.sync.on_peer_aborting(&mut NetSyncIo::new(io, self.chain.write().unwrap().deref_mut()), *peer);
}
fn timeout(&mut self, io: &mut NetworkContext<SyncMessage>, _timer: TimerToken) {
self.sync.maintain_sync(&mut NetSyncIo::new(io, self.chain.write().unwrap().deref_mut()));
}
fn message(&mut self, _io: &mut NetworkContext<SyncMessage>, _message: &SyncMessage) {
}
}

View File

@@ -0,0 +1,259 @@
/// This module defines a trait for a collection of ranged values and an implementation
/// for this trait over sorted vector.
use std::ops::{Add, Sub, Range};
pub trait ToUsize {
fn to_usize(&self) -> usize;
}
pub trait FromUsize {
fn from_usize(s: usize) -> Self;
}
/// A key-value collection orderd by key with sequential key-value pairs grouped together.
/// Such group is called a range.
/// E.g. a set of collection of 5 pairs {1, a}, {2, b}, {10, x}, {11, y}, {12, z} will be grouped into two ranges: {1, [a,b]}, {10, [x,y,z]}
pub trait RangeCollection<K, V> {
/// Check if the given key is present in the collection.
fn have_item(&self, key: &K) -> bool;
/// Get value by key.
fn find_item(&self, key: &K) -> Option<&V>;
/// Get a range of keys from `key` till the end of the range that has `key`
/// Returns an empty range is key does not exist.
fn get_tail(&mut self, key: &K) -> Range<K>;
/// Remove all elements < `start` in the range that contains `start` - 1
fn remove_head(&mut self, start: &K);
/// Remove all elements >= `start` in the range that contains `start`
fn remove_tail(&mut self, start: &K);
/// Remove all elements >= `tail`
fn insert_item(&mut self, key: K, value: V);
/// Get an iterator over ranges
fn range_iter<'c>(&'c self) -> RangeIterator<'c, K, V>;
}
/// Range iterator. For each range yelds a key for the first element of the range and a vector of values.
pub struct RangeIterator<'c, K:'c, V:'c> {
range: usize,
collection: &'c Vec<(K, Vec<V>)>
}
impl<'c, K:'c, V:'c> Iterator for RangeIterator<'c, K, V> where K: Add<Output = K> + FromUsize + ToUsize + Copy {
type Item = (K, &'c [V]);
// The 'Iterator' trait only requires the 'next' method to be defined. The
// return type is 'Option<T>', 'None' is returned when the 'Iterator' is
// over, otherwise the next value is returned wrapped in 'Some'
fn next(&mut self) -> Option<(K, &'c [V])> {
if self.range > 0 {
self.range -= 1;
}
else {
return None;
}
match self.collection.get(self.range) {
Some(&(ref k, ref vec)) => {
Some((*k, &vec))
},
None => None
}
}
}
impl<K, V> RangeCollection<K, V> for Vec<(K, Vec<V>)> where K: Ord + PartialEq + Add<Output = K> + Sub<Output = K> + Copy + FromUsize + ToUsize {
fn range_iter<'c>(&'c self) -> RangeIterator<'c, K, V> {
RangeIterator {
range: self.len(),
collection: self
}
}
fn have_item(&self, key: &K) -> bool {
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(_) => true,
Err(index) => match self.get(index) {
Some(&(ref k, ref v)) => k <= key && (*k + FromUsize::from_usize(v.len())) > *key,
_ => false
},
}
}
fn find_item(&self, key: &K) -> Option<&V> {
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(index) => self.get(index).unwrap().1.get(0),
Err(index) => match self.get(index) {
Some(&(ref k, ref v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => v.get((*key - *k).to_usize()),
_ => None
},
}
}
fn get_tail(&mut self, key: &K) -> Range<K> {
let kv = *key;
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(index) => kv..(kv + FromUsize::from_usize(self[index].1.len())),
Err(index) => {
match self.get_mut(index) {
Some(&mut (ref k, ref mut v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => {
kv..(*k + FromUsize::from_usize(v.len()))
}
_ => kv..kv
}
},
}
}
/// Remove element key and following elements in the same range
fn remove_tail(&mut self, key: &K) {
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(index) => { self.remove(index); },
Err(index) =>{
let mut empty = false;
match self.get_mut(index) {
Some(&mut (ref k, ref mut v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => {
v.truncate((*key - *k).to_usize());
empty = v.is_empty();
}
_ => {}
}
if empty {
self.remove(index);
}
},
}
}
/// Remove range elements up to key
fn remove_head(&mut self, key: &K) {
if *key == FromUsize::from_usize(0) {
return
}
let prev = *key - FromUsize::from_usize(1);
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(_) => { }, //start of range, do nothing.
Err(index) => {
let mut empty = false;
match self.get_mut(index) {
Some(&mut (ref mut k, ref mut v)) if *k <= prev && (*k + FromUsize::from_usize(v.len())) > prev => {
let tail = v.split_off((*key - *k).to_usize());
empty = tail.is_empty();
let removed = ::std::mem::replace(v, tail);
let new_k = *k + FromUsize::from_usize(removed.len());
::std::mem::replace(k, new_k);
}
_ => {}
}
if empty {
self.remove(index);
}
},
}
}
fn insert_item(&mut self, key: K, value: V) {
assert!(!self.have_item(&key));
let lower = match self.binary_search_by(|&(k, _)| k.cmp(&key).reverse()) {
Ok(index) => index,
Err(index) => index,
};
let mut to_remove: Option<usize> = None;
if lower < self.len() && self[lower].0 + FromUsize::from_usize(self[lower].1.len()) == key {
// extend into existing chunk
self[lower].1.push(value);
}
else {
// insert a new chunk
let range: Vec<V> = vec![value];
self.insert(lower, (key, range));
};
if lower > 0 {
let next = lower - 1;
if next < self.len()
{
{
let (mut next, mut inserted) = self.split_at_mut(lower);
let mut next = next.last_mut().unwrap();
let mut inserted = inserted.first_mut().unwrap();
if next.0 == key + FromUsize::from_usize(1)
{
inserted.1.append(&mut next.1);
to_remove = Some(lower - 1);
}
}
if let Some(r) = to_remove {
self.remove(r);
}
}
}
}
}
#[test]
fn test_range() {
use std::cmp::{Ordering};
let mut ranges: Vec<(u64, Vec<char>)> = Vec::new();
assert_eq!(ranges.range_iter().next(), None);
assert_eq!(ranges.find_item(&1), None);
assert!(!ranges.have_item(&1));
assert_eq!(ranges.get_tail(&0), 0..0);
ranges.insert_item(17, 'q');
assert_eq!(ranges.range_iter().cmp(vec![(17, &['q'][..])]), Ordering::Equal);
assert_eq!(ranges.find_item(&17), Some(&'q'));
assert!(ranges.have_item(&17));
assert_eq!(ranges.get_tail(&17), 17..18);
ranges.insert_item(18, 'r');
assert_eq!(ranges.range_iter().cmp(vec![(17, &['q', 'r'][..])]), Ordering::Equal);
assert_eq!(ranges.find_item(&18), Some(&'r'));
assert!(ranges.have_item(&18));
assert_eq!(ranges.get_tail(&17), 17..19);
ranges.insert_item(16, 'p');
assert_eq!(ranges.range_iter().cmp(vec![(16, &['p', 'q', 'r'][..])]), Ordering::Equal);
assert_eq!(ranges.find_item(&16), Some(&'p'));
assert_eq!(ranges.find_item(&17), Some(&'q'));
assert_eq!(ranges.find_item(&18), Some(&'r'));
assert!(ranges.have_item(&16));
assert_eq!(ranges.get_tail(&17), 17..19);
assert_eq!(ranges.get_tail(&16), 16..19);
ranges.insert_item(2, 'b');
assert_eq!(ranges.range_iter().cmp(vec![(2, &['b'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
assert_eq!(ranges.find_item(&2), Some(&'b'));
ranges.insert_item(3, 'c');
ranges.insert_item(4, 'd');
assert_eq!(ranges.get_tail(&3), 3..5);
assert_eq!(ranges.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
let mut r = ranges.clone();
r.remove_head(&1);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&2);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&3);
assert_eq!(r.range_iter().cmp(vec![(3, &['c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&10);
assert_eq!(r.range_iter().cmp(vec![(3, &['c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&5);
assert_eq!(r.range_iter().cmp(vec![(16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&19);
assert_eq!(r.range_iter().next(), None);
let mut r = ranges.clone();
r.remove_tail(&20);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_tail(&17);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p'][..])]), Ordering::Equal);
r.remove_tail(&16);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..])]), Ordering::Equal);
r.remove_tail(&3);
assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal);
r.remove_tail(&2);
assert_eq!(r.range_iter().next(), None);
}

337
src/sync/tests.rs Normal file
View File

@@ -0,0 +1,337 @@
use util::*;
use client::{BlockChainClient, BlockStatus, TreeRoute, BlockQueueStatus, BlockChainInfo};
use header::{Header as BlockHeader, BlockNumber};
use error::*;
use sync::io::SyncIo;
use sync::chain::ChainSync;
struct TestBlockChainClient {
blocks: HashMap<H256, Bytes>,
numbers: HashMap<usize, H256>,
genesis_hash: H256,
last_hash: H256,
difficulty: U256
}
impl TestBlockChainClient {
fn new() -> TestBlockChainClient {
let mut client = TestBlockChainClient {
blocks: HashMap::new(),
numbers: HashMap::new(),
genesis_hash: H256::new(),
last_hash: H256::new(),
difficulty: From::from(0),
};
client.add_blocks(1, true); // add genesis block
client.genesis_hash = client.last_hash.clone();
client
}
pub fn add_blocks(&mut self, count: usize, empty: bool) {
for n in self.numbers.len()..(self.numbers.len() + count) {
let mut header = BlockHeader::new();
header.difficulty = From::from(n);
header.parent_hash = self.last_hash.clone();
header.number = n as BlockNumber;
let mut uncles = RlpStream::new_list(if empty {0} else {1});
if !empty {
uncles.append(&H256::from(&U256::from(n)));
header.uncles_hash = uncles.as_raw().sha3();
}
let mut rlp = RlpStream::new_list(3);
rlp.append(&header);
rlp.append_raw(&rlp::NULL_RLP, 1);
rlp.append_raw(uncles.as_raw(), 1);
self.import_block(rlp.as_raw()).unwrap();
}
}
}
impl BlockChainClient for TestBlockChainClient {
fn block_header(&self, h: &H256) -> Option<Bytes> {
self.blocks.get(h).map(|r| Rlp::new(r).at(0).as_raw().to_vec())
}
fn block_body(&self, h: &H256) -> Option<Bytes> {
self.blocks.get(h).map(|r| {
let mut stream = RlpStream::new_list(2);
stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1);
stream.append_raw(Rlp::new(&r).at(2).as_raw(), 1);
stream.out()
})
}
fn block(&self, h: &H256) -> Option<Bytes> {
self.blocks.get(h).map(|b| b.clone())
}
fn block_status(&self, h: &H256) -> BlockStatus {
match self.blocks.get(h) {
Some(_) => BlockStatus::InChain,
None => BlockStatus::Unknown
}
}
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes> {
self.numbers.get(&(n as usize)).and_then(|h| self.block_header(h))
}
fn block_body_at(&self, n: BlockNumber) -> Option<Bytes> {
self.numbers.get(&(n as usize)).and_then(|h| self.block_body(h))
}
fn block_at(&self, n: BlockNumber) -> Option<Bytes> {
self.numbers.get(&(n as usize)).map(|h| self.blocks.get(h).unwrap().clone())
}
fn block_status_at(&self, n: BlockNumber) -> BlockStatus {
if (n as usize) < self.blocks.len() {
BlockStatus::InChain
} else {
BlockStatus::Unknown
}
}
fn tree_route(&self, _from: &H256, _to: &H256) -> Option<TreeRoute> {
Some(TreeRoute {
blocks: Vec::new(),
ancestor: H256::new(),
index: 0
})
}
fn state_data(&self, _h: &H256) -> Option<Bytes> {
None
}
fn block_receipts(&self, _h: &H256) -> Option<Bytes> {
None
}
fn import_block(&mut self, b: &[u8]) -> ImportResult {
let header = Rlp::new(&b).val_at::<BlockHeader>(0);
let number: usize = header.number as usize;
if number > self.blocks.len() {
panic!("Unexpected block number. Expected {}, got {}", self.blocks.len(), number);
}
if number > 0 {
match self.blocks.get(&header.parent_hash) {
Some(parent) => {
let parent = Rlp::new(parent).val_at::<BlockHeader>(0);
if parent.number != (header.number - 1) {
panic!("Unexpected block parent");
}
},
None => {
panic!("Unknown block parent {:?} for block {}", header.parent_hash, number);
}
}
}
if number == self.numbers.len() {
self.difficulty = self.difficulty + header.difficulty;
self.last_hash = header.hash();
self.blocks.insert(header.hash(), b.to_vec());
self.numbers.insert(number, header.hash());
let mut parent_hash = header.parent_hash;
if number > 0 {
let mut n = number - 1;
while n > 0 && self.numbers[&n] != parent_hash {
*self.numbers.get_mut(&n).unwrap() = parent_hash.clone();
n -= 1;
parent_hash = Rlp::new(&self.blocks[&parent_hash]).val_at::<BlockHeader>(0).parent_hash;
}
}
}
else {
self.blocks.insert(header.hash(), b.to_vec());
}
Ok(())
}
fn queue_status(&self) -> BlockQueueStatus {
BlockQueueStatus {
full: false,
}
}
fn clear_queue(&mut self) {
}
fn chain_info(&self) -> BlockChainInfo {
BlockChainInfo {
total_difficulty: self.difficulty,
pending_total_difficulty: self.difficulty,
genesis_hash: self.genesis_hash.clone(),
best_block_hash: self.last_hash.clone(),
best_block_number: self.blocks.len() as BlockNumber - 1,
}
}
}
struct TestIo<'p> {
chain: &'p mut TestBlockChainClient,
queue: &'p mut VecDeque<TestPacket>,
sender: Option<PeerId>,
}
impl<'p> TestIo<'p> {
fn new(chain: &'p mut TestBlockChainClient, queue: &'p mut VecDeque<TestPacket>, sender: Option<PeerId>) -> TestIo<'p> {
TestIo {
chain: chain,
queue: queue,
sender: sender
}
}
}
impl<'p> SyncIo for TestIo<'p> {
fn disable_peer(&mut self, _peer_id: PeerId) {
}
fn respond(&mut self, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError> {
self.queue.push_back(TestPacket {
data: data,
packet_id: packet_id,
recipient: self.sender.unwrap()
});
Ok(())
}
fn send(&mut self, peer_id: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError> {
self.queue.push_back(TestPacket {
data: data,
packet_id: packet_id,
recipient: peer_id,
});
Ok(())
}
fn chain<'a>(&'a mut self) -> &'a mut BlockChainClient {
self.chain
}
}
struct TestPacket {
data: Bytes,
packet_id: PacketId,
recipient: PeerId,
}
struct TestPeer {
chain: TestBlockChainClient,
sync: ChainSync,
queue: VecDeque<TestPacket>,
}
struct TestNet {
peers: Vec<TestPeer>
}
impl TestNet {
pub fn new(n: usize) -> TestNet {
let mut net = TestNet {
peers: Vec::new(),
};
for _ in 0..n {
net.peers.push(TestPeer {
chain: TestBlockChainClient::new(),
sync: ChainSync::new(),
queue: VecDeque::new(),
});
}
net
}
pub fn peer(&self, i: usize) -> &TestPeer {
self.peers.get(i).unwrap()
}
pub fn peer_mut(&mut self, i: usize) -> &mut TestPeer {
self.peers.get_mut(i).unwrap()
}
pub fn start(&mut self) {
for peer in 0..self.peers.len() {
for client in 0..self.peers.len() {
if peer != client {
let mut p = self.peers.get_mut(peer).unwrap();
p.sync.on_peer_connected(&mut TestIo::new(&mut p.chain, &mut p.queue, Some(client as PeerId)), client as PeerId);
}
}
}
}
pub fn sync_step(&mut self) {
for peer in 0..self.peers.len() {
match self.peers[peer].queue.pop_front() {
Some(packet) => {
let mut p = self.peers.get_mut(packet.recipient).unwrap();
trace!("--- {} -> {} ---", peer, packet.recipient);
p.sync.on_packet(&mut TestIo::new(&mut p.chain, &mut p.queue, Some(peer as PeerId)), peer as PeerId, packet.packet_id, &packet.data);
trace!("----------------");
},
None => {}
}
let mut p = self.peers.get_mut(peer).unwrap();
p.sync.maintain_sync(&mut TestIo::new(&mut p.chain, &mut p.queue, None));
}
}
pub fn sync(&mut self) {
self.start();
while !self.done() {
self.sync_step()
}
}
pub fn done(&self) -> bool {
self.peers.iter().all(|p| p.queue.is_empty())
}
}
#[test]
fn full_sync_two_peers() {
::env_logger::init().ok();
let mut net = TestNet::new(3);
net.peer_mut(1).chain.add_blocks(1000, false);
net.peer_mut(2).chain.add_blocks(1000, false);
net.sync();
assert!(net.peer(0).chain.block_at(1000).is_some());
assert_eq!(net.peer(0).chain.blocks, net.peer(1).chain.blocks);
}
#[test]
fn full_sync_empty_blocks() {
::env_logger::init().ok();
let mut net = TestNet::new(3);
for n in 0..200 {
net.peer_mut(1).chain.add_blocks(5, n % 2 == 0);
net.peer_mut(2).chain.add_blocks(5, n % 2 == 0);
}
net.sync();
assert!(net.peer(0).chain.block_at(1000).is_some());
assert_eq!(net.peer(0).chain.blocks, net.peer(1).chain.blocks);
}
#[test]
fn forked_sync() {
::env_logger::init().ok();
let mut net = TestNet::new(3);
net.peer_mut(0).chain.add_blocks(300, false);
net.peer_mut(1).chain.add_blocks(300, false);
net.peer_mut(2).chain.add_blocks(300, false);
net.peer_mut(0).chain.add_blocks(100, true); //fork
net.peer_mut(1).chain.add_blocks(200, false);
net.peer_mut(2).chain.add_blocks(200, false);
net.peer_mut(1).chain.add_blocks(100, false); //fork between 1 and 2
net.peer_mut(2).chain.add_blocks(10, true);
// peer 1 has the best chain of 601 blocks
let peer1_chain = net.peer(1).chain.numbers.clone();
net.sync();
assert_eq!(net.peer(0).chain.numbers, peer1_chain);
assert_eq!(net.peer(1).chain.numbers, peer1_chain);
assert_eq!(net.peer(2).chain.numbers, peer1_chain);
}

290
src/tests/executive.rs Normal file
View File

@@ -0,0 +1,290 @@
use super::test_common::*;
use state::*;
use executive::*;
use spec::*;
use engine::*;
use evm;
use evm::{Schedule, Ext, Factory, VMType, ContractCreateResult, MessageCallResult};
use ethereum;
use externalities::*;
use substate::*;
struct TestEngine {
vm_factory: Factory,
spec: Spec,
max_depth: usize
}
impl TestEngine {
fn new(max_depth: usize, vm_type: VMType) -> TestEngine {
TestEngine {
vm_factory: Factory::new(vm_type),
spec: ethereum::new_frontier_test(),
max_depth: max_depth
}
}
}
impl Engine for TestEngine {
fn name(&self) -> &str { "TestEngine" }
fn spec(&self) -> &Spec { &self.spec }
fn vm_factory(&self) -> &Factory { &self.vm_factory }
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
let mut schedule = Schedule::new_frontier();
schedule.max_depth = self.max_depth;
schedule
}
}
struct CallCreate {
data: Bytes,
destination: Option<Address>,
gas_limit: U256,
value: U256
}
/// Tiny wrapper around executive externalities.
/// Stores callcreates.
struct TestExt<'a> {
ext: Externalities<'a>,
callcreates: Vec<CallCreate>,
contract_address: Address
}
impl<'a> TestExt<'a> {
fn new(state: &'a mut State,
info: &'a EnvInfo,
engine: &'a Engine,
depth: usize,
origin_info: OriginInfo,
substate: &'a mut Substate,
output: OutputPolicy<'a>,
address: Address) -> Self {
TestExt {
contract_address: contract_address(&address, &state.nonce(&address)),
ext: Externalities::new(state, info, engine, depth, origin_info, substate, output),
callcreates: vec![]
}
}
}
impl<'a> Ext for TestExt<'a> {
fn storage_at(&self, key: &H256) -> H256 {
self.ext.storage_at(key)
}
fn set_storage(&mut self, key: H256, value: H256) {
self.ext.set_storage(key, value)
}
fn exists(&self, address: &Address) -> bool {
self.ext.exists(address)
}
fn balance(&self, address: &Address) -> U256 {
self.ext.balance(address)
}
fn blockhash(&self, number: &U256) -> H256 {
self.ext.blockhash(number)
}
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult {
self.callcreates.push(CallCreate {
data: code.to_vec(),
destination: None,
gas_limit: *gas,
value: *value
});
ContractCreateResult::Created(self.contract_address.clone(), *gas)
}
fn call(&mut self,
gas: &U256,
receive_address: &Address,
value: &U256,
data: &[u8],
_code_address: &Address,
_output: &mut [u8]) -> MessageCallResult {
self.callcreates.push(CallCreate {
data: data.to_vec(),
destination: Some(receive_address.clone()),
gas_limit: *gas,
value: *value
});
MessageCallResult::Success(*gas)
}
fn extcode(&self, address: &Address) -> Bytes {
self.ext.extcode(address)
}
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
self.ext.log(topics, data)
}
fn ret(&mut self, gas: &U256, data: &[u8]) -> Result<U256, evm::Error> {
self.ext.ret(gas, data)
}
fn suicide(&mut self, refund_address: &Address) {
self.ext.suicide(refund_address)
}
fn schedule(&self) -> &Schedule {
self.ext.schedule()
}
fn env_info(&self) -> &EnvInfo {
self.ext.env_info()
}
fn depth(&self) -> usize {
0
}
fn inc_sstore_clears(&mut self) {
self.ext.inc_sstore_clears()
}
}
fn do_json_test(json_data: &[u8]) -> Vec<String> {
let vms = VMType::all();
vms
.iter()
.flat_map(|vm| do_json_test_for(vm, json_data))
.collect()
}
fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
let mut failed = Vec::new();
for (name, test) in json.as_object().unwrap() {
println!("name: {:?}", name);
// sync io is usefull when something crashes in jit
// ::std::io::stdout().write(&name.as_bytes());
// ::std::io::stdout().write(b"\n");
// ::std::io::stdout().flush();
let mut fail = false;
//let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.to_string()); fail = true };
let mut fail_unless = |cond: bool, s: &str | if !cond && !fail {
failed.push(format!("[{}] {}: {}", vm, name.to_string(), s));
fail = true
};
// test env
let mut state = State::new_temp();
test.find("pre").map(|pre| for (addr, s) in pre.as_object().unwrap() {
let address = Address::from(addr.as_ref());
let balance = xjson!(&s["balance"]);
let code = xjson!(&s["code"]);
let _nonce: U256 = xjson!(&s["nonce"]);
state.new_contract(&address);
state.add_balance(&address, &balance);
state.init_code(&address, code);
BTreeMap::from_json(&s["storage"]).into_iter().foreach(|(k, v)| state.set_storage(&address, k, v));
});
let mut info = EnvInfo::new();
test.find("env").map(|env| {
info.author = xjson!(&env["currentCoinbase"]);
info.difficulty = xjson!(&env["currentDifficulty"]);
info.gas_limit = xjson!(&env["currentGasLimit"]);
info.number = xjson!(&env["currentNumber"]);
info.timestamp = xjson!(&env["currentTimestamp"]);
});
let engine = TestEngine::new(1, vm.clone());
// params
let mut params = ActionParams::new();
test.find("exec").map(|exec| {
params.address = xjson!(&exec["address"]);
params.sender = xjson!(&exec["caller"]);
params.origin = xjson!(&exec["origin"]);
params.code = xjson!(&exec["code"]);
params.data = xjson!(&exec["data"]);
params.gas = xjson!(&exec["gas"]);
params.gas_price = xjson!(&exec["gasPrice"]);
params.value = xjson!(&exec["value"]);
});
let out_of_gas = test.find("callcreates").map(|_calls| {
}).is_none();
let mut substate = Substate::new();
let mut output = vec![];
// execute
let (res, callcreates) = {
let mut ex = TestExt::new(&mut state,
&info,
&engine,
0,
OriginInfo::from(&params),
&mut substate,
OutputPolicy::Return(BytesRef::Flexible(&mut output)),
params.address.clone());
let evm = engine.vm_factory().create();
let res = evm.exec(params, &mut ex);
(res, ex.callcreates)
};
// then validate
match res {
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
Ok(gas_left) => {
// println!("name: {}, gas_left : {:?}", name, gas_left);
fail_unless(!out_of_gas, "expected to run out of gas.");
fail_unless(gas_left == xjson!(&test["gas"]), "gas_left is incorrect");
fail_unless(output == Bytes::from_json(&test["out"]), "output is incorrect");
test.find("post").map(|pre| for (addr, s) in pre.as_object().unwrap() {
let address = Address::from(addr.as_ref());
fail_unless(state.code(&address).unwrap_or(vec![]) == Bytes::from_json(&s["code"]), "code is incorrect");
fail_unless(state.balance(&address) == xjson!(&s["balance"]), "balance is incorrect");
fail_unless(state.nonce(&address) == xjson!(&s["nonce"]), "nonce is incorrect");
BTreeMap::from_json(&s["storage"]).iter().foreach(|(k, v)| fail_unless(&state.storage_at(&address, &k) == v, "storage is incorrect"));
});
let cc = test["callcreates"].as_array().unwrap();
fail_unless(callcreates.len() == cc.len(), "callcreates does not match");
for i in 0..cc.len() {
let callcreate = &callcreates[i];
let expected = &cc[i];
fail_unless(callcreate.data == Bytes::from_json(&expected["data"]), "callcreates data is incorrect");
fail_unless(callcreate.destination == xjson!(&expected["destination"]), "callcreates destination is incorrect");
fail_unless(callcreate.value == xjson!(&expected["value"]), "callcreates value is incorrect");
fail_unless(callcreate.gas_limit == xjson!(&expected["gasLimit"]), "callcreates gas_limit is incorrect");
}
}
}
}
for f in failed.iter() {
println!("FAILED: {:?}", f);
}
//assert!(false);
failed
}
declare_test!{ExecutiveTests_vmArithmeticTest, "VMTests/vmArithmeticTest"}
declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperationTest"}
// this one crashes with some vm internal error. Separately they pass.
declare_test_ignore!{ExecutiveTests_vmBlockInfoTest, "VMTests/vmBlockInfoTest"}
declare_test!{ExecutiveTests_vmEnvironmentalInfoTest, "VMTests/vmEnvironmentalInfoTest"}
declare_test!{ExecutiveTests_vmIOandFlowOperationsTest, "VMTests/vmIOandFlowOperationsTest"}
// this one take way too long.
declare_test_ignore!{ExecutiveTests_vmInputLimits, "VMTests/vmInputLimits"}
declare_test!{ExecutiveTests_vmLogTest, "VMTests/vmLogTest"}
declare_test!{ExecutiveTests_vmPerformanceTest, "VMTests/vmPerformanceTest"}
declare_test!{ExecutiveTests_vmPushDupSwapTest, "VMTests/vmPushDupSwapTest"}
declare_test!{ExecutiveTests_vmSha3Test, "VMTests/vmSha3Test"}
declare_test!{ExecutiveTests_vmSystemOperationsTest, "VMTests/vmSystemOperationsTest"}
declare_test!{ExecutiveTests_vmtests, "VMTests/vmtests"}

6
src/tests/mod.rs Normal file
View File

@@ -0,0 +1,6 @@
#[macro_use]
mod test_common;
mod transaction;
mod executive;
mod state;

92
src/tests/state.rs Normal file
View File

@@ -0,0 +1,92 @@
use super::test_common::*;
use state::*;
use pod_state::*;
use state_diff::*;
use ethereum;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
let mut failed = Vec::new();
let engine = ethereum::new_frontier_like_test().to_engine().unwrap();
flush(format!("\n"));
for (name, test) in json.as_object().unwrap() {
let mut fail = false;
{
let mut fail_unless = |cond: bool| if !cond && !fail {
failed.push(name.to_string());
flush(format!("FAIL\n"));
fail = true;
true
} else {false};
flush(format!(" - {}...", name));
let t = Transaction::from_json(&test["transaction"]);
let env = EnvInfo::from_json(&test["env"]);
let _out = Bytes::from_json(&test["out"]);
let post_state_root = xjson!(&test["postStateRoot"]);
let pre = PodState::from_json(&test["pre"]);
let post = PodState::from_json(&test["post"]);
let logs: Vec<_> = test["logs"].as_array().unwrap().iter().map(&LogEntry::from_json).collect();
//println!("Transaction: {:?}", t);
//println!("Env: {:?}", env);
let calc_post = sec_trie_root(post.get().iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect());
if fail_unless(post_state_root == calc_post) {
println!("!!! {}: Trie root mismatch (got: {}, expect: {}):", name, calc_post, post_state_root);
println!("!!! Post:\n{}", post);
} else {
let mut s = State::new_temp();
s.populate_from(pre);
s.commit();
let res = s.apply(&env, engine.deref(), &t);
if fail_unless(s.root() == &post_state_root) {
println!("!!! {}: State mismatch (got: {}, expect: {}):", name, s.root(), post_state_root);
let our_post = s.to_pod();
println!("Got:\n{}", our_post);
println!("Expect:\n{}", post);
println!("Diff ---expect -> +++got:\n{}", StateDiff::diff_pod(&post, &our_post));
}
if let Ok(r) = res {
if fail_unless(logs == r.logs) {
println!("!!! {}: Logs mismatch:", name);
println!("Got:\n{:?}", r.logs);
println!("Expect:\n{:?}", logs);
}
}
}
}
if !fail {
flush(format!("ok\n"));
}
// TODO: Add extra APIs for output
//if fail_unless(out == r.)
}
println!("!!! {:?} tests from failed.", failed.len());
failed
}
declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"}
declare_test!{StateTests_stCallCodes, "StateTests/stCallCodes"}
declare_test_ignore!{StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"} //<< Out of stack
declare_test!{StateTests_stDelegatecallTest, "StateTests/stDelegatecallTest"} //<< FAIL - gas too high
declare_test!{StateTests_stExample, "StateTests/stExample"}
declare_test!{StateTests_stInitCodeTest, "StateTests/stInitCodeTest"}
declare_test!{StateTests_stLogTests, "StateTests/stLogTests"}
declare_test!{StateTests_stMemoryStressTest, "StateTests/stMemoryStressTest"}
declare_test!{StateTests_stMemoryTest, "StateTests/stMemoryTest"}
declare_test!{StateTests_stPreCompiledContracts, "StateTests/stPreCompiledContracts"}
declare_test_ignore!{StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"} //<< Too long
declare_test_ignore!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} //<< Out of stack
declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"}
declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"}
declare_test_ignore!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} //<< Signal 11
declare_test_ignore!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} //<< Signal 11
declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"}
declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"}
declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"}

24
src/tests/test_common.rs Normal file
View File

@@ -0,0 +1,24 @@
pub use common::*;
#[macro_export]
macro_rules! declare_test {
($id: ident, $name: expr) => {
#[test]
#[allow(non_snake_case)]
fn $id() {
assert!(do_json_test(include_bytes!(concat!("../../res/ethereum/tests/", $name, ".json"))).len() == 0);
}
};
}
#[macro_export]
macro_rules! declare_test_ignore {
($id: ident, $name: expr) => {
#[test]
#[ignore]
#[allow(non_snake_case)]
fn $id() {
assert!(do_json_test(include_bytes!(concat!("../../res/ethereum/tests/", $name, ".json"))).len() == 0);
}
};
}

78
src/tests/transaction.rs Normal file
View File

@@ -0,0 +1,78 @@
use super::test_common::*;
use evm;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
let mut failed = Vec::new();
let old_schedule = evm::Schedule::new_frontier();
let new_schedule = evm::Schedule::new_homestead();
let ot = RefCell::new(Transaction::new());
for (name, test) in json.as_object().unwrap() {
let mut fail = false;
let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.to_string()); println!("Transaction: {:?}", ot.borrow()); fail = true };
let schedule = match test.find("blocknumber")
.and_then(|j| j.as_string())
.and_then(|s| BlockNumber::from_str(s).ok())
.unwrap_or(0) { x if x < 900000 => &old_schedule, _ => &new_schedule };
let rlp = Bytes::from_json(&test["rlp"]);
let res = UntrustedRlp::new(&rlp).as_val().map_err(|e| From::from(e)).and_then(|t: Transaction| t.validate(schedule, schedule.have_delegate_call));
fail_unless(test.find("transaction").is_none() == res.is_err());
if let (Some(&Json::Object(ref tx)), Some(&Json::String(ref expect_sender))) = (test.find("transaction"), test.find("sender")) {
let t = res.unwrap();
fail_unless(t.sender().unwrap() == address_from_hex(clean(expect_sender)));
fail_unless(t.data == Bytes::from_json(&tx["data"]));
fail_unless(t.gas == xjson!(&tx["gasLimit"]));
fail_unless(t.gas_price == xjson!(&tx["gasPrice"]));
fail_unless(t.nonce == xjson!(&tx["nonce"]));
fail_unless(t.value == xjson!(&tx["value"]));
if let Action::Call(ref to) = t.action {
*ot.borrow_mut() = t.clone();
fail_unless(to == &xjson!(&tx["to"]));
} else {
*ot.borrow_mut() = t.clone();
fail_unless(Bytes::from_json(&tx["to"]).len() == 0);
}
}
}
for f in failed.iter() {
println!("FAILED: {:?}", f);
}
failed
}
// Once we have interpolate idents.
/*macro_rules! declare_test {
($test_set_name: ident / $name: ident) => {
#[test]
#[allow(non_snake_case)]
fn $name() {
assert!(do_json_test(include_bytes!(concat!("../res/ethereum/tests/", stringify!($test_set_name), "/", stringify!($name), ".json"))).len() == 0);
}
};
($test_set_name: ident / $prename: ident / $name: ident) => {
#[test]
#[allow(non_snake_case)]
interpolate_idents! { fn [$prename _ $name]()
{
let json = include_bytes!(concat!("../res/ethereum/tests/", stringify!($test_set_name), "/", stringify!($prename), "/", stringify!($name), ".json"));
assert!(do_json_test(json).len() == 0);
}
}
};
}
declare_test!{TransactionTests/ttTransactionTest}
declare_test!{TransactionTests/tt10mbDataField}
declare_test!{TransactionTests/ttWrongRLPTransaction}
declare_test!{TransactionTests/Homestead/ttTransactionTest}
declare_test!{TransactionTests/Homestead/tt10mbDataField}
declare_test!{TransactionTests/Homestead/ttWrongRLPTransaction}
declare_test!{TransactionTests/RandomTests/tr201506052141PYTHON}*/
declare_test!{TransactionTests_ttTransactionTest, "TransactionTests/ttTransactionTest"}
declare_test_ignore!{TransactionTests_tt10mbDataField, "TransactionTests/tt10mbDataField"}
declare_test!{TransactionTests_ttWrongRLPTransaction, "TransactionTests/ttWrongRLPTransaction"}
declare_test!{TransactionTests_Homestead_ttTransactionTest, "TransactionTests/Homestead/ttTransactionTest"}
declare_test_ignore!{TransactionTests_Homestead_tt10mbDataField, "TransactionTests/Homestead/tt10mbDataField"}
declare_test!{TransactionTests_Homestead_ttWrongRLPTransaction, "TransactionTests/Homestead/ttWrongRLPTransaction"}
declare_test!{TransactionTests_RandomTests_tr201506052141PYTHON, "TransactionTests/RandomTests/tr201506052141PYTHON"}

View File

@@ -1,177 +0,0 @@
#include <stdint.h>
#include <string.h>
/** libkeccak-tiny
*
* A single-file implementation of SHA-3 and SHAKE.
*
* Implementor: David Leon Gil
* License: CC0, attribution kindly requested. Blame taken too,
* but not liability.
*/
#define decshake(bits) \
int shake##bits(uint8_t*, size_t, const uint8_t*, size_t);
#define decsha3(bits) \
int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t);
decshake(128)
decshake(256)
decsha3(224)
decsha3(256)
decsha3(384)
decsha3(512)
/******** The Keccak-f[1600] permutation ********/
/*** Constants. ***/
static const uint8_t rho[24] = \
{ 1, 3, 6, 10, 15, 21,
28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43,
62, 18, 39, 61, 20, 44};
static const uint8_t pi[24] = \
{10, 7, 11, 17, 18, 3,
5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2,
20, 14, 22, 9, 6, 1};
static const uint64_t RC[24] = \
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
/*** Helper macros to unroll the permutation. ***/
#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
#define REPEAT6(e) e e e e e e
#define REPEAT24(e) REPEAT6(e e e e)
#define REPEAT5(e) e e e e e
#define FOR5(v, s, e) \
v = 0; \
REPEAT5(e; v += s;)
/*** Keccak-f[1600] ***/
static inline void keccakf(void* state) {
uint64_t* a = (uint64_t*)state;
uint64_t b[5] = {0};
uint64_t t = 0;
uint8_t x, y;
int i;
for (i = 0; i < 24; i++) {
// Theta
FOR5(x, 1,
b[x] = 0;
FOR5(y, 5,
b[x] ^= a[x + y]; ))
FOR5(x, 1,
FOR5(y, 5,
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
// Rho and pi
t = a[1];
x = 0;
REPEAT24(b[0] = a[pi[x]];
a[pi[x]] = rol(t, rho[x]);
t = b[0];
x++; )
// Chi
FOR5(y,
5,
FOR5(x, 1,
b[x] = a[y + x];)
FOR5(x, 1,
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
// Iota
a[0] ^= RC[i];
}
}
/******** The FIPS202-defined functions. ********/
/*** Some helper macros. ***/
#define _(S) do { S } while (0)
#define FOR(i, ST, L, S) \
_({size_t i; for (i = 0; i < L; i += ST) { S; }})
#define mkapply_ds(NAME, S) \
static inline void NAME(uint8_t* dst, \
const uint8_t* src, \
size_t len) { \
FOR(i, 1, len, S); \
}
#define mkapply_sd(NAME, S) \
static inline void NAME(const uint8_t* src, \
uint8_t* dst, \
size_t len) { \
FOR(i, 1, len, S); \
}
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
mkapply_sd(setout, dst[i] = src[i]) // setout
#define P keccakf
#define Plen 200
// Fold P*F over the full blocks of an input.
#define foldP(I, L, F) \
while (L >= rate) { \
F(a, I, rate); \
P(a); \
I += rate; \
L -= rate; \
}
/** The sponge-based hash construction. **/
static inline int hash(uint8_t* out, size_t outlen,
const uint8_t* in, size_t inlen,
size_t rate, uint8_t delim) {
if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
return -1;
}
uint8_t a[Plen] = {0};
// Absorb input.
foldP(in, inlen, xorin);
// Xor in the DS and pad frame.
a[inlen] ^= delim;
a[rate - 1] ^= 0x80;
// Xor in the last block.
xorin(a, in, inlen);
// Apply P
P(a);
// Squeeze output.
foldP(out, outlen, setout);
setout(a, out, outlen);
memset(a, 0, 200);
return 0;
}
/*** Helper macros to define SHA3 and SHAKE instances. ***/
#define defshake(bits) \
int shake##bits(uint8_t* out, size_t outlen, \
const uint8_t* in, size_t inlen) { \
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \
}
#define defsha3(bits) \
int sha3_##bits(uint8_t* out, size_t outlen, \
const uint8_t* in, size_t inlen) { \
if (outlen > (bits/8)) { \
return -1; \
} \
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
}
/*** FIPS202 SHAKE VOFs ***/
defshake(128)
defshake(256)
/*** FIPS202 SHA3 FOFs ***/
defsha3(224)
defsha3(256)
defsha3(384)
defsha3(512)

293
src/transaction.rs Normal file
View File

@@ -0,0 +1,293 @@
use util::*;
use basic_types::*;
use error::*;
use evm::Schedule;
#[derive(Debug,Clone)]
pub enum Action {
Create,
Call(Address),
}
/// A set of information describing an externally-originating message call
/// or contract creation operation.
#[derive(Debug,Clone)]
pub struct Transaction {
pub nonce: U256,
pub gas_price: U256,
pub gas: U256,
pub action: Action,
pub value: U256,
pub data: Bytes,
// signature
pub v: u8,
pub r: U256,
pub s: U256,
hash: RefCell<Option<H256>>,
sender: RefCell<Option<Address>>,
}
impl Transaction {
pub fn new() -> Self {
Transaction {
nonce: x!(0),
gas_price: x!(0),
gas: x!(0),
action: Action::Create,
value: x!(0),
data: vec![],
v: 0,
r: x!(0),
s: x!(0),
hash: RefCell::new(None),
sender: RefCell::new(None),
}
}
/// Create a new message-call transaction.
pub fn new_call(to: Address, value: U256, data: Bytes, gas: U256, gas_price: U256, nonce: U256) -> Transaction {
Transaction {
nonce: nonce,
gas_price: gas_price,
gas: gas,
action: Action::Call(to),
value: value,
data: data,
v: 0,
r: x!(0),
s: x!(0),
hash: RefCell::new(None),
sender: RefCell::new(None),
}
}
/// Create a new contract-creation transaction.
pub fn new_create(value: U256, data: Bytes, gas: U256, gas_price: U256, nonce: U256) -> Transaction {
Transaction {
nonce: nonce,
gas_price: gas_price,
gas: gas,
action: Action::Create,
value: value,
data: data,
v: 0,
r: x!(0),
s: x!(0),
hash: RefCell::new(None),
sender: RefCell::new(None),
}
}
/// Get the nonce of the transaction.
pub fn nonce(&self) -> &U256 { &self.nonce }
/// Get the gas price of the transaction.
pub fn gas_price(&self) -> &U256 { &self.gas_price }
/// Get the gas of the transaction.
pub fn gas(&self) -> &U256 { &self.gas }
/// Get the action of the transaction (Create or Call).
pub fn action(&self) -> &Action { &self.action }
/// Get the value of the transaction.
pub fn value(&self) -> &U256 { &self.value }
/// Get the data of the transaction.
pub fn data(&self) -> &Bytes { &self.data }
/// Append object into RLP stream, optionally with or without the signature.
pub fn rlp_append_opt(&self, s: &mut RlpStream, with_seal: Seal) {
s.append_list(6 + match with_seal { Seal::With => 3, _ => 0 });
s.append(&self.nonce);
s.append(&self.gas_price);
s.append(&self.gas);
match self.action {
Action::Create => s.append_empty_data(),
Action::Call(ref to) => s.append(to),
};
s.append(&self.value);
s.append(&self.data);
match with_seal {
Seal::With => { s.append(&(self.v as u16)).append(&self.r).append(&self.s); },
_ => {}
}
}
/// Get the RLP serialisation of the object, optionally with or without the signature.
pub fn rlp_bytes_opt(&self, with_seal: Seal) -> Bytes {
let mut s = RlpStream::new();
self.rlp_append_opt(&mut s, with_seal);
s.out()
}
}
impl FromJson for Transaction {
fn from_json(json: &Json) -> Transaction {
let mut r = Transaction {
nonce: xjson!(&json["nonce"]),
gas_price: xjson!(&json["gasPrice"]),
gas: xjson!(&json["gasLimit"]),
action: match Bytes::from_json(&json["to"]) {
ref x if x.len() == 0 => Action::Create,
ref x => Action::Call(Address::from_slice(x)),
},
value: xjson!(&json["value"]),
data: xjson!(&json["data"]),
v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 },
r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) },
s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) },
hash: RefCell::new(None),
sender: match json.find("sender") {
Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))),
_ => RefCell::new(None),
},
};
if let Some(&Json::String(ref secret_key)) = json.find("secretKey") {
r.sign(&h256_from_hex(clean(secret_key)));
}
r
}
}
impl RlpStandard for Transaction {
fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_opt(s, Seal::With) }
}
impl Transaction {
/// Get the hash of this header (sha3 of the RLP).
pub fn hash(&self) -> H256 {
let mut hash = self.hash.borrow_mut();
match &mut *hash {
&mut Some(ref h) => h.clone(),
hash @ &mut None => {
*hash = Some(self.rlp_sha3());
hash.as_ref().unwrap().clone()
}
}
}
/// Note that some fields have changed. Resets the memoised hash.
pub fn note_dirty(&self) {
*self.hash.borrow_mut() = None;
}
/// 0 is `v` is 27, 1 if 28, and 4 otherwise.
pub fn standard_v(&self) -> u8 { match self.v { 27 => 0, 28 => 1, _ => 4 } }
/// Construct a signature object from the sig.
pub fn signature(&self) -> Signature { Signature::from_rsv(&From::from(&self.r), &From::from(&self.s), self.standard_v()) }
/// The message hash of the transaction.
pub fn message_hash(&self) -> H256 { self.rlp_bytes_opt(Seal::Without).sha3() }
/// Returns transaction sender.
pub fn sender(&self) -> Result<Address, Error> {
let mut sender = self.sender.borrow_mut();
match &mut *sender {
&mut Some(ref h) => Ok(h.clone()),
sender @ &mut None => {
*sender = Some(From::from(try!(ec::recover(&self.signature(), &self.message_hash())).sha3()));
Ok(sender.as_ref().unwrap().clone())
}
}
}
/// Signs the transaction as coming from `sender`.
pub fn sign(&mut self, secret: &Secret) {
// TODO: make always low.
let sig = ec::sign(secret, &self.message_hash());
let (r, s, v) = sig.unwrap().to_rsv();
self.r = r;
self.s = s;
self.v = v + 27;
}
/// Signs the transaction as coming from `sender`.
pub fn signed(self, secret: &Secret) -> Transaction { let mut r = self; r.sign(secret); r }
/// Get the transaction cost in gas for the given params.
pub fn gas_required_for(is_create: bool, data: &[u8], schedule: &Schedule) -> u64 {
data.iter().fold(
(if is_create {schedule.tx_create_gas} else {schedule.tx_gas}) as u64,
|g, b| g + (match *b { 0 => schedule.tx_data_zero_gas, _ => schedule.tx_data_non_zero_gas }) as u64
)
}
/// Get the transaction cost in gas for this transaction.
pub fn gas_required(&self, schedule: &Schedule) -> u64 {
Self::gas_required_for(match self.action{Action::Create=>true, Action::Call(_)=>false}, &self.data, schedule)
}
/// Checks whether the signature has a low 's' value.
pub fn check_low_s(&self) -> Result<(), Error> {
if !ec::is_low_s(&self.s) {
Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature)))
} else {
Ok(())
}
}
/// Do basic validation, checking for valid signature and minimum gas,
pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result<Transaction, Error> {
if require_low && !ec::is_low_s(&self.s) {
return Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature)));
}
try!(self.sender());
if self.gas < U256::from(self.gas_required(&schedule)) {
Err(From::from(TransactionError::InvalidGasLimit(OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas})))
} else {
Ok(self)
}
}
}
impl Decodable for Action {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let rlp = decoder.as_rlp();
if rlp.is_empty() {
Ok(Action::Create)
} else {
Ok(Action::Call(try!(rlp.as_val())))
}
}
}
impl Decodable for Transaction {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = try!(decoder.as_list());
if d.len() != 9 {
return Err(DecoderError::RlpIncorrectListLen);
}
Ok(Transaction {
nonce: try!(Decodable::decode(&d[0])),
gas_price: try!(Decodable::decode(&d[1])),
gas: try!(Decodable::decode(&d[2])),
action: try!(Decodable::decode(&d[3])),
value: try!(Decodable::decode(&d[4])),
data: try!(Decodable::decode(&d[5])),
v: try!(u16::decode(&d[6])) as u8,
r: try!(Decodable::decode(&d[7])),
s: try!(Decodable::decode(&d[8])),
hash: RefCell::new(None),
sender: RefCell::new(None),
})
}
}
#[test]
fn sender_test() {
let t: Transaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
assert_eq!(t.data, b"");
assert_eq!(t.gas, U256::from(0x5208u64));
assert_eq!(t.gas_price, U256::from(0x01u64));
assert_eq!(t.nonce, U256::from(0x00u64));
if let Action::Call(ref to) = t.action {
assert_eq!(*to, address_from_hex("095e7baea6a6c7c4c2dfeb977efac326af552d87"));
} else { panic!(); }
assert_eq!(t.value, U256::from(0x0au64));
assert_eq!(t.sender().unwrap(), address_from_hex("0f65fe9276bc9a24ae7083ae28e2660ef72df99e"));
}
#[test]
fn signing() {
let key = KeyPair::create().unwrap();
let t = Transaction::new_create(U256::from(42u64), b"Hello!".to_vec(), U256::from(3000u64), U256::from(50_000u64), U256::from(1u64)).signed(&key.secret());
assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap());
}

View File

@@ -1,80 +0,0 @@
use sha3::*;
use hash::H256;
use bytes::*;
use rlp::*;
use hashdb::*;
/// Type of operation for the backing database - either a new node or a node deletion.
#[derive(Debug)]
enum Operation {
New(H256, Bytes),
Delete(H256),
}
/// How many insertions and removals were done in an `apply` operation.
pub struct Score {
/// Number of insertions.
pub inserts: usize,
/// Number of removals.
pub removes: usize,
}
/// A journal of operations on the backing database.
#[derive(Debug)]
pub struct Journal (Vec<Operation>);
impl Journal {
/// Create a new, empty, object.
pub fn new() -> Journal { Journal(vec![]) }
/// Given the RLP that encodes a node, append a reference to that node `out` and leave `journal`
/// such that the reference is valid, once applied.
pub fn new_node(&mut self, rlp: Bytes, out: &mut RlpStream) {
if rlp.len() >= 32 {
let rlp_sha3 = rlp.sha3();
trace!("new_node: reference node {:?} => {:?}", rlp_sha3, rlp.pretty());
out.append(&rlp_sha3);
self.0.push(Operation::New(rlp_sha3, rlp));
}
else {
trace!("new_node: inline node {:?}", rlp.pretty());
out.append_raw(&rlp, 1);
}
}
/// Given the RLP that encodes a now-unused node, leave `journal` in such a state that it is noted.
pub fn delete_node_sha3(&mut self, old_sha3: H256) {
trace!("delete_node: {:?}", old_sha3);
self.0.push(Operation::Delete(old_sha3));
}
/// Register an RLP-encoded node for deletion (given a slice), if it needs to be deleted.
pub fn delete_node(&mut self, old: &[u8]) {
let r = Rlp::new(old);
if r.is_data() && r.size() == 32 {
self.delete_node_sha3(r.as_val());
}
}
/// Apply this journal to the HashDB `db` and return the number of insertions and removals done.
pub fn apply(self, db: &mut HashDB) -> Score {
trace!("applying {:?} changes", self.0.len());
let mut ret = Score{inserts: 0, removes: 0};
for d in self.0.into_iter() {
match d {
Operation::Delete(h) => {
trace!("TrieDBMut::apply --- {:?}", &h);
db.remove(&h);
ret.removes += 1;
},
Operation::New(h, d) => {
trace!("TrieDBMut::apply +++ {:?} -> {:?}", &h, d.pretty());
db.emplace(h, d);
ret.inserts += 1;
}
}
}
ret
}
}

View File

@@ -1,15 +0,0 @@
pub mod trietraits;
pub mod standardmap;
pub mod journal;
pub mod node;
pub mod triedb;
pub mod triedbmut;
pub mod sectriedb;
pub mod sectriedbmut;
pub use self::trietraits::*;
pub use self::standardmap::*;
pub use self::triedbmut::*;
pub use self::triedb::*;
pub use self::sectriedbmut::*;
pub use self::sectriedb::*;

View File

@@ -1,121 +0,0 @@
use hash::*;
use nibbleslice::*;
use bytes::*;
use rlp::*;
use super::journal::*;
/// Type of node in the trie and essential information thereof.
#[derive(Eq, PartialEq, Debug)]
pub enum Node<'a> {
Empty,
Leaf(NibbleSlice<'a>, &'a[u8]),
Extension(NibbleSlice<'a>, &'a[u8]),
Branch([&'a[u8]; 16], Option<&'a [u8]>)
}
impl<'a> Node<'a> {
/// Decode the `node_rlp` and return the Node.
pub fn decoded(node_rlp: &'a [u8]) -> Node<'a> {
let r = Rlp::new(node_rlp);
match r.prototype() {
// either leaf or extension - decode first item with NibbleSlice::???
// and use is_leaf return to figure out which.
// if leaf, second item is a value (is_data())
// if extension, second item is a node (either SHA3 to be looked up and
// fed back into this function or inline RLP which can be fed back into this function).
Prototype::List(2) => match NibbleSlice::from_encoded(r.at(0).data()) {
(slice, true) => Node::Leaf(slice, r.at(1).data()),
(slice, false) => Node::Extension(slice, r.at(1).as_raw()),
},
// branch - first 16 are nodes, 17th is a value (or empty).
Prototype::List(17) => {
let mut nodes: [&'a [u8]; 16] = unsafe { ::std::mem::uninitialized() };
for i in 0..16 {
nodes[i] = r.at(i).as_raw();
}
Node::Branch(nodes, if r.at(16).is_empty() { None } else { Some(r.at(16).data()) })
},
// an empty branch index.
Prototype::Data(0) => Node::Empty,
// something went wrong.
_ => panic!("Rlp is not valid.")
}
}
/// Encode the node into RLP.
///
/// Will always return the direct node RLP even if it's 32 or more bytes. To get the
/// RLP which would be valid for using in another node, use `encoded_and_added()`.
pub fn encoded(&self) -> Bytes {
match *self {
Node::Leaf(ref slice, ref value) => {
let mut stream = RlpStream::new_list(2);
stream.append(&slice.encoded(true));
stream.append(value);
stream.out()
},
Node::Extension(ref slice, ref raw_rlp) => {
let mut stream = RlpStream::new_list(2);
stream.append(&slice.encoded(false));
stream.append_raw(raw_rlp, 1);
stream.out()
},
Node::Branch(ref nodes, ref value) => {
let mut stream = RlpStream::new_list(17);
for i in 0..16 {
stream.append_raw(nodes[i], 1);
}
match *value {
Some(n) => { stream.append(&n); },
None => { stream.append_empty_data(); },
}
stream.out()
},
Node::Empty => {
let mut stream = RlpStream::new();
stream.append_empty_data();
stream.out()
}
}
}
/// Encode the node, adding it to `journal` if necessary and return the RLP valid for
/// insertion into a parent node.
pub fn encoded_and_added(&self, journal: &mut Journal) -> Bytes {
let mut stream = RlpStream::new();
match *self {
Node::Leaf(ref slice, ref value) => {
stream.append_list(2);
stream.append(&slice.encoded(true));
stream.append(value);
},
Node::Extension(ref slice, ref raw_rlp) => {
stream.append_list(2);
stream.append(&slice.encoded(false));
stream.append_raw(raw_rlp, 1);
},
Node::Branch(ref nodes, ref value) => {
stream.append_list(17);
for i in 0..16 {
stream.append_raw(nodes[i], 1);
}
match *value {
Some(n) => { stream.append(&n); },
None => { stream.append_empty_data(); },
}
},
Node::Empty => {
stream.append_empty_data();
}
}
let node = stream.out();
match node.len() {
0 ... 31 => node,
_ => {
let mut stream = RlpStream::new();
journal.new_node(node, &mut stream);
stream.out()
}
}
}
}

View File

@@ -1,59 +0,0 @@
use hash::*;
use sha3::*;
use hashdb::*;
use rlp::*;
use super::triedb::*;
use super::trietraits::*;
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
///
/// Use it as a `Trie` trait object. You can use `raw()` to get the backing TrieDB object.
pub struct SecTrieDB<'db> {
raw: TrieDB<'db>
}
impl<'db> SecTrieDB<'db> {
/// Create a new trie with the backing database `db` and empty `root`
/// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly.
pub fn new(db: &'db HashDB, root: &'db H256) -> Self {
SecTrieDB { raw: TrieDB::new(db, root) }
}
/// Get a reference to the underlying raw TrieDB struct.
pub fn raw(&self) -> &TrieDB {
&self.raw
}
/// Get a mutable reference to the underlying raw TrieDB struct.
pub fn raw_mut(&mut self) -> &TrieDB {
&mut self.raw
}
}
impl<'db> Trie for SecTrieDB<'db> {
fn root(&self) -> &H256 { self.raw.root() }
fn contains(&self, key: &[u8]) -> bool {
self.raw.contains(&key.sha3())
}
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.raw.get(&key.sha3())
}
}
#[test]
fn trie_to_sectrie() {
use memorydb::*;
use super::triedbmut::*;
let mut memdb = MemoryDB::new();
let mut root = H256::new();
{
let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&(&[0x01u8, 0x23]).sha3(), &[0x01u8, 0x23]);
}
let t = SecTrieDB::new(&memdb, &root);
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap(), &[0x01u8, 0x23]);
}

View File

@@ -1,65 +0,0 @@
use hash::*;
use sha3::*;
use hashdb::*;
use rlp::*;
use super::triedbmut::*;
use super::trietraits::*;
/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
///
/// Use it as a `Trie` or `TrieMut` trait object. You can use `raw()` to get the backing TrieDBMut object.
pub struct SecTrieDBMut<'db> {
raw: TrieDBMut<'db>
}
impl<'db> SecTrieDBMut<'db> {
/// Create a new trie with the backing database `db` and empty `root`
/// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly.
pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self {
SecTrieDBMut { raw: TrieDBMut::new(db, root) }
}
/// Create a new trie with the backing database `db` and `root`
/// Panics, if `root` does not exist
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self {
SecTrieDBMut { raw: TrieDBMut::from_existing(db, root) }
}
}
impl<'db> Trie for SecTrieDBMut<'db> {
fn root(&self) -> &H256 { self.raw.root() }
fn contains(&self, key: &[u8]) -> bool {
self.raw.contains(&key.sha3())
}
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.raw.get(&key.sha3())
}
}
impl<'db> TrieMut for SecTrieDBMut<'db> {
fn insert(&mut self, key: &[u8], value: &[u8]) {
self.raw.insert(&key.sha3(), value);
}
fn remove(&mut self, key: &[u8]) {
self.raw.remove(&key.sha3());
}
}
#[test]
fn sectrie_to_trie() {
use memorydb::*;
use super::triedb::*;
let mut memdb = MemoryDB::new();
let mut root = H256::new();
{
let mut t = SecTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
}
let t = TrieDB::new(&memdb, &root);
assert_eq!(t.get(&(&[0x01u8, 0x23]).sha3()).unwrap(), &[0x01u8, 0x23]);
}

View File

@@ -1,75 +0,0 @@
//! Key-value datastore with a modified Merkle tree.
extern crate rand;
use bytes::*;
use sha3::*;
use hash::*;
/// Alphabet to use when creating words for insertion into tries.
pub enum Alphabet {
All,
Low,
Mid,
Custom(Bytes),
}
/// Standard test map for profiling tries.
pub struct StandardMap {
alphabet: Alphabet,
min_key: usize,
journal_key: usize,
count: usize,
}
impl StandardMap {
/// Get a bunch of random bytes, at least `min_count` bytes, at most `min_count` + `journal_count` bytes.
/// `seed` is mutated pseudoramdonly and used.
fn random_bytes(min_count: usize, journal_count: usize, seed: &mut H256) -> Vec<u8> {
assert!(min_count + journal_count <= 32);
*seed = seed.sha3();
let r = min_count + (seed.bytes()[31] as usize % (journal_count + 1));
seed.bytes()[0..r].to_vec()
}
/// Get a random value. Equal chance of being 1 byte as of 32. `seed` is mutated pseudoramdonly and used.
fn random_value(seed: &mut H256) -> Bytes {
*seed = seed.sha3();
match seed.bytes()[0] % 2 {
1 => vec![seed.bytes()[31];1],
_ => seed.bytes().to_vec(),
}
}
/// Get a random word of, at least `min_count` bytes, at most `min_count` + `journal_count` bytes.
/// Each byte is an item from `alphabet`. `seed` is mutated pseudoramdonly and used.
fn random_word(alphabet: &[u8], min_count: usize, journal_count: usize, seed: &mut H256) -> Vec<u8> {
assert!(min_count + journal_count <= 32);
*seed = seed.sha3();
let r = min_count + (seed.bytes()[31] as usize % (journal_count + 1));
let mut ret: Vec<u8> = Vec::with_capacity(r);
for i in 0..r {
ret.push(alphabet[seed.bytes()[i] as usize % alphabet.len()]);
}
ret
}
/// Create the standard map (set of keys and values) for the object's fields.
pub fn make(&self) -> Vec<(Bytes, Bytes)> {
let low = b"abcdef";
let mid = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
let mut d: Vec<(Bytes, Bytes)> = Vec::new();
let mut seed = H256::new();
for _ in 0..self.count {
let k = match self.alphabet {
Alphabet::All => Self::random_bytes(self.min_key, self.journal_key, &mut seed),
Alphabet::Low => Self::random_word(low, self.min_key, self.journal_key, &mut seed),
Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, &mut seed),
Alphabet::Custom(ref a) => Self::random_word(&a, self.min_key, self.journal_key, &mut seed),
};
let v = Self::random_value(&mut seed);
d.push((k, v))
}
d
}
}

View File

@@ -1,220 +0,0 @@
use common::*;
use hashdb::*;
use nibbleslice::*;
use rlp::*;
use super::trietraits::*;
use super::node::*;
/// A `Trie` implementation using a generic `HashDB` backing database.
///
/// Use it as a `Trie` trait object. You can use `db()` to get the backing database object, `keys`
/// to get the keys belonging to the trie in the backing database, and `db_items_remaining()` to get
/// which items in the backing database do not belong to this trie. If this is the only trie in the
/// backing database, then `db_items_remaining()` should be empty.
///
/// # Example
/// ```
/// extern crate ethcore_util as util;
/// use util::trie::*;
/// use util::hashdb::*;
/// use util::memorydb::*;
/// use util::hash::*;
/// use util::rlp::*;
///
/// fn main() {
/// let mut memdb = MemoryDB::new();
/// let mut root = H256::new();
/// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar");
/// let t = TrieDB::new(&memdb, &root);
/// assert!(t.contains(b"foo"));
/// assert_eq!(t.get(b"foo").unwrap(), b"bar");
/// assert!(t.db_items_remaining().is_empty());
/// }
/// ```
pub struct TrieDB<'db> {
db: &'db HashDB,
root: &'db H256,
pub hash_count: usize,
}
impl<'db> TrieDB<'db> {
/// Create a new trie with the backing database `db` and `root`
/// Panics, if `root` does not exist
pub fn new(db: &'db HashDB, root: &'db H256) -> Self {
if !db.exists(root) {
flush(format!("Trie root not found {}", root));
panic!("Trie root not found!");
}
TrieDB {
db: db,
root: root,
hash_count: 0
}
}
/// Get the backing database.
pub fn db(&'db self) -> &'db HashDB {
self.db
}
/// Determine all the keys in the backing database that belong to the trie.
pub fn keys(&self) -> Vec<H256> {
let mut ret: Vec<H256> = Vec::new();
ret.push(self.root.clone());
self.accumulate_keys(self.root_node(), &mut ret);
ret
}
/// Convert a vector of hashes to a hashmap of hash to occurances.
pub fn to_map(hashes: Vec<H256>) -> HashMap<H256, u32> {
let mut r: HashMap<H256, u32> = HashMap::new();
for h in hashes.into_iter() {
let c = *r.get(&h).unwrap_or(&0);
r.insert(h, c + 1);
}
r
}
/// Determine occurances of items in the backing database which are not related to this
/// trie.
pub fn db_items_remaining(&self) -> HashMap<H256, i32> {
let mut ret = self.db.keys();
for (k, v) in Self::to_map(self.keys()).into_iter() {
let keycount = *ret.get(&k).unwrap_or(&0);
match keycount <= v as i32 {
true => ret.remove(&k),
_ => ret.insert(k, keycount - v as i32),
};
}
ret
}
/// Recursion helper for `keys`.
fn accumulate_keys(&self, node: Node, acc: &mut Vec<H256>) {
let mut handle_payload = |payload| {
let p = Rlp::new(payload);
if p.is_data() && p.size() == 32 {
acc.push(p.as_val());
}
self.accumulate_keys(self.get_node(payload), acc);
};
match node {
Node::Extension(_, payload) => handle_payload(payload),
Node::Branch(payloads, _) => for payload in payloads.iter() { handle_payload(payload) },
_ => {},
}
}
/// Get the root node's RLP.
fn root_node(&self) -> Node {
Node::decoded(self.db.lookup(&self.root).expect("Trie root not found!"))
}
/// Get the root node as a `Node`.
fn get_node<'a>(&'a self, node: &'a [u8]) -> Node {
Node::decoded(self.get_raw_or_lookup(node))
}
/// Indentation helper for `formal_all`.
fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result {
for _ in 0..size {
try!(write!(f, " "));
}
Ok(())
}
/// Recursion helper for implementation of formatting trait.
fn fmt_all(&self, node: Node, f: &mut fmt::Formatter, deepness: usize) -> fmt::Result {
match node {
Node::Leaf(slice, value) => try!(writeln!(f, "'{:?}: {:?}.", slice, value.pretty())),
Node::Extension(ref slice, ref item) => {
try!(write!(f, "'{:?} ", slice));
try!(self.fmt_all(self.get_node(item), f, deepness));
},
Node::Branch(ref nodes, ref value) => {
try!(writeln!(f, ""));
match value {
&Some(v) => {
try!(self.fmt_indent(f, deepness + 1));
try!(writeln!(f, "=: {:?}", v.pretty()))
},
&None => {}
}
for i in 0..16 {
match self.get_node(nodes[i]) {
Node::Empty => {},
n => {
try!(self.fmt_indent(f, deepness + 1));
try!(write!(f, "'{:x} ", i));
try!(self.fmt_all(n, f, deepness + 1));
}
}
}
},
// empty
Node::Empty => {
try!(writeln!(f, "<empty>"));
}
};
Ok(())
}
/// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists.
fn do_lookup<'a, 'key>(&'a self, key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key {
let root_rlp = self.db.lookup(&self.root).expect("Trie root not found!");
self.get_from_node(&root_rlp, key)
}
/// Recursible function to retrieve the value given a `node` and a partial `key`. `None` if no
/// value exists for the key.
///
/// Note: Not a public API; use Trie trait functions.
fn get_from_node<'a, 'key>(&'a self, node: &'a [u8], key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key {
match Node::decoded(node) {
Node::Leaf(ref slice, ref value) if key == slice => Some(value),
Node::Extension(ref slice, ref item) if key.starts_with(slice) => {
self.get_from_node(self.get_raw_or_lookup(item), &key.mid(slice.len()))
},
Node::Branch(ref nodes, value) => match key.is_empty() {
true => value,
false => self.get_from_node(self.get_raw_or_lookup(nodes[key.at(0) as usize]), &key.mid(1))
},
_ => None
}
}
/// Given some node-describing data `node`, return the actual node RLP.
/// This could be a simple identity operation in the case that the node is sufficiently small, but
/// may require a database lookup.
fn get_raw_or_lookup<'a>(&'a self, node: &'a [u8]) -> &'a [u8] {
// check if its sha3 + len
let r = Rlp::new(node);
match r.is_data() && r.size() == 32 {
true => self.db.lookup(&r.as_val::<H256>()).expect("Not found!"),
false => node
}
}
}
impl<'db> Trie for TrieDB<'db> {
fn root(&self) -> &H256 { &self.root }
fn contains(&self, key: &[u8]) -> bool {
self.get(key).is_some()
}
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.do_lookup(&NibbleSlice::new(key))
}
}
impl<'db> fmt::Debug for TrieDB<'db> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(writeln!(f, "c={:?} [", self.hash_count));
let root_rlp = self.db.lookup(&self.root).expect("Trie root not found!");
try!(self.fmt_all(Node::decoded(root_rlp), f, 0));
writeln!(f, "]")
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +0,0 @@
use hash::H256;
use rlp::SHA3_NULL_RLP;
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait Trie {
/// Return the root of the trie.
fn root(&self) -> &H256;
/// Is the trie empty?
fn is_empty(&self) -> bool { *self.root() == SHA3_NULL_RLP }
/// Does the trie contain a given key?
fn contains(&self, key: &[u8]) -> bool;
/// What is the value of the given key in this trie?
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key;
}
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait TrieMut: Trie {
/// Insert a `key`/`value` pair into the trie. An `empty` value is equivalent to removing
/// `key` from the trie.
fn insert(&mut self, key: &[u8], value: &[u8]);
/// Remove a `key` from the trie. Equivalent to making it equal to the empty
/// value.
fn remove(&mut self, key: &[u8]);
}

View File

@@ -1,337 +0,0 @@
//! Generetes trie root.
//!
//! This module should be used to generate trie root hash.
use std::collections::BTreeMap;
use std::cmp;
use hash::*;
use sha3::*;
use rlp;
use rlp::{RlpStream, Stream};
use vector::SharedPrefix;
/// Generates a trie root hash for a vector of values
///
/// ```rust
/// extern crate ethcore_util as util;
/// use std::str::FromStr;
/// use util::triehash::*;
/// use util::hash::*;
///
/// fn main() {
/// let v = vec![From::from("doe"), From::from("reindeer")];
/// let root = "e766d5d51b89dc39d981b41bda63248d7abce4f0225eefd023792a540bcffee3";
/// assert_eq!(ordered_trie_root(v), H256::from_str(root).unwrap());
/// }
/// ```
pub fn ordered_trie_root(input: Vec<Vec<u8>>) -> H256 {
let gen_input = input
// first put elements into btree to sort them by nibbles
// optimize it later
.into_iter()
.enumerate()
.fold(BTreeMap::new(), | mut acc, (i, vec) | { acc.insert(rlp::encode(&i), vec); acc })
// then move them to a vector
.into_iter()
.map(|(k, v)| (as_nibbles(&k), v) )
.collect();
gen_trie_root(gen_input)
}
/// Generates a trie root hash for a vector of key-values
///
/// ```rust
/// extern crate ethcore_util as util;
/// use std::str::FromStr;
/// use util::triehash::*;
/// use util::hash::*;
///
/// fn main() {
/// let v = vec![
/// (From::from("doe"), From::from("reindeer")),
/// (From::from("dog"), From::from("puppy")),
/// (From::from("dogglesworth"), From::from("cat")),
/// ];
///
/// let root = "8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3";
/// assert_eq!(trie_root(v), H256::from_str(root).unwrap());
/// }
/// ```
pub fn trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
let gen_input = input
// first put elements into btree to sort them and to remove duplicates
.into_iter()
.fold(BTreeMap::new(), | mut acc, (k, v) | {
acc.insert(k, v);
acc
})
// then move them to a vector
.into_iter()
.map(|(k, v)| (as_nibbles(&k), v) )
.collect();
gen_trie_root(gen_input)
}
/// Generates a key-hashed (secure) trie root hash for a vector of key-values.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use std::str::FromStr;
/// use util::triehash::*;
/// use util::hash::*;
///
/// fn main() {
/// let v = vec![
/// (From::from("doe"), From::from("reindeer")),
/// (From::from("dog"), From::from("puppy")),
/// (From::from("dogglesworth"), From::from("cat")),
/// ];
///
/// let root = "d4cd937e4a4368d7931a9cf51686b7e10abb3dce38a39000fd7902a092b64585";
/// assert_eq!(sec_trie_root(v), H256::from_str(root).unwrap());
/// }
/// ```
pub fn sec_trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
let gen_input = input
// first put elements into btree to sort them and to remove duplicates
.into_iter()
.fold(BTreeMap::new(), | mut acc, (k, v) | {
acc.insert(k.sha3().to_vec(), v);
acc
})
// then move them to a vector
.into_iter()
.map(|(k, v)| (as_nibbles(&k), v) )
.collect();
gen_trie_root(gen_input)
}
fn gen_trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
let mut stream = RlpStream::new();
hash256rlp(&input, 0, &mut stream);
stream.out().sha3()
}
/// Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1.
///
/// The "termination marker" and "leaf-node" specifier are completely equivalent.
///
/// Input values are in range `[0, 0xf]`.
///
/// ```markdown
/// [0,0,1,2,3,4,5] 0x10012345 // 7 > 4
/// [0,1,2,3,4,5] 0x00012345 // 6 > 4
/// [1,2,3,4,5] 0x112345 // 5 > 3
/// [0,0,1,2,3,4] 0x00001234 // 6 > 3
/// [0,1,2,3,4] 0x101234 // 5 > 3
/// [1,2,3,4] 0x001234 // 4 > 3
/// [0,0,1,2,3,4,5,T] 0x30012345 // 7 > 4
/// [0,0,1,2,3,4,T] 0x20001234 // 6 > 4
/// [0,1,2,3,4,5,T] 0x20012345 // 6 > 4
/// [1,2,3,4,5,T] 0x312345 // 5 > 3
/// [1,2,3,4,T] 0x201234 // 4 > 3
/// ```
fn hex_prefix_encode(nibbles: &[u8], leaf: bool) -> Vec<u8> {
let inlen = nibbles.len();
let oddness_factor = inlen % 2;
// next even number divided by two
let reslen = (inlen + 2) >> 1;
let mut res = vec![];
res.reserve(reslen);
let first_byte = {
let mut bits = ((inlen as u8 & 1) + (2 * leaf as u8)) << 4;
if oddness_factor == 1 {
bits += nibbles[0];
}
bits
};
res.push(first_byte);
let mut offset = oddness_factor;
while offset < inlen {
let byte = (nibbles[offset] << 4) + nibbles[offset + 1];
res.push(byte);
offset += 2;
}
res
}
/// Converts slice of bytes to nibbles.
fn as_nibbles(bytes: &[u8]) -> Vec<u8> {
let mut res = vec![];
res.reserve(bytes.len() * 2);
for i in 0..bytes.len() {
res.push(bytes[i] >> 4);
res.push((bytes[i] << 4) >> 4);
}
res
}
fn hash256rlp(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStream) {
let inlen = input.len();
// in case of empty slice, just append empty data
if inlen == 0 {
stream.append_empty_data();
return;
}
// take slices
let key: &Vec<u8> = &input[0].0;
let value: &[u8] = &input[0].1;
// if the slice contains just one item, append the suffix of the key
// and then append value
if inlen == 1 {
stream.append_list(2);
stream.append(&hex_prefix_encode(&key[pre_len..], true));
stream.append(&value);
return;
}
// get length of the longest shared prefix in slice keys
let shared_prefix = input.iter()
// skip first element
.skip(1)
// get minimum number of shared nibbles between first and each successive
.fold(key.len(), | acc, &(ref k, _) | {
cmp::min(key.shared_prefix_len(&k), acc)
});
// if shared prefix is higher than current prefix append its
// new part of the key to the stream
// then recursively append suffixes of all items who had this key
if shared_prefix > pre_len {
stream.append_list(2);
stream.append(&hex_prefix_encode(&key[pre_len..shared_prefix], false));
hash256aux(input, shared_prefix, stream);
return;
}
// an item for every possible nibble/suffix
// + 1 for data
stream.append_list(17);
// if first key len is equal to prefix_len, move to next element
let mut begin = match pre_len == key.len() {
true => 1,
false => 0
};
// iterate over all possible nibbles
for i in 0..16 {
// 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 )
.count(),
false => 0
};
// if at least 1 successive element has the same nibble
// append their suffixes
match len {
0 => { stream.append_empty_data(); },
_ => hash256aux(&input[begin..(begin + len)], pre_len + 1, stream)
}
begin += len;
}
// if fist key len is equal prefix, append it's value
match pre_len == key.len() {
true => { stream.append(&value); },
false => { stream.append_empty_data(); }
};
}
fn hash256aux(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStream) {
let mut s = RlpStream::new();
hash256rlp(input, pre_len, &mut s);
let out = s.out();
match out.len() {
0...31 => stream.append_raw(&out, 1),
_ => stream.append(&out.sha3())
};
}
#[test]
fn test_nibbles() {
let v = vec![0x31, 0x23, 0x45];
let e = vec![3, 1, 2, 3, 4, 5];
assert_eq!(as_nibbles(&v), e);
// A => 65 => 0x41 => [4, 1]
let v: Vec<u8> = From::from("A");
let e = vec![4, 1];
assert_eq!(as_nibbles(&v), e);
}
#[test]
fn test_hex_prefix_encode() {
let v = vec![0, 0, 1, 2, 3, 4, 5];
let e = vec![0x10, 0x01, 0x23, 0x45];
let h = hex_prefix_encode(&v, false);
assert_eq!(h, e);
let v = vec![0, 1, 2, 3, 4, 5];
let e = vec![0x00, 0x01, 0x23, 0x45];
let h = hex_prefix_encode(&v, false);
assert_eq!(h, e);
let v = vec![0, 1, 2, 3, 4, 5];
let e = vec![0x20, 0x01, 0x23, 0x45];
let h = hex_prefix_encode(&v, true);
assert_eq!(h, e);
let v = vec![1, 2, 3, 4, 5];
let e = vec![0x31, 0x23, 0x45];
let h = hex_prefix_encode(&v, true);
assert_eq!(h, e);
let v = vec![1, 2, 3, 4];
let e = vec![0x00, 0x12, 0x34];
let h = hex_prefix_encode(&v, false);
assert_eq!(h, e);
let v = vec![4, 1];
let e = vec![0x20, 0x41];
let h = hex_prefix_encode(&v, true);
assert_eq!(h, e);
}
#[cfg(test)]
mod tests {
extern crate json_tests;
use self::json_tests::*;
use hash::*;
use triehash::*;
#[test]
fn test_triehash_out_of_order() {
assert!(trie_root(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]),
]) ==
trie_root(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]),
(vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
]));
}
#[test]
fn test_triehash_json() {
execute_tests_from_directory::<trie::TriehashTest, _>("json-tests/json/trie/*.json", &mut | file, input, output | {
println!("file: {}, output: {:?}", file, output);
assert_eq!(trie_root(input), H256::from_slice(&output));
});
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,85 +0,0 @@
//! vector util functions
use std::ptr;
pub trait InsertSlice<T> {
fn insert_slice(&mut self, index: usize, elements: &[T]);
}
/// based on `insert` function implementation from standard library
impl<T> InsertSlice<T> for Vec<T> {
fn insert_slice(&mut self, index: usize, elements: &[T]) {
let e_len = elements.len();
if e_len == 0 {
return;
}
let len = self.len();
assert!(index <= len);
// space for the new element
self.reserve(e_len);
unsafe {
{
let p = self.as_mut_ptr().offset(index as isize);
let ep = elements.as_ptr().offset(0);
// shift everything by e_len, to make space
ptr::copy(p, p.offset(e_len as isize), len - index);
// write new element
ptr::copy(ep, p, e_len);
}
self.set_len(len + e_len);
}
}
}
/// Returns len of prefix shared with elem
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::vector::SharedPrefix;
///
/// fn main () {
/// let a = vec![1,2,3,3,5];
/// let b = vec![1,2,3];
/// assert_eq!(a.shared_prefix_len(&b), 3);
/// }
/// ```
pub trait SharedPrefix <T> {
fn shared_prefix_len(&self, elem: &[T]) -> usize;
}
impl <T> SharedPrefix<T> for Vec<T> where T: Eq {
fn shared_prefix_len(&self, elem: &[T]) -> usize {
use std::cmp;
let len = cmp::min(self.len(), elem.len());
(0..len).take_while(|&i| self[i] == elem[i]).count()
}
}
#[cfg(test)]
mod test {
use vector::SharedPrefix;
#[test]
fn test_shared_prefix() {
let a = vec![1,2,3,4,5,6];
let b = vec![4,2,3,4,5,6];
assert_eq!(a.shared_prefix_len(&b), 0);
}
#[test]
fn test_shared_prefix2() {
let a = vec![1,2,3,3,5];
let b = vec![1,2,3];
assert_eq!(a.shared_prefix_len(&b), 3);
}
#[test]
fn test_shared_prefix3() {
let a = vec![1,2,3,4,5,6];
let b = vec![1,2,3,4,5,6];
assert_eq!(a.shared_prefix_len(&b), 6);
}
}

Some files were not shown because too many files have changed in this diff Show More