Merge branch 'master' into clippy

Conflicts:
	src/service.rs
	src/views.rs
This commit is contained in:
Tomusdrw
2016-01-19 10:18:18 +01:00
32 changed files with 733 additions and 309 deletions

View File

@@ -1,6 +1,7 @@
use common::*;
use engine::*;
use state::*;
use verification::PreVerifiedBlock;
/// A transaction/receipt execution entry.
pub struct Entry {
@@ -263,30 +264,39 @@ 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> {
/// Enact the block given by block header, transactions and uncles
pub fn enact<'x, 'y>(header: &Header, transactions: &[Transaction], uncles: &[Header], 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());
let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author().clone(), header.extra_data().clone());
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)); }
for t in transactions { try!(b.push_transaction(t.clone(), None)); }
for u in uncles { try!(b.push_uncle(u.clone())); }
Ok(b.close())
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
pub fn enact_bytes<'x, 'y>(block_bytes: &[u8], engine: &'x Engine, db: OverlayDB, parent: &Header, last_hashes: &'y LastHashes) -> Result<ClosedBlock<'x, 'y>, Error> {
let block = BlockView::new(block_bytes);
let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
pub fn enact_verified<'x, 'y>(block: &PreVerifiedBlock, engine: &'x Engine, db: OverlayDB, parent: &Header, last_hashes: &'y LastHashes) -> Result<ClosedBlock<'x, 'y>, Error> {
let view = BlockView::new(&block.bytes);
enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes)
}
/// 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())))
Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(header.seal())))
}
#[test]

View File

@@ -88,7 +88,7 @@ pub trait BlockChainClient : Sync + Send {
fn block_receipts(&self, hash: &H256) -> Option<Bytes>;
/// Import a block into the blockchain.
fn import_block(&mut self, byte: &[u8]) -> ImportResult;
fn import_block(&mut self, bytes: Bytes) -> ImportResult;
/// Get block queue information.
fn queue_status(&self) -> BlockQueueStatus;
@@ -152,58 +152,75 @@ impl Client {
}
/// 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());
pub fn import_verified_blocks(&mut self) {
let mut bad = HashSet::new();
let blocks = self.queue.drain(128);
if blocks.is_empty() {
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);
}
for block in blocks {
if bad.contains(&block.header.parent_hash) {
self.queue.mark_as_bad(&block.header.hash());
bad.insert(block.header.hash());
continue;
}
let header = &block.header;
if let Err(e) = verify_block_family(&header, &block.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());
bad.insert(block.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();
};
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());
bad.insert(block.header.hash());
return;
},
None => break,
};
// 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);
let result = match enact_verified(&block, 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);
bad.insert(block.header.hash());
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;
}
};
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;
self.chain.write().unwrap().insert_block(&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());
}
info!(target: "client", "Imported #{} ({})", header.number(), header.hash());
}
}
@@ -261,8 +278,8 @@ impl BlockChainClient for Client {
unimplemented!();
}
fn import_block(&mut self, bytes: &[u8]) -> ImportResult {
let header = BlockView::new(bytes).header();
fn import_block(&mut self, bytes: Bytes) -> ImportResult {
let header = BlockView::new(&bytes).header();
if self.chain.read().unwrap().is_known(&header.hash()) {
return Err(ImportError::AlreadyInChain);
}

View File

@@ -146,6 +146,10 @@ impl Engine for Ethash {
}
Ok(())
}
fn verify_transaction(&self, t: &Transaction, _header: &Header) -> Result<(), Error> {
t.sender().map(|_|()) // Perform EC recovery and cache sender
}
}
impl Ethash {

View File

@@ -27,6 +27,14 @@ fn color(instruction: Instruction, name: &'static str) -> String {
format!("\x1B[1;{}m{}\x1B[0m", colors[c], name)
}
macro_rules! overflowing {
($x: expr) => {{
let (v, overflow) = $x;
if overflow { return Err(evm::Error::OutOfGas); }
v
}}
}
type CodePosition = usize;
type Gas = U256;
type ProgramCounter = usize;
@@ -136,7 +144,7 @@ trait Memory {
/// Checks whether offset and size is valid memory range
fn is_valid_range(off: usize, size: usize) -> bool {
// When size is zero we haven't actually expanded the memory
let (_a, overflow) = off.overflowing_add(size);
let overflow = off.overflowing_add(size).1;
size > 0 && !overflow
}
@@ -235,15 +243,10 @@ impl<'a> CodeReader<'a> {
}
}
enum RequiredMem {
Mem(U256),
OutOfMemory
}
enum InstructionCost {
Gas(U256),
GasMem(U256, RequiredMem),
GasMemCopy(U256, RequiredMem, U256)
GasMem(U256, U256),
GasMemCopy(U256, U256, U256)
}
enum InstructionResult {
@@ -373,35 +376,31 @@ impl Interpreter {
InstructionCost::Gas(U256::from(schedule.sload_gas))
},
instructions::MSTORE => {
InstructionCost::GasMem(default_gas, self.mem_needed_const(stack.peek(0), 32))
InstructionCost::GasMem(default_gas, try!(self.mem_needed_const(stack.peek(0), 32)))
},
instructions::MLOAD => {
InstructionCost::GasMem(default_gas, self.mem_needed_const(stack.peek(0), 32))
InstructionCost::GasMem(default_gas, try!(self.mem_needed_const(stack.peek(0), 32)))
},
instructions::MSTORE8 => {
InstructionCost::GasMem(default_gas, self.mem_needed_const(stack.peek(0), 1))
InstructionCost::GasMem(default_gas, try!(self.mem_needed_const(stack.peek(0), 1)))
},
instructions::RETURN => {
InstructionCost::GasMem(default_gas, self.mem_needed(stack.peek(0), stack.peek(1)))
InstructionCost::GasMem(default_gas, try!(self.mem_needed(stack.peek(0), stack.peek(1))))
},
instructions::SHA3 => {
match add_u256_usize(stack.peek(1), 31) {
(_w, true) => InstructionCost::GasMem(U256::zero(), RequiredMem::OutOfMemory),
(w, false) => {
let words = w >> 5;
let gas = U256::from(schedule.sha3_gas) + (U256::from(schedule.sha3_word_gas) * words);
InstructionCost::GasMem(gas, self.mem_needed(stack.peek(0), stack.peek(1)))
}
}
let w = overflowing!(add_u256_usize(stack.peek(1), 31));
let words = w >> 5;
let gas = U256::from(schedule.sha3_gas) + (U256::from(schedule.sha3_word_gas) * words);
InstructionCost::GasMem(gas, try!(self.mem_needed(stack.peek(0), stack.peek(1))))
},
instructions::CALLDATACOPY => {
InstructionCost::GasMemCopy(default_gas, self.mem_needed(stack.peek(0), stack.peek(2)), stack.peek(2).clone())
InstructionCost::GasMemCopy(default_gas, try!(self.mem_needed(stack.peek(0), stack.peek(2))), stack.peek(2).clone())
},
instructions::CODECOPY => {
InstructionCost::GasMemCopy(default_gas, self.mem_needed(stack.peek(0), stack.peek(2)), stack.peek(2).clone())
InstructionCost::GasMemCopy(default_gas, try!(self.mem_needed(stack.peek(0), stack.peek(2))), stack.peek(2).clone())
},
instructions::EXTCODECOPY => {
InstructionCost::GasMemCopy(default_gas, self.mem_needed(stack.peek(1), stack.peek(3)), stack.peek(3).clone())
InstructionCost::GasMemCopy(default_gas, try!(self.mem_needed(stack.peek(1), stack.peek(3))), stack.peek(3).clone())
},
instructions::JUMPDEST => {
InstructionCost::Gas(U256::one())
@@ -409,50 +408,41 @@ impl Interpreter {
instructions::LOG0...instructions::LOG4 => {
let no_of_topics = instructions::get_log_topics(instruction);
let log_gas = schedule.log_gas + schedule.log_topic_gas * no_of_topics;
// TODO [todr] potential overflow of datagass
let data_gas = stack.peek(1).clone() * U256::from(schedule.log_data_gas);
let gas = try!(self.gas_add(data_gas, U256::from(log_gas)));
InstructionCost::GasMem(gas, self.mem_needed(stack.peek(0), stack.peek(1)))
let data_gas = overflowing!(stack.peek(1).overflowing_mul(U256::from(schedule.log_data_gas)));
let gas = overflowing!(data_gas.overflowing_add(U256::from(log_gas)));
InstructionCost::GasMem(gas, try!(self.mem_needed(stack.peek(0), stack.peek(1))))
},
instructions::CALL | instructions::CALLCODE => {
match add_u256_usize(stack.peek(0), schedule.call_gas) {
(_gas, true) => InstructionCost::GasMem(U256::zero(), RequiredMem::OutOfMemory),
(mut gas, false) => {
let mem = self.mem_max(
self.mem_needed(stack.peek(5), stack.peek(6)),
self.mem_needed(stack.peek(3), stack.peek(4))
);
let address = u256_to_address(stack.peek(1));
let mut gas = overflowing!(add_u256_usize(stack.peek(0), schedule.call_gas));
let mem = cmp::max(
try!(self.mem_needed(stack.peek(5), stack.peek(6))),
try!(self.mem_needed(stack.peek(3), stack.peek(4)))
);
let address = u256_to_address(stack.peek(1));
// TODO [todr] Potential overflows
if instruction == instructions::CALL && !ext.exists(&address) {
gas = gas + U256::from(schedule.call_new_account_gas);
};
if instruction == instructions::CALL && !ext.exists(&address) {
gas = overflowing!(gas.overflowing_add(U256::from(schedule.call_new_account_gas)));
};
if stack.peek(2).clone() > U256::zero() {
gas = gas + U256::from(schedule.call_value_transfer_gas)
};
if stack.peek(2).clone() > U256::zero() {
gas = overflowing!(gas.overflowing_add(U256::from(schedule.call_value_transfer_gas)));
};
InstructionCost::GasMem(gas,mem)
}
}
InstructionCost::GasMem(gas,mem)
},
instructions::DELEGATECALL => {
match add_u256_usize(stack.peek(0), schedule.call_gas) {
(_gas, true) => InstructionCost::GasMem(U256::zero(), RequiredMem::OutOfMemory),
(gas, false) => {
let mem = self.mem_max(
self.mem_needed(stack.peek(4), stack.peek(5)),
self.mem_needed(stack.peek(2), stack.peek(3))
);
InstructionCost::GasMem(gas, mem)
}
}
let gas = overflowing!(add_u256_usize(stack.peek(0), schedule.call_gas));
let mem = cmp::max(
try!(self.mem_needed(stack.peek(4), stack.peek(5))),
try!(self.mem_needed(stack.peek(2), stack.peek(3)))
);
InstructionCost::GasMem(gas, mem)
},
instructions::CREATE => {
let gas = U256::from(schedule.create_gas);
let mem = self.mem_needed(stack.peek(1), stack.peek(2));
let mem = try!(self.mem_needed(stack.peek(1), stack.peek(2)));
InstructionCost::GasMem(gas, mem)
},
instructions::EXP => {
@@ -468,84 +458,57 @@ impl Interpreter {
InstructionCost::Gas(gas) => {
Ok((gas, 0))
},
InstructionCost::GasMem(gas, mem_size) => match mem_size {
RequiredMem::Mem(mem_size) => {
let (mem_gas, new_mem_size) = self.mem_gas_cost(schedule, mem.size(), &mem_size);
let gas = try!(self.gas_add(gas, mem_gas));
Ok((gas, new_mem_size))
},
RequiredMem::OutOfMemory => Err(evm::Error::OutOfGas)
InstructionCost::GasMem(gas, mem_size) => {
let (mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, mem.size(), &mem_size));
let gas = overflowing!(gas.overflowing_add(mem_gas));
Ok((gas, new_mem_size))
},
InstructionCost::GasMemCopy(gas, mem_size, copy) => match mem_size {
RequiredMem::Mem(mem_size) => {
let (mem_gas, new_mem_size) = self.mem_gas_cost(schedule, mem.size(), &mem_size);
match add_u256_usize(&copy, 31) {
(_c, true) => Err(evm::Error::OutOfGas),
(copy, false) => {
let copy_gas = U256::from(schedule.copy_gas) * (copy / U256::from(32));
let gas = try!(self.gas_add(try!(self.gas_add(gas, copy_gas)), mem_gas));
Ok((gas, new_mem_size))
}
}
},
RequiredMem::OutOfMemory => Err(evm::Error::OutOfGas)
InstructionCost::GasMemCopy(gas, mem_size, copy) => {
let (mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, mem.size(), &mem_size));
let copy = overflowing!(add_u256_usize(&copy, 31));
let copy_gas = U256::from(schedule.copy_gas) * (copy / U256::from(32));
let gas = overflowing!(gas.overflowing_add(copy_gas));
let gas = overflowing!(gas.overflowing_add(mem_gas));
Ok((gas, new_mem_size))
}
}
}
fn gas_add(&self, a: U256, b: U256) -> Result<U256, evm::Error> {
match a.overflowing_add(b) {
(_val, true) => Err(evm::Error::OutOfGas),
(val, false) => Ok(val)
}
}
fn mem_gas_cost(&self, schedule: &evm::Schedule, current_mem_size: usize, mem_size: &U256) -> (U256, usize) {
fn mem_gas_cost(&self, schedule: &evm::Schedule, current_mem_size: usize, mem_size: &U256) -> Result<(U256, usize), evm::Error> {
let gas_for_mem = |mem_size: U256| {
let s = mem_size >> 5;
s * U256::from(schedule.memory_gas) + s * s / U256::from(schedule.quad_coeff_div)
// s * memory_gas + s * s / quad_coeff_div
let a = overflowing!(s.overflowing_mul(U256::from(schedule.memory_gas)));
// We need to go to U512 to calculate s*s/quad_coeff_div
let b = U512::from(s) * U512::from(s) / U512::from(schedule.quad_coeff_div);
if b > U512::from(!U256::zero()) {
Err(evm::Error::OutOfGas)
} else {
Ok(overflowing!(a.overflowing_add(U256::from(b))))
}
};
let current_mem_size = U256::from(current_mem_size);
let req_mem_size_rounded = ((mem_size.clone() + U256::from(31)) >> 5) << 5;
let new_mem_gas = gas_for_mem(U256::from(req_mem_size_rounded));
let current_mem_gas = gas_for_mem(current_mem_size);
let req_mem_size_rounded = (overflowing!(mem_size.overflowing_add(U256::from(31))) >> 5) << 5;
let new_mem_gas = try!(gas_for_mem(U256::from(req_mem_size_rounded)));
let current_mem_gas = try!(gas_for_mem(current_mem_size));
(if req_mem_size_rounded > current_mem_size {
Ok((if req_mem_size_rounded > current_mem_size {
new_mem_gas - current_mem_gas
} else {
U256::zero()
}, req_mem_size_rounded.low_u64() as usize)
}, req_mem_size_rounded.low_u64() as usize))
}
fn mem_max(&self, m_a: RequiredMem, m_b: RequiredMem) -> RequiredMem {
match (m_a, m_b) {
(RequiredMem::Mem(a), RequiredMem::Mem(b)) => {
RequiredMem::Mem(cmp::max(a, b))
},
(RequiredMem::OutOfMemory, _) | (_, RequiredMem::OutOfMemory) => {
RequiredMem::OutOfMemory
}
}
fn mem_needed_const(&self, mem: &U256, add: usize) -> Result<U256, evm::Error> {
Ok(overflowing!(mem.overflowing_add(U256::from(add))))
}
fn mem_needed_const(&self, mem: &U256, add: usize) -> RequiredMem {
match mem.overflowing_add(U256::from(add)) {
(_, true) => RequiredMem::OutOfMemory,
(mem, false) => RequiredMem::Mem(mem)
}
}
fn mem_needed(&self, offset: &U256, size: &U256) -> RequiredMem {
fn mem_needed(&self, offset: &U256, size: &U256) -> Result<U256, ::evm::Error> {
if self.is_zero(size) {
return RequiredMem::Mem(U256::zero());
return Ok(U256::zero());
}
match offset.clone().overflowing_add(size.clone()) {
(_result, true) => RequiredMem::OutOfMemory,
(result, false) => {
RequiredMem::Mem(result)
}
}
Ok(overflowing!(offset.overflowing_add(size.clone())))
}
fn exec_instruction(&self,
@@ -646,7 +609,6 @@ impl Interpreter {
return match call_result {
MessageCallResult::Success(gas_left) => {
println!("Unused: {}", gas_left);
stack.push(U256::one());
Ok(InstructionResult::UnusedGas(gas_left))
},
@@ -906,41 +868,34 @@ impl Interpreter {
instructions::ADD => {
let a = stack.pop_back();
let b = stack.pop_back();
let (c, _overflow) = a.overflowing_add(b);
stack.push(c);
stack.push(a.overflowing_add(b).0);
},
instructions::MUL => {
let a = stack.pop_back();
let b = stack.pop_back();
let (c, _overflow) = a.overflowing_mul(b);
stack.push(c);
stack.push(a.overflowing_mul(b).0);
},
instructions::SUB => {
let a = stack.pop_back();
let b = stack.pop_back();
let (c, _overflow) = a.overflowing_sub(b);
stack.push(c);
stack.push(a.overflowing_sub(b).0);
},
instructions::DIV => {
let a = stack.pop_back();
let b = stack.pop_back();
stack.push(match !self.is_zero(&b) {
true => {
let (c, _overflow) = a.overflowing_div(b);
c
},
false => U256::zero()
stack.push(if !self.is_zero(&b) {
a.overflowing_div(b).0
} else {
U256::zero()
});
},
instructions::MOD => {
let a = stack.pop_back();
let b = stack.pop_back();
stack.push(match !self.is_zero(&b) {
true => {
let (c, _overflow) = a.overflowing_rem(b);
c
},
false => U256::zero()
stack.push(if !self.is_zero(&b) {
a.overflowing_rem(b).0
} else {
U256::zero()
});
},
instructions::SDIV => {
@@ -954,7 +909,7 @@ impl Interpreter {
} else if a == min && b == !U256::zero() {
min
} else {
let (c, _overflow) = a.overflowing_div(b);
let c = a.overflowing_div(b).0;
set_sign(c, sign_a ^ sign_b)
});
},
@@ -962,10 +917,10 @@ impl Interpreter {
let ua = stack.pop_back();
let ub = stack.pop_back();
let (a, sign_a) = get_and_reset_sign(ua);
let (b, _sign_b) = get_and_reset_sign(ub);
let b = get_and_reset_sign(ub).0;
stack.push(if !self.is_zero(&b) {
let (c, _overflow) = a.overflowing_rem(b);
let c = a.overflowing_rem(b).0;
set_sign(c, sign_a)
} else {
U256::zero()
@@ -974,7 +929,7 @@ impl Interpreter {
instructions::EXP => {
let base = stack.pop_back();
let expon = stack.pop_back();
let (res, _overflow) = base.overflowing_pow(expon);
let res = base.overflowing_pow(expon).0;
stack.push(res);
},
instructions::NOT => {
@@ -1052,8 +1007,8 @@ impl Interpreter {
stack.push(if !self.is_zero(&c) {
// upcast to 512
let a5 = U512::from(a);
let (res, _overflow) = a5.overflowing_add(U512::from(b));
let (x, _overflow) = res.overflowing_rem(U512::from(c));
let res = a5.overflowing_add(U512::from(b)).0;
let x = res.overflowing_rem(U512::from(c)).0;
U256::from(x)
} else {
U256::zero()
@@ -1066,8 +1021,8 @@ impl Interpreter {
stack.push(if !self.is_zero(&c) {
let a5 = U512::from(a);
let (res, _overflow) = a5.overflowing_mul(U512::from(b));
let (x, _overflow) = res.overflowing_rem(U512::from(c));
let res = a5.overflowing_mul(U512::from(b)).0;
let x = res.overflowing_rem(U512::from(c)).0;
U256::from(x)
} else {
U256::zero()
@@ -1123,8 +1078,7 @@ fn get_and_reset_sign(value: U256) -> (U256, bool) {
fn set_sign(value: U256, sign: bool) -> U256 {
if sign {
let (val, _overflow) = (!U256::zero() ^ value).overflowing_add(U256::one());
val
(!U256::zero() ^ value).overflowing_add(U256::one()).0
} else {
value
}
@@ -1145,6 +1099,23 @@ fn address_to_u256(value: Address) -> U256 {
U256::from(H256::from(value).as_slice())
}
#[test]
fn test_mem_gas_cost() {
// given
let interpreter = Interpreter;
let schedule = evm::Schedule::default();
let current_mem_size = 5;
let mem_size = !U256::zero();
// when
let result = interpreter.mem_gas_cost(&schedule, current_mem_size, &mem_size);
// then
if let Ok(_) = result {
assert!(false, "Should fail with OutOfGas");
}
}
#[cfg(test)]
mod tests {
use common::*;
@@ -1173,7 +1144,7 @@ mod tests {
let mem_size = U256::from(5);
// when
let (mem_cost, mem_size) = interpreter.mem_gas_cost(&schedule, current_mem_size, &mem_size);
let (mem_cost, mem_size) = interpreter.mem_gas_cost(&schedule, current_mem_size, &mem_size).unwrap();
// then
assert_eq!(mem_cost, U256::from(3));

View File

@@ -171,7 +171,7 @@ impl<'a> Executive<'a> {
// 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);
trace!("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

View File

@@ -82,6 +82,7 @@ extern crate heapsize;
extern crate crypto;
extern crate time;
extern crate env_logger;
extern crate num_cpus;
#[cfg(feature = "jit" )]
extern crate evmjit;
#[macro_use]

View File

@@ -1,59 +1,245 @@
use std::thread::{JoinHandle, self};
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
use util::*;
use verification::*;
use error::*;
use engine::Engine;
use sync::*;
use views::*;
use header::*;
/// 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>>,
more_to_verify: Arc<Condvar>,
verification: Arc<Mutex<Verification>>,
verifiers: Vec<JoinHandle<()>>,
deleting: Arc<AtomicBool>,
ready_signal: Arc<QueueSignal>,
processing: HashSet<H256>
}
struct UnVerifiedBlock {
header: Header,
bytes: Bytes,
}
struct VerifyingBlock {
hash: H256,
block: Option<PreVerifiedBlock>,
}
struct QueueSignal {
signalled: AtomicBool,
message_channel: IoChannel<NetSyncMessage>,
}
impl QueueSignal {
fn set(&self) {
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message");
}
}
fn reset(&self) {
self.signalled.store(false, AtomicOrdering::Relaxed);
}
}
#[derive(Default)]
struct Verification {
unverified: VecDeque<UnVerifiedBlock>,
verified: VecDeque<PreVerifiedBlock>,
verifying: VecDeque<VerifyingBlock>,
bad: HashSet<H256>,
}
impl BlockQueue {
/// Creates a new queue instance.
pub fn new(engine: Arc<Box<Engine>>, message_channel: IoChannel<NetSyncMessage>) -> BlockQueue {
let verification = Arc::new(Mutex::new(Verification::default()));
let more_to_verify = Arc::new(Condvar::new());
let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel });
let deleting = Arc::new(AtomicBool::new(false));
let mut verifiers: Vec<JoinHandle<()>> = Vec::new();
let thread_count = max(::num_cpus::get(), 2) - 1;
for _ in 0..thread_count {
let verification = verification.clone();
let engine = engine.clone();
let more_to_verify = more_to_verify.clone();
let ready_signal = ready_signal.clone();
let deleting = deleting.clone();
verifiers.push(thread::spawn(move || BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting)));
}
BlockQueue {
engine: engine,
message_channel: message_channel,
bad: HashSet::new(),
ready_signal: ready_signal.clone(),
more_to_verify: more_to_verify.clone(),
verification: verification.clone(),
verifiers: verifiers,
deleting: deleting.clone(),
processing: HashSet::new(),
}
}
fn verify(verification: Arc<Mutex<Verification>>, engine: Arc<Box<Engine>>, wait: Arc<Condvar>, ready: Arc<QueueSignal>, deleting: Arc<AtomicBool>) {
while !deleting.load(AtomicOrdering::Relaxed) {
{
let mut lock = verification.lock().unwrap();
while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) {
lock = wait.wait(lock).unwrap();
}
if deleting.load(AtomicOrdering::Relaxed) {
return;
}
}
let block = {
let mut v = verification.lock().unwrap();
if v.unverified.is_empty() {
continue;
}
let block = v.unverified.pop_front().unwrap();
v.verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None });
block
};
let block_hash = block.header.hash();
match verify_block_unordered(block.header, block.bytes, engine.deref().deref()) {
Ok(verified) => {
let mut v = verification.lock().unwrap();
for e in &mut v.verifying {
if e.hash == block_hash {
e.block = Some(verified);
break;
}
}
if !v.verifying.is_empty() && v.verifying.front().unwrap().hash == block_hash {
// we're next!
let mut vref = v.deref_mut();
BlockQueue::drain_verifying(&mut vref.verifying, &mut vref.verified, &mut vref.bad);
ready.set();
}
},
Err(err) => {
let mut v = verification.lock().unwrap();
warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err);
v.bad.insert(block_hash.clone());
v.verifying.retain(|e| e.hash != block_hash);
let mut vref = v.deref_mut();
BlockQueue::drain_verifying(&mut vref.verifying, &mut vref.verified, &mut vref.bad);
ready.set();
}
}
}
}
fn drain_verifying(verifying: &mut VecDeque<VerifyingBlock>, verified: &mut VecDeque<PreVerifiedBlock>, bad: &mut HashSet<H256>) {
while !verifying.is_empty() && verifying.front().unwrap().block.is_some() {
let block = verifying.pop_front().unwrap().block.unwrap();
if bad.contains(&block.header.parent_hash) {
bad.insert(block.header.hash());
}
else {
verified.push_back(block);
}
}
}
/// Clear the queue and stop verification activity.
pub fn clear(&mut self) {
let mut verification = self.verification.lock().unwrap();
verification.unverified.clear();
verification.verifying.clear();
}
/// 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));
pub fn import_block(&mut self, bytes: Bytes) -> ImportResult {
let header = BlockView::new(&bytes).header();
if self.processing.contains(&header.hash()) {
return Err(ImportError::AlreadyQueued);
}
{
let mut verification = self.verification.lock().unwrap();
if verification.bad.contains(&header.hash()) {
return Err(ImportError::Bad(None));
}
if verification.bad.contains(&header.parent_hash) {
verification.bad.insert(header.hash());
return Err(ImportError::Bad(None));
}
}
if self.bad.contains(&header.parent_hash) {
self.bad.insert(header.hash());
return Err(ImportError::Bad(None));
match verify_block_basic(&header, &bytes, self.engine.deref().deref()) {
Ok(()) => {
self.processing.insert(header.hash());
self.verification.lock().unwrap().unverified.push_back(UnVerifiedBlock { header: header, bytes: bytes });
self.more_to_verify.notify_all();
},
Err(err) => {
warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err);
self.verification.lock().unwrap().bad.insert(header.hash());
}
}
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(())
}
/// Mark given block and all its children as bad. Stops verification.
pub fn mark_as_bad(&mut self, hash: &H256) {
self.bad.insert(hash.clone());
//TODO: walk the queue
let mut verification_lock = self.verification.lock().unwrap();
let mut verification = verification_lock.deref_mut();
verification.bad.insert(hash.clone());
let mut new_verified = VecDeque::new();
for block in verification.verified.drain(..) {
if verification.bad.contains(&block.header.parent_hash) {
verification.bad.insert(block.header.hash());
}
else {
new_verified.push_back(block);
}
}
verification.verified = new_verified;
}
pub fn drain(&mut self, max: usize) -> Vec<PreVerifiedBlock> {
let mut verification = self.verification.lock().unwrap();
let count = min(max, verification.verified.len());
let mut result = Vec::with_capacity(count);
for _ in 0..count {
let block = verification.verified.pop_front().unwrap();
self.processing.remove(&block.header.hash());
result.push(block);
}
self.ready_signal.reset();
result
}
}
impl Drop for BlockQueue {
fn drop(&mut self) {
self.clear();
self.deleting.store(true, AtomicOrdering::Relaxed);
self.more_to_verify.notify_all();
for t in self.verifiers.drain(..) {
t.join().unwrap();
}
}
}
#[cfg(test)]
mod tests {
use util::*;
use spec::*;
use queue::*;
#[test]
fn test_block_queue() {
// TODO better test
let spec = Spec::new_test();
let engine = spec.to_engine().unwrap();
let _ = BlockQueue::new(Arc::new(engine), IoChannel::disconnected());
}
}

View File

@@ -54,8 +54,8 @@ impl IoHandler<NetSyncMessage> for ClientIoHandler {
#[allow(match_ref_pats)]
fn message<'s>(&'s mut self, _io: &mut IoContext<'s, NetSyncMessage>, net_message: &'s mut NetSyncMessage) {
if let &mut UserMessage(ref mut message) = net_message {
if let &mut SyncMessage::BlockVerified(ref mut bytes) = message {
self.client.write().unwrap().import_verified_block(mem::replace(bytes, Bytes::new()));
if let &mut SyncMessage::BlockVerified= message {
self.client.write().unwrap().import_verified_blocks();
}
}
}

View File

@@ -150,10 +150,10 @@ impl State {
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()));
trace!("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);
trace!("Transaction receipt: {:?}", receipt);
Ok(receipt)
}

View File

@@ -401,7 +401,7 @@ impl ChainSync {
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()) {
match io.chain().import_block(block_rlp.as_raw().to_vec()) {
Err(ImportError::AlreadyInChain) => {
trace!(target: "sync", "New block already in chain {:?}", h);
},
@@ -655,7 +655,7 @@ impl ChainSync {
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()) {
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;

View File

@@ -43,7 +43,7 @@ pub enum SyncMessage {
/// New block has been imported into the blockchain
NewChainBlock(Bytes),
/// A block is ready
BlockVerified(Bytes),
BlockVerified,
}
pub type NetSyncMessage = NetworkIoMessage<SyncMessage>;

View File

@@ -43,7 +43,7 @@ impl TestBlockChainClient {
rlp.append(&header);
rlp.append_raw(&rlp::NULL_RLP, 1);
rlp.append_raw(uncles.as_raw(), 1);
self.import_block(rlp.as_raw()).unwrap();
self.import_block(rlp.as_raw().to_vec()).unwrap();
}
}
}
@@ -110,7 +110,7 @@ impl BlockChainClient for TestBlockChainClient {
None
}
fn import_block(&mut self, b: &[u8]) -> ImportResult {
fn import_block(&mut self, b: Bytes) -> ImportResult {
let header = Rlp::new(&b).val_at::<BlockHeader>(0);
let number: usize = header.number as usize;
if number > self.blocks.len() {
@@ -132,7 +132,7 @@ impl BlockChainClient for TestBlockChainClient {
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.blocks.insert(header.hash(), b);
self.numbers.insert(number, header.hash());
let mut parent_hash = header.parent_hash;
if number > 0 {

View File

@@ -9,6 +9,16 @@ use common::*;
use engine::Engine;
use blockchain::*;
/// Preprocessed block data gathered in `verify_block_unordered` call
pub struct PreVerifiedBlock {
/// Populated block header
pub header: Header,
/// Populated block transactions
pub transactions: Vec<Transaction>,
/// Block bytes
pub bytes: Bytes,
}
/// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block
pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Result<(), Error> {
try!(verify_header(&header, engine));
@@ -29,19 +39,26 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res
/// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash.
/// Still operates on a individual block
/// TODO: return cached transactions, header hash.
pub fn verify_block_unordered(header: &Header, bytes: &[u8], engine: &Engine) -> Result<(), Error> {
try!(engine.verify_block_unordered(&header, Some(bytes)));
for u in Rlp::new(bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
/// Returns a PreVerifiedBlock structure populated with transactions
pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result<PreVerifiedBlock, Error> {
try!(engine.verify_block_unordered(&header, Some(&bytes)));
for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
try!(engine.verify_block_unordered(&u, None));
}
// Verify transactions.
// TODO: pass in pre-recovered transactions - maybe verify_transaction wants to call `sender()`.
let v = BlockView::new(bytes);
for t in v.transactions() {
try!(engine.verify_transaction(&t, &header));
// Verify transactions.
let mut transactions = Vec::new();
{
let v = BlockView::new(&bytes);
for t in v.transactions() {
try!(engine.verify_transaction(&t, &header));
transactions.push(t);
}
}
Ok(())
Ok(PreVerifiedBlock {
header: header,
transactions: transactions,
bytes: bytes,
})
}
/// Phase 3 verification. Check block information against parent and uncles.

View File

@@ -61,6 +61,44 @@ impl<'a> Hashable for TransactionView<'a> {
}
}
/// View onto transaction rlp.
pub struct AccountView<'a> {
rlp: Rlp<'a>
}
impl<'a> AccountView<'a> {
/// Creates new view onto block from raw bytes.
pub fn new(bytes: &'a [u8]) -> AccountView<'a> {
AccountView {
rlp: Rlp::new(bytes)
}
}
/// Creates new view onto block from rlp.
pub fn new_from_rlp(rlp: Rlp<'a>) -> AccountView<'a> {
AccountView {
rlp: rlp
}
}
/// Return reference to underlaying rlp.
pub fn rlp(&self) -> &Rlp<'a> {
&self.rlp
}
/// Get the nonce field of the transaction.
pub fn nonce(&self) -> U256 { self.rlp.val_at(0) }
/// Get the gas_price field of the transaction.
pub fn balance(&self) -> U256 { self.rlp.val_at(1) }
/// Get the gas field of the transaction.
pub fn storage_root(&self) -> H256 { self.rlp.val_at(2) }
/// Get the value field of the transaction.
pub fn code_hash(&self) -> H256 { self.rlp.val_at(3) }
}
/// View onto block rlp.
pub struct BlockView<'a> {
rlp: Rlp<'a>
@@ -97,13 +135,13 @@ impl<'a> BlockView<'a> {
}
/// Return List of transactions in given block.
pub fn transaction_views(&self) -> Vec<TransactionView> {
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
pub fn transactions(&self) -> Vec<Transaction> {
self.rlp.val_at(1)
}
/// Return List of transactions in given block.
pub fn transactions(&self) -> Vec<Transaction> {
self.rlp.val_at(1)
pub fn transaction_views(&self) -> Vec<TransactionView> {
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
}
/// Return transaction hashes.
@@ -116,6 +154,11 @@ impl<'a> BlockView<'a> {
self.rlp.val_at(2)
}
/// Return List of transactions in given block.
pub fn uncle_views(&self) -> Vec<HeaderView> {
self.rlp.at(2).iter().map(|rlp| HeaderView::new_from_rlp(rlp)).collect()
}
/// Return list of uncle hashes of given block.
pub fn uncle_hashes(&self) -> Vec<H256> {
self.rlp.at(2).iter().map(|rlp| rlp.as_raw().sha3()).collect()