Support Homestead,
This commit is contained in:
		
							parent
							
								
									b4556c3436
								
							
						
					
					
						commit
						dd5fcb398f
					
				@ -252,8 +252,7 @@ impl BlockChain {
 | 
				
			|||||||
	/// If it doesn't, then rewind down until we find one that does and delete data to ensure that
 | 
						/// If it doesn't, then rewind down until we find one that does and delete data to ensure that
 | 
				
			||||||
	/// later blocks will be reimported. 
 | 
						/// later blocks will be reimported. 
 | 
				
			||||||
	pub fn ensure_good(&mut self, _state: &OverlayDB) {
 | 
						pub fn ensure_good(&mut self, _state: &OverlayDB) {
 | 
				
			||||||
		info!("Rescuing database.");
 | 
							unimplemented!();
 | 
				
			||||||
		// TODO.
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Returns a tree route between `from` and `to`, which is a tuple of:
 | 
						/// Returns a tree route between `from` and `to`, which is a tuple of:
 | 
				
			||||||
 | 
				
			|||||||
@ -138,7 +138,7 @@ impl Client {
 | 
				
			|||||||
		engine.spec().ensure_db_good(&mut state_db);
 | 
							engine.spec().ensure_db_good(&mut state_db);
 | 
				
			||||||
		state_db.commit().expect("Error commiting genesis state to state DB");
 | 
							state_db.commit().expect("Error commiting genesis state to state DB");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		chain.write().unwrap().ensure_good(&state_db);
 | 
					//		chain.write().unwrap().ensure_good(&state_db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Ok(Client {
 | 
							Ok(Client {
 | 
				
			||||||
			chain: chain,
 | 
								chain: chain,
 | 
				
			||||||
 | 
				
			|||||||
@ -50,6 +50,7 @@ pub trait Engine : Sync + Send {
 | 
				
			|||||||
	/// Additional verification for transactions in blocks.
 | 
						/// Additional verification for transactions in blocks.
 | 
				
			||||||
	// TODO: Add flags for which bits of the transaction to check.
 | 
						// TODO: Add flags for which bits of the transaction to check.
 | 
				
			||||||
	// TODO: consider including State in the params.
 | 
						// 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(()) }
 | 
						fn verify_transaction(&self, _t: &Transaction, _header: &Header) -> Result<(), Error> { Ok(()) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Don't forget to call Super::populateFromParent when subclassing & overriding.
 | 
						/// Don't forget to call Super::populateFromParent when subclassing & overriding.
 | 
				
			||||||
 | 
				
			|||||||
@ -8,14 +8,28 @@ use evm::Schedule;
 | 
				
			|||||||
/// mainnet chains in the Olympic, Frontier and Homestead eras.
 | 
					/// mainnet chains in the Olympic, Frontier and Homestead eras.
 | 
				
			||||||
pub struct Ethash {
 | 
					pub struct Ethash {
 | 
				
			||||||
	spec: Spec,
 | 
						spec: Spec,
 | 
				
			||||||
 | 
						u64_params: RwLock<HashMap<String, u64>>,
 | 
				
			||||||
 | 
						u256_params: RwLock<HashMap<String, U256>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Ethash {
 | 
					impl Ethash {
 | 
				
			||||||
	pub fn new_boxed(spec: Spec) -> Box<Engine> {
 | 
						pub fn new_boxed(spec: Spec) -> Box<Engine> {
 | 
				
			||||||
		Box::new(Ethash{spec: spec})
 | 
							Box::new(Ethash{
 | 
				
			||||||
 | 
								spec: spec,
 | 
				
			||||||
 | 
								u64_params: RwLock::new(HashMap::new()),
 | 
				
			||||||
 | 
								u256_params: RwLock::new(HashMap::new()),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn u256_param(&self, name: &str) -> U256 { self.spec().engine_params.get(name).map(|a| decode(&a)).unwrap_or(U256::from(0u64)) }
 | 
						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 {
 | 
					impl Engine for Ethash {
 | 
				
			||||||
@ -29,7 +43,12 @@ impl Engine for Ethash {
 | 
				
			|||||||
	/// Additional engine-specific information for the user/developer concerning `header`.
 | 
						/// Additional engine-specific information for the user/developer concerning `header`.
 | 
				
			||||||
	fn extra_info(&self, _header: &Header) -> HashMap<String, String> { HashMap::new() }
 | 
						fn extra_info(&self, _header: &Header) -> HashMap<String, String> { HashMap::new() }
 | 
				
			||||||
	fn spec(&self) -> &Spec { &self.spec }
 | 
						fn spec(&self) -> &Spec { &self.spec }
 | 
				
			||||||
	fn schedule(&self, _env_info: &EnvInfo) -> Schedule { Schedule::new_frontier() }
 | 
						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) {
 | 
						fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
 | 
				
			||||||
		header.difficulty = self.calculate_difficuty(header, parent);
 | 
							header.difficulty = self.calculate_difficuty(header, parent);
 | 
				
			||||||
@ -64,12 +83,13 @@ impl Engine for Ethash {
 | 
				
			|||||||
		fields.state.commit();
 | 
							fields.state.commit();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn verify_block_basic(&self, header: &Header,  _block: Option<&[u8]>) -> result::Result<(), Error> {
 | 
						fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
 | 
				
			||||||
		let min_difficulty = decode(self.spec().engine_params.get("minimumDifficulty").unwrap());
 | 
							let min_difficulty = decode(self.spec().engine_params.get("minimumDifficulty").unwrap());
 | 
				
			||||||
		if header.difficulty < min_difficulty {
 | 
							if header.difficulty < min_difficulty {
 | 
				
			||||||
			return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: min_difficulty, found: header.difficulty })))
 | 
								return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: min_difficulty, found: header.difficulty })))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// TODO: Verify seal (quick)
 | 
							// TODO: Verify seal (quick)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Ok(())
 | 
							Ok(())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -93,7 +113,12 @@ impl Engine for Ethash {
 | 
				
			|||||||
		Ok(())
 | 
							Ok(())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn verify_transaction(&self, _t: &Transaction, _header: &Header) -> result::Result<(), Error> { 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 {
 | 
					impl Ethash {
 | 
				
			||||||
@ -103,10 +128,10 @@ impl Ethash {
 | 
				
			|||||||
			panic!("Can't calculate genesis block difficulty");
 | 
								panic!("Can't calculate genesis block difficulty");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let min_difficulty = decode(self.spec().engine_params.get("minimumDifficulty").unwrap());
 | 
							let min_difficulty = self.u256_param("minimumDifficulty");
 | 
				
			||||||
		let difficulty_bound_divisor = decode(self.spec().engine_params.get("difficultyBoundDivisor").unwrap());
 | 
							let difficulty_bound_divisor = self.u256_param("difficultyBoundDivisor");
 | 
				
			||||||
		let duration_limit: u64 = decode(self.spec().engine_params.get("durationLimit").unwrap());
 | 
							let duration_limit = self.u64_param("durationLimit");
 | 
				
			||||||
		let frontier_limit = decode(self.spec().engine_params.get("frontierCompatibilityModeLimit").unwrap());
 | 
							let frontier_limit = self.u64_param("frontierCompatibilityModeLimit");
 | 
				
			||||||
		let mut target = if header.number < frontier_limit {
 | 
							let mut target = if header.number < frontier_limit {
 | 
				
			||||||
			if header.timestamp >= parent.timestamp + duration_limit {
 | 
								if header.timestamp >= parent.timestamp + duration_limit {
 | 
				
			||||||
				parent.difficulty - (parent.difficulty / difficulty_bound_divisor) 
 | 
									parent.difficulty - (parent.difficulty / difficulty_bound_divisor) 
 | 
				
			||||||
 | 
				
			|||||||
@ -38,7 +38,8 @@ struct ClientIoHandler {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl IoHandler<NetSyncMessage> for ClientIoHandler {
 | 
					impl IoHandler<NetSyncMessage> for ClientIoHandler {
 | 
				
			||||||
	fn initialize<'s>(&'s mut self, _io: &mut IoContext<'s, NetSyncMessage>) { }
 | 
						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) {
 | 
						fn message<'s>(&'s mut self, _io: &mut IoContext<'s, NetSyncMessage>, net_message: &'s mut NetSyncMessage) {
 | 
				
			||||||
		match net_message {
 | 
							match net_message {
 | 
				
			||||||
 | 
				
			|||||||
@ -215,6 +215,15 @@ impl Transaction {
 | 
				
			|||||||
		Self::gas_required_for(match self.action{Action::Create=>true, Action::Call(_)=>false}, &self.data, schedule)
 | 
							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,
 | 
						/// Do basic validation, checking for valid signature and minimum gas,
 | 
				
			||||||
	pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result<Transaction, Error> {
 | 
						pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result<Transaction, Error> {
 | 
				
			||||||
		if require_low && !ec::is_low_s(&self.s) {
 | 
							if require_low && !ec::is_low_s(&self.s) {
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,12 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res
 | 
				
			|||||||
		try!(verify_header(&u, engine));
 | 
							try!(verify_header(&u, engine));
 | 
				
			||||||
		try!(engine.verify_block_basic(&u, None));
 | 
							try!(engine.verify_block_basic(&u, None));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// Verify transactions.
 | 
				
			||||||
 | 
						// TODO: either use transaction views or cache the decoded transactions.
 | 
				
			||||||
 | 
						let v = BlockView::new(bytes);
 | 
				
			||||||
 | 
						for t in v.transactions() {
 | 
				
			||||||
 | 
							try!(engine.verify_transaction_basic(&t, &header));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	Ok(())
 | 
						Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -29,6 +35,12 @@ pub fn verify_block_unordered(header: &Header, bytes: &[u8], engine: &Engine) ->
 | 
				
			|||||||
	for u in Rlp::new(bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
 | 
						for u in Rlp::new(bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
 | 
				
			||||||
		try!(engine.verify_block_unordered(&u, None));
 | 
							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));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	Ok(())
 | 
						Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										57
									
								
								src/views.rs
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								src/views.rs
									
									
									
									
									
								
							@ -2,7 +2,57 @@
 | 
				
			|||||||
use util::*;
 | 
					use util::*;
 | 
				
			||||||
use header::*;
 | 
					use header::*;
 | 
				
			||||||
use transaction::*;
 | 
					use transaction::*;
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					/// View onto block rlp.
 | 
				
			||||||
 | 
					pub struct TransactionView<'a> {
 | 
				
			||||||
 | 
						rlp: Rlp<'a>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> TransactionView<'a> {
 | 
				
			||||||
 | 
						/// Creates new view onto block from raw bytes.
 | 
				
			||||||
 | 
						pub fn new(bytes: &'a [u8]) -> TransactionView<'a> {
 | 
				
			||||||
 | 
							BlockView {
 | 
				
			||||||
 | 
								rlp: Rlp::new(bytes)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Creates new view onto block from rlp.
 | 
				
			||||||
 | 
						pub fn new_from_rlp(rlp: Rlp<'a>) -> TransactionView<'a> {
 | 
				
			||||||
 | 
							TransactionView {
 | 
				
			||||||
 | 
								rlp: rlp
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Return reference to underlaying rlp.
 | 
				
			||||||
 | 
						pub fn rlp(&self) -> &Rlp<'a> {
 | 
				
			||||||
 | 
							&self.rlp
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn nonce(&self) -> U256 { self.rlp.val_at(0) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn gas_price(&self) -> U256 { self.rlp.val_at(1) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn gas(&self) -> U256 { self.rlp.val_at(2) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn action(&self) -> Action { self.rlp.val_at(3) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn value(&self) -> U256 { self.rlp.val_at(4) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn data(&self) -> Bytes { self.rlp.val_at(5) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn v(&self) -> u8 { self.rlp.val_at(6) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn r(&self) -> U256 { self.rlp.val_at(7) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn s(&self) -> U256 { self.rlp.val_at(8) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> Hashable for TransactionView<'a> {
 | 
				
			||||||
 | 
						fn sha3(&self) -> H256 {
 | 
				
			||||||
 | 
							self.rlp.as_raw().sha3()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
/// View onto block rlp.
 | 
					/// View onto block rlp.
 | 
				
			||||||
pub struct BlockView<'a> {
 | 
					pub struct BlockView<'a> {
 | 
				
			||||||
	rlp: Rlp<'a>
 | 
						rlp: Rlp<'a>
 | 
				
			||||||
@ -37,7 +87,12 @@ impl<'a> BlockView<'a> {
 | 
				
			|||||||
	pub fn header_view(&self) -> HeaderView<'a> {
 | 
						pub fn header_view(&self) -> HeaderView<'a> {
 | 
				
			||||||
		HeaderView::new_from_rlp(self.rlp.at(0))
 | 
							HeaderView::new_from_rlp(self.rlp.at(0))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
						/// Return List of transactions in given block.
 | 
				
			||||||
 | 
						pub fn transactions(&self) -> Vec<TransactionView> {
 | 
				
			||||||
 | 
							self.rlp.at(1).iter().map(|rlp| TransactionView::new_from_rlp(rlp)).collect()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
	/// Return List of transactions in given block.
 | 
						/// Return List of transactions in given block.
 | 
				
			||||||
	pub fn transactions(&self) -> Vec<Transaction> {
 | 
						pub fn transactions(&self) -> Vec<Transaction> {
 | 
				
			||||||
		self.rlp.val_at(1)
 | 
							self.rlp.val_at(1)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user