Merge branch 'master' of github.com:ethcore/parity into move_hash
This commit is contained in:
commit
1ed2de1d9b
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -646,7 +646,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
[[package]]
|
||||
name = "json-ipc-server"
|
||||
version = "0.2.4"
|
||||
source = "git+https://github.com/ethcore/json-ipc-server.git#7a02a0f8b249fda100b9bab5f90b2081d410d8cf"
|
||||
source = "git+https://github.com/ethcore/json-ipc-server.git#56b6307130710ebc73cb9be087b6ed0b6c400bcf"
|
||||
dependencies = [
|
||||
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1543,13 +1543,13 @@ dependencies = [
|
||||
"checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf"
|
||||
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
||||
"checksum docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4cc0acb4ce0828c6a5a11d47baa432fe885881c27428c3a4e473e454ffe57a76"
|
||||
"checksum elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7ec9af4640023400b86c9ce9126c79ed17ab247ec10a2f530eb78e3893b51aa"
|
||||
"checksum elastic-array 0.4.0 (git+https://github.com/ethcore/elastic-array)" = "<none>"
|
||||
"checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5"
|
||||
"checksum eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)" = "<none>"
|
||||
"checksum gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3da3a2cbaeb01363c8e3704fd9fd0eb2ceb17c6f27abd4c1ef040fb57d20dc79"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1"
|
||||
"checksum heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "927f352867eb72d0ef81b0e2aa457cd9b0888b2d26672cf7ca5912d771215191"
|
||||
"checksum heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "abb306abb8d398e053cfb1b3e7b72c2f580be048b85745c52652954f8ad1439c"
|
||||
"checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
|
||||
"checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae"
|
||||
"checksum hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb0f4d00bb781e559b6e66ae4b5479df0fdf9ab15949f52fa2f1f5de16d4cc07"
|
||||
|
@ -4,7 +4,7 @@
|
||||
"Null": null
|
||||
},
|
||||
"params": {
|
||||
"accountStartNonce": "0x0100000",
|
||||
"accountStartNonce": "0x0",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x2"
|
||||
|
@ -226,7 +226,7 @@ impl BlockQueue {
|
||||
};
|
||||
|
||||
let block_hash = block.header.hash();
|
||||
match verify_block_unordered(block.header, block.bytes, engine.deref().deref()) {
|
||||
match verify_block_unordered(block.header, block.bytes, &**engine) {
|
||||
Ok(verified) => {
|
||||
let mut verifying = verification.verifying.lock();
|
||||
for e in verifying.iter_mut() {
|
||||
@ -319,7 +319,7 @@ impl BlockQueue {
|
||||
}
|
||||
}
|
||||
|
||||
match verify_block_basic(&header, &bytes, self.engine.deref().deref()) {
|
||||
match verify_block_basic(&header, &bytes, &**self.engine) {
|
||||
Ok(()) => {
|
||||
self.processing.write().insert(h.clone());
|
||||
self.verification.unverified.lock().push_back(UnverifiedBlock { header: header, bytes: bytes });
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::collections::{HashSet, HashMap, VecDeque};
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::path::{Path};
|
||||
use std::fmt;
|
||||
@ -35,7 +34,7 @@ use util::kvdb::*;
|
||||
|
||||
// other
|
||||
use views::{BlockView, HeaderView, BodyView};
|
||||
use error::{ImportError, ExecutionError, ReplayError, BlockError, ImportResult};
|
||||
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult};
|
||||
use header::BlockNumber;
|
||||
use state::State;
|
||||
use spec::Spec;
|
||||
@ -272,7 +271,7 @@ impl Client {
|
||||
}
|
||||
|
||||
fn check_and_close_block(&self, block: &PreverifiedBlock) -> Result<LockedBlock, ()> {
|
||||
let engine = self.engine.deref().deref();
|
||||
let engine = &**self.engine;
|
||||
let header = &block.header;
|
||||
|
||||
// Check the block isn't so old we won't be able to enact it.
|
||||
@ -283,7 +282,7 @@ impl Client {
|
||||
}
|
||||
|
||||
// Verify Block Family
|
||||
let verify_family_result = self.verifier.verify_block_family(header, &block.bytes, engine, self.chain.deref());
|
||||
let verify_family_result = self.verifier.verify_block_family(header, &block.bytes, engine, &*self.chain);
|
||||
if let Err(e) = verify_family_result {
|
||||
warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||
return Err(());
|
||||
@ -639,8 +638,8 @@ impl Client {
|
||||
}
|
||||
|
||||
impl BlockChainClient for Client {
|
||||
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
||||
let header = self.block_header(BlockID::Latest).unwrap();
|
||||
fn call(&self, t: &SignedTransaction, block: BlockID, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
let header = try!(self.block_header(block).ok_or(CallError::StatePruned));
|
||||
let view = HeaderView::new(&header);
|
||||
let last_hashes = self.build_last_hashes(view.hash());
|
||||
let env_info = EnvInfo {
|
||||
@ -653,7 +652,9 @@ impl BlockChainClient for Client {
|
||||
gas_limit: U256::max_value(),
|
||||
};
|
||||
// that's just a copy of the state.
|
||||
let mut state = self.state();
|
||||
let mut state = try!(self.state_at(block).ok_or(CallError::StatePruned));
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
|
||||
let sender = try!(t.sender().map_err(|e| {
|
||||
let message = format!("Transaction malformed: {:?}", e);
|
||||
ExecutionError::TransactionMalformed(message)
|
||||
@ -665,26 +666,23 @@ impl BlockChainClient for Client {
|
||||
state.add_balance(&sender, &(needed_balance - balance));
|
||||
}
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let mut ret = Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, options);
|
||||
let mut ret = try!(Executive::new(&mut state, &env_info, &**self.engine, &self.vm_factory).transact(t, options));
|
||||
|
||||
// TODO gav move this into Executive.
|
||||
if analytics.state_diffing {
|
||||
if let Ok(ref mut x) = ret {
|
||||
x.state_diff = Some(state.diff_from(self.state()));
|
||||
}
|
||||
}
|
||||
ret
|
||||
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn replay(&self, id: TransactionID, analytics: CallAnalytics) -> Result<Executed, ReplayError> {
|
||||
let address = try!(self.transaction_address(id).ok_or(ReplayError::TransactionNotFound));
|
||||
let header_data = try!(self.block_header(BlockID::Hash(address.block_hash)).ok_or(ReplayError::StatePruned));
|
||||
let body_data = try!(self.block_body(BlockID::Hash(address.block_hash)).ok_or(ReplayError::StatePruned));
|
||||
let mut state = try!(self.state_at_beginning(BlockID::Hash(address.block_hash)).ok_or(ReplayError::StatePruned));
|
||||
fn replay(&self, id: TransactionID, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
let address = try!(self.transaction_address(id).ok_or(CallError::TransactionNotFound));
|
||||
let header_data = try!(self.block_header(BlockID::Hash(address.block_hash)).ok_or(CallError::StatePruned));
|
||||
let body_data = try!(self.block_body(BlockID::Hash(address.block_hash)).ok_or(CallError::StatePruned));
|
||||
let mut state = try!(self.state_at_beginning(BlockID::Hash(address.block_hash)).ok_or(CallError::StatePruned));
|
||||
let txs = BodyView::new(&body_data).transactions();
|
||||
|
||||
if address.index >= txs.len() {
|
||||
return Err(ReplayError::TransactionNotFound);
|
||||
return Err(CallError::TransactionNotFound);
|
||||
}
|
||||
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
@ -700,20 +698,18 @@ impl BlockChainClient for Client {
|
||||
gas_limit: view.gas_limit(),
|
||||
};
|
||||
for t in txs.iter().take(address.index) {
|
||||
match Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, Default::default()) {
|
||||
match Executive::new(&mut state, &env_info, &**self.engine, &self.vm_factory).transact(t, Default::default()) {
|
||||
Ok(x) => { env_info.gas_used = env_info.gas_used + x.gas_used; }
|
||||
Err(ee) => { return Err(ReplayError::Execution(ee)) }
|
||||
Err(ee) => { return Err(CallError::Execution(ee)) }
|
||||
}
|
||||
}
|
||||
let t = &txs[address.index];
|
||||
let orig = state.clone();
|
||||
let mut ret = Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, options);
|
||||
if analytics.state_diffing {
|
||||
if let Ok(ref mut x) = ret {
|
||||
x.state_diff = Some(state.diff_from(orig));
|
||||
}
|
||||
}
|
||||
ret.map_err(ReplayError::Execution)
|
||||
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
let mut ret = try!(Executive::new(&mut state, &env_info, &**self.engine, &self.vm_factory).transact(t, options));
|
||||
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn keep_alive(&self) {
|
||||
@ -1002,7 +998,7 @@ impl BlockChainClient for Client {
|
||||
|
||||
impl MiningBlockChainClient for Client {
|
||||
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
|
||||
let engine = self.engine.deref().deref();
|
||||
let engine = &**self.engine;
|
||||
let h = self.chain.best_block_hash();
|
||||
|
||||
let mut open_block = OpenBlock::new(
|
||||
|
@ -37,7 +37,7 @@ use spec::Spec;
|
||||
use block_queue::BlockQueueInfo;
|
||||
use block::{OpenBlock, SealedBlock};
|
||||
use executive::Executed;
|
||||
use error::{ExecutionError, ReplayError};
|
||||
use error::CallError;
|
||||
use trace::LocalizedTrace;
|
||||
|
||||
/// Test client.
|
||||
@ -61,7 +61,7 @@ pub struct TestBlockChainClient {
|
||||
/// Code.
|
||||
pub code: RwLock<HashMap<Address, Bytes>>,
|
||||
/// Execution result.
|
||||
pub execution_result: RwLock<Option<Executed>>,
|
||||
pub execution_result: RwLock<Option<Result<Executed, CallError>>>,
|
||||
/// Transaction receipts.
|
||||
pub receipts: RwLock<HashMap<TransactionID, LocalizedReceipt>>,
|
||||
/// Block queue size.
|
||||
@ -125,7 +125,7 @@ impl TestBlockChainClient {
|
||||
}
|
||||
|
||||
/// Set the execution result.
|
||||
pub fn set_execution_result(&self, result: Executed) {
|
||||
pub fn set_execution_result(&self, result: Result<Executed, CallError>) {
|
||||
*self.execution_result.write() = Some(result);
|
||||
}
|
||||
|
||||
@ -292,12 +292,12 @@ impl MiningBlockChainClient for TestBlockChainClient {
|
||||
}
|
||||
|
||||
impl BlockChainClient for TestBlockChainClient {
|
||||
fn call(&self, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
||||
Ok(self.execution_result.read().clone().unwrap())
|
||||
fn call(&self, _t: &SignedTransaction, _block: BlockID, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
self.execution_result.read().clone().unwrap()
|
||||
}
|
||||
|
||||
fn replay(&self, _id: TransactionID, _analytics: CallAnalytics) -> Result<Executed, ReplayError> {
|
||||
Ok(self.execution_result.read().clone().unwrap())
|
||||
fn replay(&self, _id: TransactionID, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
self.execution_result.read().clone().unwrap()
|
||||
}
|
||||
|
||||
fn block_total_difficulty(&self, _id: BlockID) -> Option<U256> {
|
||||
@ -310,7 +310,7 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
|
||||
fn nonce(&self, address: &Address, id: BlockID) -> Option<U256> {
|
||||
match id {
|
||||
BlockID::Latest => Some(self.nonces.read().get(address).cloned().unwrap_or_else(U256::zero)),
|
||||
BlockID::Latest => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params.account_start_nonce)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use transaction::{LocalizedTransaction, SignedTransaction};
|
||||
use log_entry::LocalizedLogEntry;
|
||||
use filter::Filter;
|
||||
use views::{BlockView};
|
||||
use error::{ImportResult, ExecutionError, ReplayError};
|
||||
use error::{ImportResult, CallError};
|
||||
use receipt::LocalizedReceipt;
|
||||
use trace::LocalizedTrace;
|
||||
use evm::Factory as EvmFactory;
|
||||
@ -151,11 +151,10 @@ pub trait BlockChainClient : Sync + Send {
|
||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>;
|
||||
|
||||
/// Makes a non-persistent transaction call.
|
||||
// TODO: should be able to accept blockchain location for call.
|
||||
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError>;
|
||||
fn call(&self, t: &SignedTransaction, block: BlockID, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
||||
|
||||
/// Replays a given transaction for inspection.
|
||||
fn replay(&self, t: TransactionID, analytics: CallAnalytics) -> Result<Executed, ReplayError>;
|
||||
fn replay(&self, t: TransactionID, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
||||
|
||||
/// Returns traces matching given filter.
|
||||
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>>;
|
||||
|
@ -22,7 +22,7 @@ use basic_types::LogBloom;
|
||||
use client::Error as ClientError;
|
||||
use ipc::binary::{BinaryConvertError, BinaryConvertable};
|
||||
use types::block_import_error::BlockImportError;
|
||||
pub use types::executed::{ExecutionError, ReplayError};
|
||||
pub use types::executed::{ExecutionError, CallError};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
/// Errors concerning transaction processing.
|
||||
|
@ -464,7 +464,7 @@ impl MinerService for Miner {
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
||||
fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
let sealing_work = self.sealing_work.lock();
|
||||
match sealing_work.queue.peek_last_ref() {
|
||||
Some(work) => {
|
||||
@ -484,6 +484,8 @@ impl MinerService for Miner {
|
||||
};
|
||||
// that's just a copy of the state.
|
||||
let mut state = block.state().clone();
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
|
||||
let sender = try!(t.sender().map_err(|e| {
|
||||
let message = format!("Transaction malformed: {:?}", e);
|
||||
ExecutionError::TransactionMalformed(message)
|
||||
@ -495,18 +497,15 @@ impl MinerService for Miner {
|
||||
state.add_balance(&sender, &(needed_balance - balance));
|
||||
}
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let mut ret = Executive::new(&mut state, &env_info, self.engine(), chain.vm_factory()).transact(t, options);
|
||||
let mut ret = try!(Executive::new(&mut state, &env_info, self.engine(), chain.vm_factory()).transact(t, options));
|
||||
|
||||
// TODO gav move this into Executive.
|
||||
if analytics.state_diffing {
|
||||
if let Ok(ref mut x) = ret {
|
||||
x.state_diff = Some(state.diff_from(block.state().clone()));
|
||||
}
|
||||
}
|
||||
ret
|
||||
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
||||
|
||||
Ok(ret)
|
||||
},
|
||||
None => {
|
||||
chain.call(t, analytics)
|
||||
chain.call(t, BlockID::Latest, analytics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ use util::{H256, U256, Address, Bytes};
|
||||
use client::{MiningBlockChainClient, Executed, CallAnalytics};
|
||||
use block::ClosedBlock;
|
||||
use receipt::Receipt;
|
||||
use error::{Error, ExecutionError};
|
||||
use error::{Error, CallError};
|
||||
use transaction::SignedTransaction;
|
||||
|
||||
/// Miner client API
|
||||
@ -163,7 +163,7 @@ pub trait MinerService : Send + Sync {
|
||||
fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256;
|
||||
|
||||
/// Call into contract code using pending state.
|
||||
fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError>;
|
||||
fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
||||
|
||||
/// Get storage value in pending state.
|
||||
fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256;
|
||||
|
@ -175,7 +175,7 @@ impl State {
|
||||
/// Get the nonce of account `a`.
|
||||
pub fn nonce(&self, a: &Address) -> U256 {
|
||||
self.ensure_cached(a, false,
|
||||
|a| a.as_ref().map_or(U256::zero(), |account| *account.nonce()))
|
||||
|a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce()))
|
||||
}
|
||||
|
||||
/// Mutate storage of account `address` so that it is `value` for `key`.
|
||||
|
@ -104,7 +104,7 @@ pub struct Executed {
|
||||
}
|
||||
|
||||
/// Result of executing the transaction.
|
||||
#[derive(PartialEq, Debug, Binary)]
|
||||
#[derive(PartialEq, Debug, Clone, Binary)]
|
||||
pub enum ExecutionError {
|
||||
/// Returned when there gas paid for transaction execution is
|
||||
/// lower than base gas required.
|
||||
@ -171,19 +171,25 @@ impl fmt::Display for ExecutionError {
|
||||
}
|
||||
|
||||
/// Result of executing the transaction.
|
||||
#[derive(PartialEq, Debug, Binary)]
|
||||
pub enum ReplayError {
|
||||
#[derive(PartialEq, Debug, Clone, Binary)]
|
||||
pub enum CallError {
|
||||
/// Couldn't find the transaction in the chain.
|
||||
TransactionNotFound,
|
||||
/// Couldn't find the transaction block's state in the chain.
|
||||
/// Couldn't find requested block's state in the chain.
|
||||
StatePruned,
|
||||
/// Error executing.
|
||||
Execution(ExecutionError),
|
||||
}
|
||||
|
||||
impl fmt::Display for ReplayError {
|
||||
impl From<ExecutionError> for CallError {
|
||||
fn from(error: ExecutionError) -> Self {
|
||||
CallError::Execution(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CallError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::ReplayError::*;
|
||||
use self::CallError::*;
|
||||
|
||||
let msg = match *self {
|
||||
TransactionNotFound => "Transaction couldn't be found in the chain".into(),
|
||||
@ -191,7 +197,7 @@ impl fmt::Display for ReplayError {
|
||||
Execution(ref e) => format!("{}", e),
|
||||
};
|
||||
|
||||
f.write_fmt(format_args!("Transaction replay error ({}).", msg))
|
||||
f.write_fmt(format_args!("Transaction execution error ({}).", msg))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ use std::mem;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
/// Uniquely identifies block.
|
||||
#[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)]
|
||||
#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq, Binary)]
|
||||
pub enum BlockID {
|
||||
/// Block's sha3.
|
||||
/// Querying by hash is always faster.
|
||||
|
@ -44,8 +44,7 @@ use self::ethash::SeedHashCompute;
|
||||
use v1::traits::Eth;
|
||||
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256};
|
||||
use v1::helpers::CallRequest as CRequest;
|
||||
use v1::impls::{default_gas_price, dispatch_transaction, error_codes};
|
||||
use serde;
|
||||
use v1::impls::{default_gas_price, dispatch_transaction, error_codes, from_params_default_second, from_params_default_third};
|
||||
|
||||
/// Eth RPC options
|
||||
pub struct EthClientOptions {
|
||||
@ -215,27 +214,6 @@ pub fn pending_logs<M>(miner: &M, filter: &EthcoreFilter) -> Vec<Log> where M: M
|
||||
|
||||
const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6.
|
||||
|
||||
fn params_len(params: &Params) -> usize {
|
||||
match params {
|
||||
&Params::Array(ref vec) => vec.len(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
|
||||
_ => from_params::<(F, BlockNumber)>(params),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)),
|
||||
_ => from_params::<(F1, F2, BlockNumber)>(params)
|
||||
}
|
||||
}
|
||||
|
||||
fn make_unsupported_err() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::UNSUPPORTED_REQUEST_CODE),
|
||||
@ -656,8 +634,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
let signed = try!(self.sign_call(request));
|
||||
let r = match block_number {
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()),
|
||||
BlockNumber::Latest => take_weak!(self.client).call(&signed, Default::default()),
|
||||
_ => panic!("{:?}", block_number),
|
||||
block_number => take_weak!(self.client).call(&signed, block_number.into(), Default::default()),
|
||||
};
|
||||
to_value(&r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![])))
|
||||
})
|
||||
@ -671,8 +648,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
let signed = try!(self.sign_call(request));
|
||||
let r = match block_number {
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()),
|
||||
BlockNumber::Latest => take_weak!(self.client).call(&signed, Default::default()),
|
||||
_ => return Err(Error::invalid_params()),
|
||||
block => take_weak!(self.client).call(&signed, block.into(), Default::default()),
|
||||
};
|
||||
to_value(&RpcU256::from(r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0))))
|
||||
})
|
||||
|
@ -26,7 +26,7 @@ use ethcore::account_provider::AccountProvider;
|
||||
use v1::helpers::{SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationsQueue, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest};
|
||||
use v1::traits::EthSigning;
|
||||
use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, U256 as RpcU256};
|
||||
use v1::impls::{default_gas_price, sign_and_dispatch, transaction_rejected_error, signer_disabled_error};
|
||||
use v1::impls::{default_gas_price, sign_and_dispatch, request_rejected_error, request_not_found_error, signer_disabled_error};
|
||||
|
||||
fn fill_optional_fields<C, M>(request: TRequest, client: &C, miner: &M) -> FilledRequest
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
@ -143,7 +143,7 @@ impl<C, M> EthSigning for EthSigningQueueClient<C, M>
|
||||
})
|
||||
}
|
||||
|
||||
fn check_transaction(&self, params: Params) -> Result<Value, Error> {
|
||||
fn check_request(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
let mut pending = self.pending.lock();
|
||||
from_params::<(RpcU256, )>(params).and_then(|(id, )| {
|
||||
@ -151,10 +151,10 @@ impl<C, M> EthSigning for EthSigningQueueClient<C, M>
|
||||
let res = match pending.get(&id) {
|
||||
Some(ref promise) => match promise.result() {
|
||||
ConfirmationResult::Waiting => { return Ok(Value::Null); }
|
||||
ConfirmationResult::Rejected => Err(transaction_rejected_error()),
|
||||
ConfirmationResult::Rejected => Err(request_rejected_error()),
|
||||
ConfirmationResult::Confirmed(rpc_response) => rpc_response,
|
||||
},
|
||||
_ => { return Err(Error::invalid_params()); }
|
||||
_ => { return Err(request_not_found_error()); }
|
||||
};
|
||||
pending.remove(&id);
|
||||
res
|
||||
@ -225,7 +225,7 @@ impl<C, M> EthSigning for EthSigningUnsafeClient<C, M> where
|
||||
Err(signer_disabled_error())
|
||||
}
|
||||
|
||||
fn check_transaction(&self, _: Params) -> Result<Value, Error> {
|
||||
fn check_request(&self, _: Params) -> Result<Value, Error> {
|
||||
// We don't support this in non-signer mode.
|
||||
Err(signer_disabled_error())
|
||||
}
|
||||
|
@ -53,8 +53,9 @@ pub use self::ethcore_set::EthcoreSetClient;
|
||||
pub use self::traces::TracesClient;
|
||||
pub use self::rpc::RpcClient;
|
||||
|
||||
use serde;
|
||||
use v1::helpers::TransactionRequest;
|
||||
use v1::types::{H256 as RpcH256, H520 as RpcH520};
|
||||
use v1::types::{H256 as RpcH256, H520 as RpcH520, BlockNumber};
|
||||
use ethcore::error::Error as EthcoreError;
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::client::MiningBlockChainClient;
|
||||
@ -63,7 +64,7 @@ use ethcore::account_provider::{AccountProvider, Error as AccountError};
|
||||
use util::{U256, H256, Address};
|
||||
use util::rlp::encode;
|
||||
use util::bytes::ToPretty;
|
||||
use jsonrpc_core::{Error, ErrorCode, Value, to_value};
|
||||
use jsonrpc_core::{Error, ErrorCode, Value, to_value, from_params, Params};
|
||||
|
||||
mod error_codes {
|
||||
// NOTE [ToDr] Codes from [-32099, -32000]
|
||||
@ -72,12 +73,37 @@ mod error_codes {
|
||||
pub const NO_AUTHOR_CODE: i64 = -32002;
|
||||
pub const UNKNOWN_ERROR: i64 = -32009;
|
||||
pub const TRANSACTION_ERROR: i64 = -32010;
|
||||
pub const TRANSACTION_REJECTED: i64 = -32011;
|
||||
pub const ACCOUNT_LOCKED: i64 = -32020;
|
||||
pub const PASSWORD_INVALID: i64 = -32021;
|
||||
pub const SIGNER_DISABLED: i64 = -32030;
|
||||
pub const REQUEST_REJECTED: i64 = -32040;
|
||||
pub const REQUEST_NOT_FOUND: i64 = -32041;
|
||||
}
|
||||
|
||||
fn params_len(params: &Params) -> usize {
|
||||
match params {
|
||||
&Params::Array(ref vec) => vec.len(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize request parameters with optional second parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
|
||||
pub fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
|
||||
_ => from_params::<(F, BlockNumber)>(params),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
|
||||
pub fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)),
|
||||
_ => from_params::<(F1, F2, BlockNumber)>(params)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error>
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
let hash = RpcH256::from(signed_transaction.hash());
|
||||
@ -171,11 +197,20 @@ fn password_error(error: AccountError) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error returned when transaction is rejected (in Trusted Signer).
|
||||
pub fn transaction_rejected_error() -> Error {
|
||||
/// Error returned when request is rejected (in Trusted Signer).
|
||||
pub fn request_rejected_error() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::TRANSACTION_REJECTED),
|
||||
message: "Transaction has been rejected.".into(),
|
||||
code: ErrorCode::ServerError(error_codes::REQUEST_REJECTED),
|
||||
message: "Request has been rejected.".into(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Error returned when request is not found in queue.
|
||||
pub fn request_not_found_error() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::REQUEST_NOT_FOUND),
|
||||
message: "Request not found.".into(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Act
|
||||
use v1::traits::Traces;
|
||||
use v1::helpers::CallRequest as CRequest;
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
|
||||
use v1::impls::from_params_default_third;
|
||||
|
||||
fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
|
||||
CallAnalytics {
|
||||
@ -122,11 +123,11 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
|
||||
|
||||
fn call(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
from_params(params)
|
||||
.and_then(|(request, flags)| {
|
||||
from_params_default_third(params)
|
||||
.and_then(|(request, flags, block)| {
|
||||
let request = CallRequest::into(request);
|
||||
let signed = try!(self.sign_call(request));
|
||||
match take_weak!(self.client).call(&signed, to_call_analytics(flags)) {
|
||||
match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) {
|
||||
Ok(e) => to_value(&TraceResults::from(e)),
|
||||
_ => Ok(Value::Null),
|
||||
}
|
||||
@ -135,11 +136,11 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
|
||||
|
||||
fn raw_transaction(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(Bytes, _)>(params)
|
||||
.and_then(|(raw_transaction, flags)| {
|
||||
let raw_transaction = raw_transaction.to_vec();
|
||||
from_params_default_third(params)
|
||||
.and_then(|(raw_transaction, flags, block)| {
|
||||
let raw_transaction = Bytes::to_vec(raw_transaction);
|
||||
match UntrustedRlp::new(&raw_transaction).as_val() {
|
||||
Ok(signed) => match take_weak!(self.client).call(&signed, to_call_analytics(flags)) {
|
||||
Ok(signed) => match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) {
|
||||
Ok(e) => to_value(&TraceResults::from(e)),
|
||||
_ => Ok(Value::Null),
|
||||
},
|
||||
|
@ -238,6 +238,54 @@ const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{
|
||||
}
|
||||
"#;
|
||||
|
||||
const POSITIVE_NONCE_SPEC: &'static [u8] = br#"{
|
||||
"name": "Frontier (Test)",
|
||||
"engine": {
|
||||
"Ethash": {
|
||||
"params": {
|
||||
"gasLimitBoundDivisor": "0x0400",
|
||||
"minimumDifficulty": "0x020000",
|
||||
"difficultyBoundDivisor": "0x0800",
|
||||
"durationLimit": "0x0d",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
|
||||
"daoHardforkTransition": "0xffffffffffffffff",
|
||||
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
|
||||
"daoHardforkAccounts": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"accountStartNonce": "0x0100",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x50000",
|
||||
"networkID" : "0x1"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
"ethereum": {
|
||||
"nonce": "0x0000000000000042",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"difficulty": "0x400000000",
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
|
||||
"gasLimit": "0x50000"
|
||||
},
|
||||
"accounts": {
|
||||
"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 } } } },
|
||||
"faa34835af5c2ea724333018a515fbb7d5bc0b33": { "balance": "10000000000000", "nonce": "0" }
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn eth_transaction_count() {
|
||||
use util::crypto::Secret;
|
||||
@ -367,6 +415,24 @@ fn verify_transaction_counts(name: String, chain: BlockChain) {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn starting_nonce_test() {
|
||||
let tester = EthTester::from_spec_provider(|| Spec::load(POSITIVE_NONCE_SPEC));
|
||||
let address = ::util::hash::Address::from(10);
|
||||
|
||||
let sample = tester.handler.handle_request(&(r#"
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getTransactionCount",
|
||||
"params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"],
|
||||
"id": 15
|
||||
}
|
||||
"#)
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(r#"{"jsonrpc":"2.0","result":"0x0100","id":15}"#, &sample);
|
||||
}
|
||||
|
||||
register_test!(eth_transaction_count_1, verify_transaction_counts, "BlockchainTests/bcWalletTest");
|
||||
register_test!(eth_transaction_count_2, verify_transaction_counts, "BlockchainTests/bcTotalDifficultyTest");
|
||||
register_test!(eth_transaction_count_3, verify_transaction_counts, "BlockchainTests/bcGasPricerTest");
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
use util::{Address, H256, Bytes, U256, FixedHash, Uint};
|
||||
use util::standard::*;
|
||||
use ethcore::error::{Error, ExecutionError};
|
||||
use ethcore::error::{Error, CallError};
|
||||
use ethcore::client::{MiningBlockChainClient, Executed, CallAnalytics};
|
||||
use ethcore::block::{ClosedBlock, IsBlock};
|
||||
use ethcore::transaction::SignedTransaction;
|
||||
@ -220,7 +220,7 @@ impl MinerService for TestMinerService {
|
||||
self.latest_closed_block.lock().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone())
|
||||
}
|
||||
|
||||
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
||||
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
|
@ -423,9 +423,9 @@ fn rpc_eth_code() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_eth_call() {
|
||||
fn rpc_eth_call_latest() {
|
||||
let tester = EthTester::default();
|
||||
tester.client.set_execution_result(Executed {
|
||||
tester.client.set_execution_result(Ok(Executed {
|
||||
gas: U256::zero(),
|
||||
gas_used: U256::from(0xff30),
|
||||
refunded: U256::from(0x5),
|
||||
@ -436,7 +436,7 @@ fn rpc_eth_call() {
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
});
|
||||
}));
|
||||
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
@ -458,9 +458,9 @@ fn rpc_eth_call() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_eth_call_default_block() {
|
||||
fn rpc_eth_call() {
|
||||
let tester = EthTester::default();
|
||||
tester.client.set_execution_result(Executed {
|
||||
tester.client.set_execution_result(Ok(Executed {
|
||||
gas: U256::zero(),
|
||||
gas_used: U256::from(0xff30),
|
||||
refunded: U256::from(0x5),
|
||||
@ -471,7 +471,42 @@ fn rpc_eth_call_default_block() {
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
});
|
||||
}));
|
||||
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_call",
|
||||
"params": [{
|
||||
"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
|
||||
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
|
||||
"gas": "0x76c0",
|
||||
"gasPrice": "0x9184e72a000",
|
||||
"value": "0x9184e72a",
|
||||
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
|
||||
},
|
||||
"0x0"],
|
||||
"id": 1
|
||||
}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"0x1234ff","id":1}"#;
|
||||
|
||||
assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_eth_call_default_block() {
|
||||
let tester = EthTester::default();
|
||||
tester.client.set_execution_result(Ok(Executed {
|
||||
gas: U256::zero(),
|
||||
gas_used: U256::from(0xff30),
|
||||
refunded: U256::from(0x5),
|
||||
cumulative_gas_used: U256::zero(),
|
||||
logs: vec![],
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
}));
|
||||
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
@ -494,7 +529,7 @@ fn rpc_eth_call_default_block() {
|
||||
#[test]
|
||||
fn rpc_eth_estimate_gas() {
|
||||
let tester = EthTester::default();
|
||||
tester.client.set_execution_result(Executed {
|
||||
tester.client.set_execution_result(Ok(Executed {
|
||||
gas: U256::zero(),
|
||||
gas_used: U256::from(0xff30),
|
||||
refunded: U256::from(0x5),
|
||||
@ -505,7 +540,7 @@ fn rpc_eth_estimate_gas() {
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
});
|
||||
}));
|
||||
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
@ -529,7 +564,7 @@ fn rpc_eth_estimate_gas() {
|
||||
#[test]
|
||||
fn rpc_eth_estimate_gas_default_block() {
|
||||
let tester = EthTester::default();
|
||||
tester.client.set_execution_result(Executed {
|
||||
tester.client.set_execution_result(Ok(Executed {
|
||||
gas: U256::zero(),
|
||||
gas_used: U256::from(0xff30),
|
||||
refunded: U256::from(0x5),
|
||||
@ -540,7 +575,7 @@ fn rpc_eth_estimate_gas_default_block() {
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
});
|
||||
}));
|
||||
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
|
@ -17,7 +17,7 @@
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use jsonrpc_core::IoHandler;
|
||||
use jsonrpc_core::{IoHandler, to_value};
|
||||
use v1::impls::EthSigningQueueClient;
|
||||
use v1::traits::EthSigning;
|
||||
use v1::helpers::{ConfirmationsQueue, SigningQueue};
|
||||
@ -106,6 +106,65 @@ fn should_post_sign_to_queue() {
|
||||
assert_eq!(tester.queue.requests().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_check_status_of_request() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let address = Address::random();
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_postSign",
|
||||
"params": [
|
||||
""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000005"
|
||||
],
|
||||
"id": 1
|
||||
}"#;
|
||||
tester.io.handle_request(&request).expect("Sent");
|
||||
|
||||
// when
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_checkRequest",
|
||||
"params": ["0x1"],
|
||||
"id": 1
|
||||
}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
|
||||
|
||||
// then
|
||||
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_check_status_of_request_when_its_resolved() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let address = Address::random();
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_postSign",
|
||||
"params": [
|
||||
""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000005"
|
||||
],
|
||||
"id": 1
|
||||
}"#;
|
||||
tester.io.handle_request(&request).expect("Sent");
|
||||
tester.queue.request_confirmed(U256::from(1), to_value(&"Hello World!"));
|
||||
|
||||
// when
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_checkRequest",
|
||||
"params": ["0x1"],
|
||||
"id": 1
|
||||
}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"Hello World!","id":1}"#;
|
||||
|
||||
// then
|
||||
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_sign_if_account_is_unlocked() {
|
||||
// given
|
||||
|
@ -220,20 +220,21 @@ pub trait EthSigning: Sized + Send + Sync + 'static {
|
||||
/// Will return a transaction ID for later use with check_transaction.
|
||||
fn post_transaction(&self, _: Params) -> Result<Value, Error>;
|
||||
|
||||
/// Checks the progress of a previously posted transaction.
|
||||
/// Checks the progress of a previously posted request (transaction/sign).
|
||||
/// Should be given a valid send_transaction ID.
|
||||
/// Returns the transaction hash, the zero hash (not yet available),
|
||||
/// or the signature,
|
||||
/// or an error.
|
||||
fn check_transaction(&self, _: Params) -> Result<Value, Error>;
|
||||
fn check_request(&self, _: Params) -> Result<Value, Error>;
|
||||
|
||||
/// Should be used to convert object to io delegate.
|
||||
fn to_delegate(self) -> IoDelegate<Self> {
|
||||
let mut delegate = IoDelegate::new(Arc::new(self));
|
||||
delegate.add_method("eth_sign", EthSigning::sign);
|
||||
delegate.add_method("eth_postSign", EthSigning::post_sign);
|
||||
delegate.add_method("eth_sendTransaction", EthSigning::send_transaction);
|
||||
delegate.add_method("eth_postSign", EthSigning::post_sign);
|
||||
delegate.add_method("eth_postTransaction", EthSigning::post_transaction);
|
||||
delegate.add_method("eth_checkTransaction", EthSigning::check_transaction);
|
||||
delegate.add_method("eth_checkRequest", EthSigning::check_request);
|
||||
delegate
|
||||
}
|
||||
}
|
||||
|
@ -479,27 +479,37 @@ known_heap_size!(0, H32, H64, H128, Address, H256, H264, H512, H520, H1024, H204
|
||||
// Specialized HashMap and HashSet
|
||||
|
||||
/// Hasher that just takes 8 bytes of the provided value.
|
||||
pub struct PlainHasher(u64);
|
||||
/// May only be used for keys which are 32 bytes.
|
||||
pub struct PlainHasher {
|
||||
prefix: [u8; 8],
|
||||
_marker: [u64; 0], // for alignment
|
||||
}
|
||||
|
||||
impl Default for PlainHasher {
|
||||
#[inline]
|
||||
fn default() -> PlainHasher {
|
||||
PlainHasher(0)
|
||||
PlainHasher {
|
||||
prefix: [0; 8],
|
||||
_marker: [0; 0],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hasher for PlainHasher {
|
||||
#[inline]
|
||||
fn finish(&self) -> u64 {
|
||||
self.0
|
||||
unsafe { ::std::mem::transmute(self.prefix) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
debug_assert!(bytes.len() == 32);
|
||||
let mut prefix = [0u8; 8];
|
||||
prefix.clone_from_slice(&bytes[0..8]);
|
||||
self.0 = unsafe { ::std::mem::transmute(prefix) };
|
||||
|
||||
for quarter in bytes.chunks(8) {
|
||||
for (x, y) in self.prefix.iter_mut().zip(quarter) {
|
||||
*x ^= *y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,6 +524,12 @@ mod tests {
|
||||
use uint::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn hasher_alignment() {
|
||||
use std::mem::align_of;
|
||||
assert_eq!(align_of::<u64>(), align_of::<PlainHasher>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(feature="dev", allow(eq_op))]
|
||||
fn hash() {
|
||||
|
@ -28,7 +28,7 @@ const DB_BACKGROUND_COMPACTIONS: i32 = 2;
|
||||
|
||||
/// Write transaction. Batches a sequence of put/delete operations for efficiency.
|
||||
pub struct DBTransaction {
|
||||
ops: RwLock<Vec<DBOp>>,
|
||||
ops: Mutex<Vec<DBOp>>,
|
||||
}
|
||||
|
||||
enum DBOp {
|
||||
@ -52,7 +52,7 @@ impl DBTransaction {
|
||||
/// Create new transaction.
|
||||
pub fn new(_db: &Database) -> DBTransaction {
|
||||
DBTransaction {
|
||||
ops: RwLock::new(Vec::with_capacity(256)),
|
||||
ops: Mutex::new(Vec::with_capacity(256)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ impl DBTransaction {
|
||||
pub fn put(&self, col: Option<u32>, key: &[u8], value: &[u8]) -> Result<(), String> {
|
||||
let mut ekey = ElasticArray32::new();
|
||||
ekey.append_slice(key);
|
||||
self.ops.write().push(DBOp::Insert {
|
||||
self.ops.lock().push(DBOp::Insert {
|
||||
col: col,
|
||||
key: ekey,
|
||||
value: value.to_vec(),
|
||||
@ -72,7 +72,7 @@ impl DBTransaction {
|
||||
pub fn put_vec(&self, col: Option<u32>, key: &[u8], value: Bytes) -> Result<(), String> {
|
||||
let mut ekey = ElasticArray32::new();
|
||||
ekey.append_slice(key);
|
||||
self.ops.write().push(DBOp::Insert {
|
||||
self.ops.lock().push(DBOp::Insert {
|
||||
col: col,
|
||||
key: ekey,
|
||||
value: value,
|
||||
@ -85,7 +85,7 @@ impl DBTransaction {
|
||||
pub fn put_compressed(&self, col: Option<u32>, key: &[u8], value: Bytes) -> Result<(), String> {
|
||||
let mut ekey = ElasticArray32::new();
|
||||
ekey.append_slice(key);
|
||||
self.ops.write().push(DBOp::InsertCompressed {
|
||||
self.ops.lock().push(DBOp::InsertCompressed {
|
||||
col: col,
|
||||
key: ekey,
|
||||
value: value,
|
||||
@ -97,7 +97,7 @@ impl DBTransaction {
|
||||
pub fn delete(&self, col: Option<u32>, key: &[u8]) -> Result<(), String> {
|
||||
let mut ekey = ElasticArray32::new();
|
||||
ekey.append_slice(key);
|
||||
self.ops.write().push(DBOp::Delete {
|
||||
self.ops.lock().push(DBOp::Delete {
|
||||
col: col,
|
||||
key: ekey,
|
||||
});
|
||||
@ -290,30 +290,30 @@ impl Database {
|
||||
}
|
||||
|
||||
|
||||
fn to_overly_column(col: Option<u32>) -> usize {
|
||||
fn to_overlay_column(col: Option<u32>) -> usize {
|
||||
col.map_or(0, |c| (c + 1) as usize)
|
||||
}
|
||||
|
||||
/// Commit transaction to database.
|
||||
pub fn write_buffered(&self, tr: DBTransaction) -> Result<(), String> {
|
||||
let mut overlay = self.overlay.write();
|
||||
let ops = mem::replace(&mut *tr.ops.write(), Vec::new());
|
||||
let ops = tr.ops.into_inner();
|
||||
for op in ops {
|
||||
match op {
|
||||
DBOp::Insert { col, key, value } => {
|
||||
let c = Self::to_overly_column(col);
|
||||
let c = Self::to_overlay_column(col);
|
||||
overlay[c].deletions.remove(&key);
|
||||
overlay[c].compressed_insertions.remove(&key);
|
||||
overlay[c].insertions.insert(key, value);
|
||||
},
|
||||
DBOp::InsertCompressed { col, key, value } => {
|
||||
let c = Self::to_overly_column(col);
|
||||
let c = Self::to_overlay_column(col);
|
||||
overlay[c].deletions.remove(&key);
|
||||
overlay[c].insertions.remove(&key);
|
||||
overlay[c].compressed_insertions.insert(key, value);
|
||||
},
|
||||
DBOp::Delete { col, key } => {
|
||||
let c = Self::to_overly_column(col);
|
||||
let c = Self::to_overlay_column(col);
|
||||
overlay[c].insertions.remove(&key);
|
||||
overlay[c].compressed_insertions.remove(&key);
|
||||
overlay[c].deletions.insert(key);
|
||||
@ -364,7 +364,7 @@ impl Database {
|
||||
/// Commit transaction to database.
|
||||
pub fn write(&self, tr: DBTransaction) -> Result<(), String> {
|
||||
let batch = WriteBatch::new();
|
||||
let ops = mem::replace(&mut *tr.ops.write(), Vec::new());
|
||||
let ops = tr.ops.into_inner();
|
||||
for op in ops {
|
||||
match op {
|
||||
DBOp::Insert { col, key, value } => {
|
||||
@ -384,7 +384,7 @@ impl Database {
|
||||
|
||||
/// Get value by key.
|
||||
pub fn get(&self, col: Option<u32>, key: &[u8]) -> Result<Option<Bytes>, String> {
|
||||
let overlay = &self.overlay.read()[Self::to_overly_column(col)];
|
||||
let overlay = &self.overlay.read()[Self::to_overlay_column(col)];
|
||||
overlay.insertions.get(key).or_else(|| overlay.compressed_insertions.get(key)).map_or_else(||
|
||||
col.map_or_else(
|
||||
|| self.db.get(key).map(|r| r.map(|v| v.to_vec())),
|
||||
|
Loading…
Reference in New Issue
Block a user