Merge pull request #141 from gavofyork/gav
Homestead transition support, maybe.
This commit is contained in:
commit
9d3c1ee444
@ -3,7 +3,7 @@
|
|||||||
"engineName": "Ethash",
|
"engineName": "Ethash",
|
||||||
"params": {
|
"params": {
|
||||||
"accountStartNonce": "0x00",
|
"accountStartNonce": "0x00",
|
||||||
"frontierCompatibilityModeLimit": "0xfffa2990",
|
"frontierCompatibilityModeLimit": "0xDBBA0",
|
||||||
"maximumExtraDataSize": "0x20",
|
"maximumExtraDataSize": "0x20",
|
||||||
"tieBreakingGas": false,
|
"tieBreakingGas": false,
|
||||||
"minGasLimit": "0x1388",
|
"minGasLimit": "0x1388",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"engineName": "Ethash",
|
"engineName": "Ethash",
|
||||||
"params": {
|
"params": {
|
||||||
"accountStartNonce": "0x00",
|
"accountStartNonce": "0x00",
|
||||||
"frontierCompatibilityModeLimit": "0xffffffff",
|
"frontierCompatibilityModeLimit": "0",
|
||||||
"maximumExtraDataSize": "0x20",
|
"maximumExtraDataSize": "0x20",
|
||||||
"minGasLimit": "0x1388",
|
"minGasLimit": "0x1388",
|
||||||
"tieBreakingGas": false,
|
"tieBreakingGas": false,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"engineName": "Ethash",
|
"engineName": "Ethash",
|
||||||
"params": {
|
"params": {
|
||||||
"accountStartNonce": "0x0100000",
|
"accountStartNonce": "0x0100000",
|
||||||
"frontierCompatibilityModeLimit": "0xfffa2990",
|
"frontierCompatibilityModeLimit": "0xDBBA0",
|
||||||
"maximumExtraDataSize": "0x20",
|
"maximumExtraDataSize": "0x20",
|
||||||
"tieBreakingGas": false,
|
"tieBreakingGas": false,
|
||||||
"minGasLimit": "0x1388",
|
"minGasLimit": "0x1388",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"engineName": "Ethash",
|
"engineName": "Ethash",
|
||||||
"params": {
|
"params": {
|
||||||
"accountStartNonce": "0x00",
|
"accountStartNonce": "0x00",
|
||||||
"frontierCompatibilityModeLimit": "0xffffffff",
|
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
|
||||||
"maximumExtraDataSize": "0x0400",
|
"maximumExtraDataSize": "0x0400",
|
||||||
"tieBreakingGas": false,
|
"tieBreakingGas": false,
|
||||||
"minGasLimit": "125000",
|
"minGasLimit": "125000",
|
||||||
|
@ -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:
|
||||||
|
@ -141,7 +141,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);
|
||||||
@ -70,6 +89,7 @@ impl Engine for Ethash {
|
|||||||
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)
|
||||||
|
@ -48,7 +48,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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
63
src/views.rs
63
src/views.rs
@ -3,6 +3,64 @@ use util::*;
|
|||||||
use header::*;
|
use header::*;
|
||||||
use transaction::*;
|
use transaction::*;
|
||||||
|
|
||||||
|
/// View onto transaction 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> {
|
||||||
|
TransactionView {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 gas_price(&self) -> U256 { self.rlp.val_at(1) }
|
||||||
|
|
||||||
|
/// Get the gas field of the transaction.
|
||||||
|
pub fn gas(&self) -> U256 { self.rlp.val_at(2) }
|
||||||
|
|
||||||
|
/// Get the value field of the transaction.
|
||||||
|
pub fn value(&self) -> U256 { self.rlp.val_at(4) }
|
||||||
|
|
||||||
|
/// Get the data field of the transaction.
|
||||||
|
pub fn data(&self) -> Bytes { self.rlp.val_at(5) }
|
||||||
|
|
||||||
|
/// Get the v field of the transaction.
|
||||||
|
pub fn v(&self) -> u8 { let r: u16 = self.rlp.val_at(6); r as u8 }
|
||||||
|
|
||||||
|
/// Get the r field of the transaction.
|
||||||
|
pub fn r(&self) -> U256 { self.rlp.val_at(7) }
|
||||||
|
|
||||||
|
/// Get the s field of the transaction.
|
||||||
|
pub fn s(&self) -> U256 { self.rlp.val_at(8) }
|
||||||
|
|
||||||
|
// TODO: something like pub fn action(&self) -> Action { self.rlp.val_at(3) }
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
@ -38,6 +96,11 @@ impl<'a> BlockView<'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 transaction_views(&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