Merge branch 'master' into tracing
This commit is contained in:
@@ -21,6 +21,7 @@ clippy = { version = "0.0.54", optional = true }
|
||||
crossbeam = "0.1.5"
|
||||
lazy_static = "0.1"
|
||||
ethcore-devtools = { path = "../devtools" }
|
||||
ethjson = { path = "../json" }
|
||||
|
||||
[features]
|
||||
jit = ["evmjit"]
|
||||
|
||||
@@ -33,10 +33,10 @@
|
||||
"enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@parity-node-zero.ethcore.io:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"3282791d6fd713f1e94f4bfd565eaa78b3a0599d": {
|
||||
"balance": "1337000000000000000000"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"engineName": "Frontier (Test)",
|
||||
"name": "Frontier (Test)",
|
||||
"engineName": "Ethash",
|
||||
"params": {
|
||||
"accountStartNonce": "0x00",
|
||||
@@ -26,9 +26,9 @@
|
||||
"gasLimit": "0x1388"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"engineName": "Frontier (Test)",
|
||||
"name": "Frontier (Test)",
|
||||
"engineName": "Ethash",
|
||||
"params": {
|
||||
"accountStartNonce": "0x00",
|
||||
@@ -26,9 +26,9 @@
|
||||
"gasLimit": "0x1388"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
"gasLimit": "0x1388"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
"enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
"gasLimit": "0x2fefd8"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "balance": "1606938044258990275541962092341162602522202993782792835301376" },
|
||||
"e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "1606938044258990275541962092341162602522202993782792835301376" },
|
||||
"b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "1606938044258990275541962092341162602522202993782792835301376" },
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
"gasLimit": "0x2fefd8"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ mod tests {
|
||||
open_block.push_uncle(uncle1_header).unwrap();
|
||||
open_block.push_uncle(uncle2_header).unwrap();
|
||||
let b = open_block.close().seal(engine.deref(), vec![]).unwrap();
|
||||
|
||||
|
||||
let orig_bytes = b.rlp_bytes();
|
||||
let orig_db = b.drain();
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ use crypto::sha2::Sha256;
|
||||
use crypto::ripemd160::Ripemd160;
|
||||
use crypto::digest::Digest;
|
||||
|
||||
/// Definition of a contract whose implementation is built-in.
|
||||
/// 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.
|
||||
@@ -63,14 +63,16 @@ impl Builtin {
|
||||
|
||||
/// Create a builtin from JSON.
|
||||
///
|
||||
/// JSON must be of the form `{ "name": "identity", "linear": {"base": 10, "word": 20} }`.
|
||||
/// JSON must be of the form `{ "name": "identity", "pricing": {"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);
|
||||
if let Json::Object(ref o) = json["pricing"] {
|
||||
if let Json::Object(ref o) = o["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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,7 +276,7 @@ fn from_named_linear() {
|
||||
|
||||
#[test]
|
||||
fn from_json() {
|
||||
let text = "{ \"name\": \"identity\", \"linear\": {\"base\": 10, \"word\": 20} }";
|
||||
let text = r#"{"name": "identity", "pricing": {"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));
|
||||
|
||||
@@ -37,6 +37,8 @@ use log_entry::LocalizedLogEntry;
|
||||
use block_queue::{BlockQueue, BlockQueueInfo};
|
||||
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
||||
use client::{BlockId, TransactionId, ClientConfig, BlockChainClient};
|
||||
use env_info::EnvInfo;
|
||||
use executive::{Executive, Executed};
|
||||
pub use blockchain::CacheSize as BlockChainCacheSize;
|
||||
|
||||
/// General block status
|
||||
@@ -385,6 +387,29 @@ impl<V> Client<V> where V: Verifier {
|
||||
}
|
||||
|
||||
impl<V> BlockChainClient for Client<V> where V: Verifier {
|
||||
fn call(&self, t: &SignedTransaction) -> Result<Executed, Error> {
|
||||
let header = self.block_header(BlockId::Latest).unwrap();
|
||||
let view = HeaderView::new(&header);
|
||||
let last_hashes = self.build_last_hashes(view.hash());
|
||||
let env_info = EnvInfo {
|
||||
number: view.number(),
|
||||
author: view.author(),
|
||||
timestamp: view.timestamp(),
|
||||
difficulty: view.difficulty(),
|
||||
last_hashes: last_hashes,
|
||||
gas_used: U256::zero(),
|
||||
gas_limit: U256::max_value(),
|
||||
};
|
||||
// that's just a copy of the state.
|
||||
let mut state = self.state();
|
||||
let sender = try!(t.sender());
|
||||
let balance = state.balance(&sender);
|
||||
// give the sender max balance
|
||||
state.sub_balance(&sender, &balance);
|
||||
state.add_balance(&sender, &U256::max_value());
|
||||
Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t, false)
|
||||
}
|
||||
|
||||
// TODO [todr] Should be moved to miner crate eventually.
|
||||
fn try_seal(&self, block: ClosedBlock, seal: Vec<Bytes>) -> Result<SealedBlock, ClosedBlock> {
|
||||
block.try_seal(self.engine.deref().deref(), seal)
|
||||
|
||||
@@ -25,6 +25,7 @@ pub use self::client::*;
|
||||
pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig};
|
||||
pub use self::ids::{BlockId, TransactionId};
|
||||
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
||||
pub use executive::Executed;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use util::bytes::Bytes;
|
||||
@@ -37,7 +38,7 @@ use header::BlockNumber;
|
||||
use transaction::{LocalizedTransaction, SignedTransaction};
|
||||
use log_entry::LocalizedLogEntry;
|
||||
use filter::Filter;
|
||||
use error::{ImportResult};
|
||||
use error::{ImportResult, Error};
|
||||
|
||||
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
||||
pub trait BlockChainClient : Sync + Send {
|
||||
@@ -118,5 +119,7 @@ pub trait BlockChainClient : Sync + Send {
|
||||
/// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error.
|
||||
fn try_seal(&self, block: ClosedBlock, seal: Vec<Bytes>) -> Result<SealedBlock, ClosedBlock>;
|
||||
|
||||
/// Makes a non-persistent transaction call.
|
||||
fn call(&self, t: &SignedTransaction) -> Result<Executed, Error>;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ use error::{ImportResult};
|
||||
|
||||
use block_queue::BlockQueueInfo;
|
||||
use block::{SealedBlock, ClosedBlock};
|
||||
use executive::Executed;
|
||||
use error::Error;
|
||||
|
||||
/// Test client.
|
||||
pub struct TestBlockChainClient {
|
||||
@@ -48,6 +50,8 @@ pub struct TestBlockChainClient {
|
||||
pub storage: RwLock<HashMap<(Address, H256), H256>>,
|
||||
/// Code.
|
||||
pub code: RwLock<HashMap<Address, Bytes>>,
|
||||
/// Execution result.
|
||||
pub execution_result: RwLock<Option<Executed>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -82,12 +86,18 @@ impl TestBlockChainClient {
|
||||
balances: RwLock::new(HashMap::new()),
|
||||
storage: RwLock::new(HashMap::new()),
|
||||
code: RwLock::new(HashMap::new()),
|
||||
execution_result: RwLock::new(None),
|
||||
};
|
||||
client.add_blocks(1, EachBlockWith::Nothing); // add genesis block
|
||||
client.genesis_hash = client.last_hash.read().unwrap().clone();
|
||||
client
|
||||
}
|
||||
|
||||
/// Set the execution result.
|
||||
pub fn set_execution_result(&self, result: Executed) {
|
||||
*self.execution_result.write().unwrap() = Some(result);
|
||||
}
|
||||
|
||||
/// Set the balance of account `address` to `balance`.
|
||||
pub fn set_balance(&self, address: Address, balance: U256) {
|
||||
self.balances.write().unwrap().insert(address, balance);
|
||||
@@ -182,6 +192,10 @@ impl TestBlockChainClient {
|
||||
}
|
||||
|
||||
impl BlockChainClient for TestBlockChainClient {
|
||||
fn call(&self, _t: &SignedTransaction) -> Result<Executed, Error> {
|
||||
Ok(self.execution_result.read().unwrap().clone().unwrap())
|
||||
}
|
||||
|
||||
fn block_total_difficulty(&self, _id: BlockId) -> Option<U256> {
|
||||
Some(U256::zero())
|
||||
}
|
||||
@@ -219,11 +233,11 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
}
|
||||
|
||||
fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec<SignedTransaction>) -> Option<(ClosedBlock, HashSet<H256>)> {
|
||||
unimplemented!()
|
||||
None
|
||||
}
|
||||
|
||||
fn try_seal(&self, _block: ClosedBlock, _seal: Vec<Bytes>) -> Result<SealedBlock, ClosedBlock> {
|
||||
unimplemented!()
|
||||
fn try_seal(&self, block: ClosedBlock, _seal: Vec<Bytes>) -> Result<SealedBlock, ClosedBlock> {
|
||||
Err(block)
|
||||
}
|
||||
|
||||
fn block_header(&self, id: BlockId) -> Option<Bytes> {
|
||||
|
||||
@@ -65,6 +65,10 @@ pub enum ExecutionError {
|
||||
#[derive(Debug)]
|
||||
/// Errors concerning transaction processing.
|
||||
pub enum TransactionError {
|
||||
/// Transaction is already imported to the queue
|
||||
AlreadyImported,
|
||||
/// Transaction is not valid anymore (state already has higher nonce)
|
||||
Old,
|
||||
/// Transaction's gas price is below threshold.
|
||||
InsufficientGasPrice {
|
||||
/// Minimal expected gas price
|
||||
|
||||
@@ -37,25 +37,25 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
|
||||
}
|
||||
|
||||
/// Transaction execution receipt.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
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>,
|
||||
|
||||
@@ -66,7 +66,8 @@ pub struct Executed {
|
||||
///
|
||||
/// B creation ends first, and it will be the first element of the vector.
|
||||
pub contracts_created: Vec<Address>,
|
||||
|
||||
/// Transaction output.
|
||||
pub output: Bytes,
|
||||
/// The trace of this transaction.
|
||||
pub trace: Option<Trace>,
|
||||
}
|
||||
@@ -152,7 +153,7 @@ impl<'a> Executive<'a> {
|
||||
|
||||
let mut substate = Substate::new(tracing);
|
||||
|
||||
let res = match t.action {
|
||||
let (gas_left, output) = match t.action {
|
||||
Action::Create => {
|
||||
let new_address = contract_address(&sender, &nonce);
|
||||
let params = ActionParams {
|
||||
@@ -166,7 +167,7 @@ impl<'a> Executive<'a> {
|
||||
code: Some(t.data.clone()),
|
||||
data: None,
|
||||
};
|
||||
self.create(params, &mut substate)
|
||||
(self.create(params, &mut substate), vec![])
|
||||
},
|
||||
Action::Call(ref address) => {
|
||||
let params = ActionParams {
|
||||
@@ -182,12 +183,12 @@ impl<'a> Executive<'a> {
|
||||
};
|
||||
// TODO: move output upstream
|
||||
let mut out = vec![];
|
||||
self.call(params, &mut substate, BytesRef::Flexible(&mut out))
|
||||
(self.call(params, &mut substate, BytesRef::Flexible(&mut out)), out)
|
||||
}
|
||||
};
|
||||
|
||||
// finalize here!
|
||||
Ok(try!(self.finalize(t, substate, res)))
|
||||
Ok(try!(self.finalize(t, substate, gas_left, output)))
|
||||
}
|
||||
|
||||
fn exec_vm(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy) -> evm::Result {
|
||||
@@ -258,7 +259,7 @@ impl<'a> Executive<'a> {
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()))
|
||||
};
|
||||
|
||||
// if there's tracing, make up trace_info's result with trace_output and some arithmetic.
|
||||
// if there's tracing, make up trace_info's result with trace_output and some arithmetic.
|
||||
if let Some((TraceAction::Call(ref mut c), _)) = trace_info {
|
||||
c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: qed")));
|
||||
}
|
||||
@@ -314,7 +315,7 @@ impl<'a> Executive<'a> {
|
||||
}
|
||||
|
||||
/// Finalizes the transaction (does refunds and suicides).
|
||||
fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result) -> ExecutionResult {
|
||||
fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result, output: Bytes) -> ExecutionResult {
|
||||
let schedule = self.engine.schedule(self.info);
|
||||
|
||||
// refunds from SSTORE nonzero -> zero
|
||||
@@ -357,6 +358,7 @@ impl<'a> Executive<'a> {
|
||||
cumulative_gas_used: self.info.gas_used + t.gas,
|
||||
logs: vec![],
|
||||
contracts_created: vec![],
|
||||
output: output,
|
||||
trace: trace,
|
||||
})
|
||||
},
|
||||
@@ -368,6 +370,7 @@ impl<'a> Executive<'a> {
|
||||
cumulative_gas_used: self.info.gas_used + gas_used,
|
||||
logs: substate.logs,
|
||||
contracts_created: substate.contracts_created,
|
||||
output: output,
|
||||
trace: trace,
|
||||
})
|
||||
},
|
||||
|
||||
@@ -16,18 +16,19 @@
|
||||
|
||||
use super::test_common::*;
|
||||
use client::{BlockChainClient, Client, ClientConfig};
|
||||
use pod_state::*;
|
||||
use block::Block;
|
||||
use ethereum;
|
||||
use tests::helpers::*;
|
||||
use devtools::*;
|
||||
use spec::Genesis;
|
||||
use ethjson;
|
||||
|
||||
pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
||||
init_log();
|
||||
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
|
||||
let tests = ethjson::blockchain::Test::load(json_data).unwrap();
|
||||
let mut failed = Vec::new();
|
||||
|
||||
for (name, test) in json.as_object().unwrap() {
|
||||
for (name, blockchain) in tests.deref() {
|
||||
let mut fail = false;
|
||||
{
|
||||
let mut fail_unless = |cond: bool| if !cond && !fail {
|
||||
@@ -39,37 +40,36 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
||||
|
||||
flush!(" - {}...", name);
|
||||
|
||||
let blocks: Vec<(Bytes, bool)> = test["blocks"].as_array().unwrap().iter().map(|e| (xjson!(&e["rlp"]), e.find("blockHeader").is_some())).collect();
|
||||
let mut spec = match era {
|
||||
ChainEra::Frontier => ethereum::new_frontier_test(),
|
||||
ChainEra::Homestead => ethereum::new_homestead_test(),
|
||||
};
|
||||
let s = PodState::from_json(test.find("pre").unwrap());
|
||||
spec.set_genesis_state(s);
|
||||
spec.overwrite_genesis(test.find("genesisBlockHeader").unwrap());
|
||||
|
||||
let genesis = Genesis::from(blockchain.genesis());
|
||||
let state = From::from(blockchain.pre_state.clone());
|
||||
spec.set_genesis_state(state);
|
||||
spec.overwrite_genesis_params(genesis);
|
||||
assert!(spec.is_state_root_valid());
|
||||
let genesis_hash = spec.genesis_header().hash();
|
||||
assert_eq!(genesis_hash, H256::from_json(&test.find("genesisBlockHeader").unwrap()["hash"]));
|
||||
|
||||
let temp = RandomTempPath::new();
|
||||
{
|
||||
let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap();
|
||||
assert_eq!(client.chain_info().best_block_hash, genesis_hash);
|
||||
for (b, is_valid) in blocks.into_iter() {
|
||||
for b in &blockchain.blocks_rlp() {
|
||||
if Block::is_good(&b) {
|
||||
let _ = client.import_block(b.clone());
|
||||
client.flush_queue();
|
||||
client.import_verified_blocks(&IoChannel::disconnected());
|
||||
}
|
||||
client.flush_queue();
|
||||
let imported_ok = client.import_verified_blocks(&IoChannel::disconnected()) > 0;
|
||||
assert_eq!(imported_ok, is_valid);
|
||||
}
|
||||
fail_unless(client.chain_info().best_block_hash == H256::from_json(&test["lastblockhash"]));
|
||||
fail_unless(client.chain_info().best_block_hash == blockchain.best_block.clone().into());
|
||||
}
|
||||
}
|
||||
|
||||
if !fail {
|
||||
flushln!("ok");
|
||||
}
|
||||
}
|
||||
|
||||
println!("!!! {:?} tests from failed.", failed.len());
|
||||
failed
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ extern crate time;
|
||||
extern crate env_logger;
|
||||
extern crate num_cpus;
|
||||
extern crate crossbeam;
|
||||
extern crate ethjson;
|
||||
|
||||
#[cfg(test)] extern crate ethcore_devtools as devtools;
|
||||
#[cfg(feature = "jit" )] extern crate evmjit;
|
||||
@@ -101,13 +102,13 @@ pub mod spec;
|
||||
pub mod transaction;
|
||||
pub mod views;
|
||||
pub mod receipt;
|
||||
pub mod pod_state;
|
||||
|
||||
mod common;
|
||||
mod basic_types;
|
||||
#[macro_use] mod evm;
|
||||
mod env_info;
|
||||
mod pod_account;
|
||||
mod pod_state;
|
||||
mod account_diff;
|
||||
mod state_diff;
|
||||
mod engine;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
use util::*;
|
||||
use account::*;
|
||||
use account_db::*;
|
||||
use ethjson;
|
||||
|
||||
#[derive(Debug,Clone,PartialEq,Eq)]
|
||||
/// An account, expressed as Plain-Old-Data (hence the name).
|
||||
@@ -73,6 +74,22 @@ impl PodAccount {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ethjson::blockchain::Account> for PodAccount {
|
||||
fn from(a: ethjson::blockchain::Account) -> Self {
|
||||
PodAccount {
|
||||
balance: a.balance.into(),
|
||||
nonce: a.nonce.into(),
|
||||
code: a.code.into(),
|
||||
storage: a.storage.into_iter().fold(BTreeMap::new(), |mut acc, (key, value)| {
|
||||
let key: U256 = key.into();
|
||||
let value: U256 = value.into();
|
||||
acc.insert(H256::from(key), H256::from(value));
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
|
||||
@@ -14,11 +14,14 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! State of all accounts in the system expressed in Plain Old Data.
|
||||
|
||||
use util::*;
|
||||
use pod_account::*;
|
||||
use ethjson;
|
||||
|
||||
#[derive(Debug,Clone,PartialEq,Eq,Default)]
|
||||
/// State of all accounts in the system expressed in Plain Old Data.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct PodState (BTreeMap<Address, PodAccount>);
|
||||
|
||||
impl PodState {
|
||||
@@ -64,6 +67,15 @@ impl FromJson for PodState {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ethjson::blockchain::State> for PodState {
|
||||
fn from(s: ethjson::blockchain::State) -> PodState {
|
||||
PodState(s.0.into_iter().fold(BTreeMap::new(), |mut acc, (key, value)| {
|
||||
acc.insert(key.into(), PodAccount::from(value));
|
||||
acc
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PodState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for (add, acc) in &self.0 {
|
||||
|
||||
91
ethcore/src/spec/genesis.rs
Normal file
91
ethcore/src/spec/genesis.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use util::rlp::*;
|
||||
use util::numbers::{Uint, U256};
|
||||
use util::hash::{H64, Address, H256};
|
||||
use ethjson;
|
||||
|
||||
/// Genesis seal type.
|
||||
pub enum Seal {
|
||||
/// Classic ethereum seal.
|
||||
Ethereum {
|
||||
/// Seal nonce.
|
||||
nonce: H64,
|
||||
/// Seal mix hash.
|
||||
mix_hash: H256,
|
||||
},
|
||||
/// Generic seal.
|
||||
Generic {
|
||||
/// Number of seal fields.
|
||||
fields: usize,
|
||||
/// Seal rlp.
|
||||
rlp: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Genesis components.
|
||||
pub struct Genesis {
|
||||
/// Seal.
|
||||
pub seal: Seal,
|
||||
/// Difficulty.
|
||||
pub difficulty: U256,
|
||||
/// Author.
|
||||
pub author: Address,
|
||||
/// Timestamp.
|
||||
pub timestamp: u64,
|
||||
/// Parent hash.
|
||||
pub parent_hash: H256,
|
||||
/// Gas limit.
|
||||
pub gas_limit: U256,
|
||||
/// Transactions root.
|
||||
pub transactions_root: H256,
|
||||
/// Receipts root.
|
||||
pub receipts_root: H256,
|
||||
/// State root.
|
||||
pub state_root: Option<H256>,
|
||||
/// Gas used.
|
||||
pub gas_used: U256,
|
||||
/// Extra data.
|
||||
pub extra_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::Genesis> for Genesis {
|
||||
fn from(g: ethjson::spec::Genesis) -> Self {
|
||||
Genesis {
|
||||
seal: match (g.nonce, g.mix_hash) {
|
||||
(Some(nonce), Some(mix_hash)) => Seal::Ethereum {
|
||||
nonce: nonce.into(),
|
||||
mix_hash: mix_hash.into(),
|
||||
},
|
||||
_ => Seal::Generic {
|
||||
fields: g.seal_fields.unwrap(),
|
||||
rlp: g.seal_rlp.unwrap().into(),
|
||||
}
|
||||
},
|
||||
difficulty: g.difficulty.into(),
|
||||
author: g.author.into(),
|
||||
timestamp: g.timestamp.into(),
|
||||
parent_hash: g.parent_hash.into(),
|
||||
gas_limit: g.gas_limit.into(),
|
||||
transactions_root: g.transactions_root.map_or_else(|| SHA3_NULL_RLP.clone(), Into::into),
|
||||
receipts_root: g.receipts_root.map_or_else(|| SHA3_NULL_RLP.clone(), Into::into),
|
||||
state_root: g.state_root.map(Into::into),
|
||||
gas_used: g.gas_used.map_or_else(U256::zero, Into::into),
|
||||
extra_data: g.extra_data.map_or_else(Vec::new, Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
23
ethcore/src/spec/mod.rs
Normal file
23
ethcore/src/spec/mod.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Blockchain params.
|
||||
|
||||
mod genesis;
|
||||
pub mod spec;
|
||||
|
||||
pub use self::spec::*;
|
||||
pub use self::genesis::Genesis;
|
||||
@@ -21,6 +21,8 @@ use engine::*;
|
||||
use pod_state::*;
|
||||
use null_engine::*;
|
||||
use account_db::*;
|
||||
use ethereum;
|
||||
use super::genesis::{Seal as GenesisSeal, Genesis};
|
||||
|
||||
/// Convert JSON value to equivalent RLP representation.
|
||||
// TODO: handle container types.
|
||||
@@ -106,7 +108,7 @@ impl Spec {
|
||||
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)),
|
||||
"Ethash" => Ok(ethereum::Ethash::new_boxed(self)),
|
||||
_ => Err(Error::UnknownEngineName(self.engine_name.clone()))
|
||||
}
|
||||
}
|
||||
@@ -197,6 +199,32 @@ impl Spec {
|
||||
self.state_root_memo = RwLock::new(genesis.find("stateRoot").and_then(|_| Some(H256::from_json(&genesis["stateRoot"]))));
|
||||
}
|
||||
|
||||
/// Overwrite the genesis components.
|
||||
pub fn overwrite_genesis_params(&mut self, g: Genesis) {
|
||||
let (seal_fields, seal_rlp) = match g.seal {
|
||||
GenesisSeal::Generic { fields, rlp } => (fields, rlp),
|
||||
GenesisSeal::Ethereum { nonce, mix_hash } => {
|
||||
let mut s = RlpStream::new();
|
||||
s.append(&mix_hash);
|
||||
s.append(&nonce);
|
||||
(2, s.out())
|
||||
}
|
||||
};
|
||||
|
||||
self.parent_hash = g.parent_hash;
|
||||
self.transactions_root = g.transactions_root;
|
||||
self.receipts_root = g.receipts_root;
|
||||
self.author = g.author;
|
||||
self.difficulty = g.difficulty;
|
||||
self.gas_limit = g.gas_limit;
|
||||
self.gas_used = g.gas_used;
|
||||
self.timestamp = g.timestamp;
|
||||
self.extra_data = g.extra_data;
|
||||
self.seal_fields = seal_fields;
|
||||
self.seal_rlp = seal_rlp;
|
||||
self.state_root_memo = RwLock::new(g.state_root);
|
||||
}
|
||||
|
||||
/// Alter the value of the genesis state.
|
||||
pub fn set_genesis_state(&mut self, s: PodState) {
|
||||
self.genesis_state = s;
|
||||
@@ -304,7 +332,7 @@ impl Spec {
|
||||
}
|
||||
|
||||
/// 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")) }
|
||||
pub fn new_test() -> Spec { Self::from_json_utf8(include_bytes!("../../res/null_morden.json")) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -256,6 +256,9 @@ impl<'a> HeaderView<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns header hash.
|
||||
pub fn hash(&self) -> H256 { self.sha3() }
|
||||
|
||||
/// Returns raw rlp.
|
||||
pub fn rlp(&self) -> &Rlp<'a> { &self.rlp }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user