VM tracing and JSON RPC endpoint for it. (#1169)
* Groundwork for basic VM tracing. * RPC endpoint for VM tracing and ser/de types ready. * Create VMTracer trait. * Rearchitected VM tracing to reflect existing tracing. Should more or less work now. * Integrated VM tracing into JSONRPC. * Fix ethcore module tests. * Add tests for VM tracing. * Fix consensus test code. * Fix mock tests. * Added VM trace information for post-execution stuff. * Fix max-value calls and add "creates" field to getTransaction. * Tests for VM tracing. * Don't implement the trait with unimplemented. * Remove invlaid comment. * Fix tests.
This commit is contained in:
@@ -26,6 +26,7 @@ extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate jsonrpc_core;
|
||||
extern crate jsonrpc_http_server;
|
||||
#[macro_use]
|
||||
extern crate ethcore_util as util;
|
||||
extern crate ethcore;
|
||||
extern crate ethsync;
|
||||
|
||||
@@ -511,8 +511,8 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
|
||||
.and_then(|(request, block_number,)| {
|
||||
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),
|
||||
BlockNumber::Latest => take_weak!(self.client).call(&signed),
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, false),
|
||||
BlockNumber::Latest => take_weak!(self.client).call(&signed, false),
|
||||
_ => panic!("{:?}", block_number),
|
||||
};
|
||||
to_value(&r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![])))
|
||||
@@ -524,8 +524,8 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
|
||||
.and_then(|(request, block_number,)| {
|
||||
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),
|
||||
BlockNumber::Latest => take_weak!(self.client).call(&signed),
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, false),
|
||||
BlockNumber::Latest => take_weak!(self.client).call(&signed, false),
|
||||
_ => return Err(Error::invalid_params()),
|
||||
};
|
||||
to_value(&r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0)))
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Ethcore-specific rpc implementation.
|
||||
use util::{U256, Address, RotatingLogger};
|
||||
use util::{U256, Address, RotatingLogger, FixedHash, Uint};
|
||||
use util::network_settings::NetworkSettings;
|
||||
use util::misc::version_data;
|
||||
use std::sync::{Arc, Weak};
|
||||
@@ -23,29 +23,99 @@ use std::ops::Deref;
|
||||
use std::collections::BTreeMap;
|
||||
use jsonrpc_core::*;
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
|
||||
use ethcore::client::BlockChainClient;
|
||||
use ethcore::trace::VMTrace;
|
||||
use v1::traits::Ethcore;
|
||||
use v1::types::Bytes;
|
||||
use v1::types::{Bytes, CallRequest};
|
||||
|
||||
/// Ethcore implementation.
|
||||
pub struct EthcoreClient<M>
|
||||
where M: MinerService {
|
||||
pub struct EthcoreClient<C, M> where
|
||||
C: BlockChainClient,
|
||||
M: MinerService {
|
||||
|
||||
client: Weak<C>,
|
||||
miner: Weak<M>,
|
||||
logger: Arc<RotatingLogger>,
|
||||
settings: Arc<NetworkSettings>,
|
||||
}
|
||||
|
||||
impl<M> EthcoreClient<M> where M: MinerService {
|
||||
impl<C, M> EthcoreClient<C, M> where C: BlockChainClient, M: MinerService {
|
||||
/// Creates new `EthcoreClient`.
|
||||
pub fn new(miner: &Arc<M>, logger: Arc<RotatingLogger>, settings: Arc<NetworkSettings>) -> Self {
|
||||
pub fn new(client: &Arc<C>, miner: &Arc<M>, logger: Arc<RotatingLogger>, settings: Arc<NetworkSettings>) -> Self {
|
||||
EthcoreClient {
|
||||
client: Arc::downgrade(client),
|
||||
miner: Arc::downgrade(miner),
|
||||
logger: logger,
|
||||
settings: settings,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: share with eth.rs
|
||||
fn sign_call(&self, request: CallRequest) -> Result<SignedTransaction, Error> {
|
||||
let client = take_weak!(self.client);
|
||||
let miner = take_weak!(self.miner);
|
||||
let from = request.from.unwrap_or(Address::zero());
|
||||
Ok(EthTransaction {
|
||||
nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
|
||||
action: request.to.map_or(Action::Create, Action::Call),
|
||||
gas: request.gas.unwrap_or(U256::from(50_000_000)),
|
||||
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
||||
value: request.value.unwrap_or_else(U256::zero),
|
||||
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
||||
}.fake_sign(from))
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> Ethcore for EthcoreClient<M> where M: MinerService + 'static {
|
||||
fn vm_trace_to_object(t: &VMTrace) -> Value {
|
||||
let mut ret = BTreeMap::new();
|
||||
ret.insert("code".to_owned(), to_value(&t.code).unwrap());
|
||||
|
||||
let mut subs = t.subs.iter();
|
||||
let mut next_sub = subs.next();
|
||||
|
||||
let ops = t.operations
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, op)| {
|
||||
let mut m = map![
|
||||
"pc".to_owned() => to_value(&op.pc).unwrap(),
|
||||
"cost".to_owned() => match op.gas_cost <= U256::from(!0u64) {
|
||||
true => to_value(&op.gas_cost.low_u64()),
|
||||
false => to_value(&op.gas_cost),
|
||||
}.unwrap()
|
||||
];
|
||||
if let Some(ref ex) = op.executed {
|
||||
let mut em = map![
|
||||
"used".to_owned() => to_value(&ex.gas_used.low_u64()).unwrap(),
|
||||
"push".to_owned() => to_value(&ex.stack_push).unwrap()
|
||||
];
|
||||
if let Some(ref md) = ex.mem_diff {
|
||||
em.insert("mem".to_owned(), Value::Object(map![
|
||||
"off".to_owned() => to_value(&md.offset).unwrap(),
|
||||
"data".to_owned() => to_value(&md.data).unwrap()
|
||||
]));
|
||||
}
|
||||
if let Some(ref sd) = ex.store_diff {
|
||||
em.insert("store".to_owned(), Value::Object(map![
|
||||
"key".to_owned() => to_value(&sd.location).unwrap(),
|
||||
"val".to_owned() => to_value(&sd.value).unwrap()
|
||||
]));
|
||||
}
|
||||
m.insert("ex".to_owned(), Value::Object(em));
|
||||
}
|
||||
if next_sub.is_some() && next_sub.unwrap().parent_step == i {
|
||||
m.insert("sub".to_owned(), vm_trace_to_object(next_sub.unwrap()));
|
||||
next_sub = subs.next();
|
||||
}
|
||||
Value::Object(m)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
ret.insert("ops".to_owned(), Value::Array(ops));
|
||||
Value::Object(ret)
|
||||
}
|
||||
|
||||
impl<C, M> Ethcore for EthcoreClient<C, M> where C: BlockChainClient + 'static, M: MinerService + 'static {
|
||||
|
||||
fn set_min_gas_price(&self, params: Params) -> Result<Value, Error> {
|
||||
from_params::<(U256,)>(params).and_then(|(gas_price,)| {
|
||||
@@ -135,4 +205,19 @@ impl<M> Ethcore for EthcoreClient<M> where M: MinerService + 'static {
|
||||
let version = version_data();
|
||||
to_value(&Bytes::new(version))
|
||||
}
|
||||
|
||||
fn vm_trace_call(&self, params: Params) -> Result<Value, Error> {
|
||||
trace!(target: "jsonrpc", "vm_trace_call: {:?}", params);
|
||||
from_params(params)
|
||||
.and_then(|(request,)| {
|
||||
let signed = try!(self.sign_call(request));
|
||||
let r = take_weak!(self.client).call(&signed, true);
|
||||
if let Ok(executed) = r {
|
||||
if let Some(vm_trace) = executed.vm_trace {
|
||||
return Ok(vm_trace_to_object(&vm_trace));
|
||||
}
|
||||
}
|
||||
Ok(Value::Null)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,12 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::str::FromStr;
|
||||
|
||||
use ethcore::client::{MiningBlockChainClient, BlockChainClient, Client, ClientConfig};
|
||||
use ethcore::client::{BlockChainClient, Client, ClientConfig};
|
||||
use ethcore::ids::BlockID;
|
||||
use ethcore::spec::{Genesis, Spec};
|
||||
use ethcore::block::Block;
|
||||
use ethcore::views::BlockView;
|
||||
use ethcore::ethereum;
|
||||
use ethcore::transaction::{Transaction, Action};
|
||||
use ethcore::miner::{MinerService, ExternalMiner, Miner};
|
||||
use devtools::RandomTempPath;
|
||||
use util::Hashable;
|
||||
|
||||
@@ -202,7 +202,7 @@ impl MinerService for TestMinerService {
|
||||
self.latest_closed_block.lock().unwrap().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone())
|
||||
}
|
||||
|
||||
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction) -> Result<Executed, ExecutionError> {
|
||||
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _vm_tracing: bool) -> Result<Executed, ExecutionError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ fn rpc_eth_pending_transaction_by_hash() {
|
||||
tester.miner.pending_transactions.lock().unwrap().insert(H256::zero(), tx);
|
||||
}
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x01","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x00","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"value":"0x0a"},"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x01","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x00","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"value":"0x0a"},"id":1}"#;
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getTransactionByHash",
|
||||
@@ -430,6 +430,7 @@ fn rpc_eth_call() {
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: None,
|
||||
vm_trace: None,
|
||||
});
|
||||
|
||||
let request = r#"{
|
||||
@@ -463,6 +464,7 @@ fn rpc_eth_call_default_block() {
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: None,
|
||||
vm_trace: None,
|
||||
});
|
||||
|
||||
let request = r#"{
|
||||
@@ -495,6 +497,7 @@ fn rpc_eth_estimate_gas() {
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: None,
|
||||
vm_trace: None,
|
||||
});
|
||||
|
||||
let request = r#"{
|
||||
@@ -528,6 +531,7 @@ fn rpc_eth_estimate_gas_default_block() {
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: None,
|
||||
vm_trace: None,
|
||||
});
|
||||
|
||||
let request = r#"{
|
||||
|
||||
@@ -18,6 +18,7 @@ use std::sync::Arc;
|
||||
use std::str::FromStr;
|
||||
use jsonrpc_core::IoHandler;
|
||||
use v1::{Ethcore, EthcoreClient};
|
||||
use ethcore::client::{TestBlockChainClient};
|
||||
use ethcore::miner::MinerService;
|
||||
use v1::tests::helpers::TestMinerService;
|
||||
use util::numbers::*;
|
||||
@@ -25,10 +26,15 @@ use rustc_serialize::hex::FromHex;
|
||||
use util::log::RotatingLogger;
|
||||
use util::network_settings::NetworkSettings;
|
||||
|
||||
fn blockchain_client() -> Arc<TestBlockChainClient> {
|
||||
let client = TestBlockChainClient::new();
|
||||
Arc::new(client)
|
||||
}
|
||||
|
||||
fn miner_service() -> Arc<TestMinerService> {
|
||||
Arc::new(TestMinerService::default())
|
||||
}
|
||||
|
||||
fn logger() -> Arc<RotatingLogger> {
|
||||
Arc::new(RotatingLogger::new("rpc=trace".to_owned()))
|
||||
}
|
||||
@@ -45,14 +51,15 @@ fn settings() -> Arc<NetworkSettings> {
|
||||
})
|
||||
}
|
||||
|
||||
fn ethcore_client(miner: &Arc<TestMinerService>) -> EthcoreClient<TestMinerService> {
|
||||
EthcoreClient::new(&miner, logger(), settings())
|
||||
fn ethcore_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>) -> EthcoreClient<TestBlockChainClient, TestMinerService> {
|
||||
EthcoreClient::new(&client, &miner, logger(), settings())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_ethcore_extra_data() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -68,7 +75,8 @@ fn rpc_ethcore_default_extra_data() {
|
||||
use util::ToPretty;
|
||||
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -81,7 +89,8 @@ fn rpc_ethcore_default_extra_data() {
|
||||
#[test]
|
||||
fn rpc_ethcore_gas_floor_target() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -94,7 +103,8 @@ fn rpc_ethcore_gas_floor_target() {
|
||||
#[test]
|
||||
fn rpc_ethcore_min_gas_price() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -107,7 +117,8 @@ fn rpc_ethcore_min_gas_price() {
|
||||
#[test]
|
||||
fn rpc_ethcore_set_min_gas_price() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -121,7 +132,8 @@ fn rpc_ethcore_set_min_gas_price() {
|
||||
#[test]
|
||||
fn rpc_ethcore_set_gas_floor_target() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -135,7 +147,8 @@ fn rpc_ethcore_set_gas_floor_target() {
|
||||
#[test]
|
||||
fn rpc_ethcore_set_extra_data() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -149,7 +162,8 @@ fn rpc_ethcore_set_extra_data() {
|
||||
#[test]
|
||||
fn rpc_ethcore_set_author() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -163,10 +177,11 @@ fn rpc_ethcore_set_author() {
|
||||
#[test]
|
||||
fn rpc_ethcore_dev_logs() {
|
||||
let miner = miner_service();
|
||||
let client = blockchain_client();
|
||||
let logger = logger();
|
||||
logger.append("a".to_owned());
|
||||
logger.append("b".to_owned());
|
||||
let ethcore = EthcoreClient::new(&miner, logger.clone(), settings()).to_delegate();
|
||||
let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings()).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -179,7 +194,8 @@ fn rpc_ethcore_dev_logs() {
|
||||
#[test]
|
||||
fn rpc_ethcore_dev_logs_levels() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -191,7 +207,8 @@ fn rpc_ethcore_dev_logs_levels() {
|
||||
#[test]
|
||||
fn rpc_ethcore_set_transactions_limit() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -205,7 +222,8 @@ fn rpc_ethcore_set_transactions_limit() {
|
||||
#[test]
|
||||
fn rpc_ethcore_transactions_limit() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -218,7 +236,8 @@ fn rpc_ethcore_transactions_limit() {
|
||||
#[test]
|
||||
fn rpc_ethcore_net_chain() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -231,7 +250,8 @@ fn rpc_ethcore_net_chain() {
|
||||
#[test]
|
||||
fn rpc_ethcore_net_max_peers() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -244,7 +264,8 @@ fn rpc_ethcore_net_max_peers() {
|
||||
#[test]
|
||||
fn rpc_ethcore_net_port() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -257,7 +278,8 @@ fn rpc_ethcore_net_port() {
|
||||
#[test]
|
||||
fn rpc_ethcore_rpc_settings() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -270,7 +292,8 @@ fn rpc_ethcore_rpc_settings() {
|
||||
#[test]
|
||||
fn rpc_ethcore_node_name() {
|
||||
let miner = miner_service();
|
||||
let ethcore = ethcore_client(&miner).to_delegate();
|
||||
let client = blockchain_client();
|
||||
let ethcore = ethcore_client(&client, &miner).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
|
||||
@@ -72,6 +72,8 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
|
||||
/// Returns default extra data
|
||||
fn default_extra_data(&self, _: Params) -> Result<Value, Error>;
|
||||
|
||||
/// Executes the given call and returns the VM trace for it.
|
||||
fn vm_trace_call(&self, _: Params) -> Result<Value, Error>;
|
||||
|
||||
/// Should be used to convert object to io delegate.
|
||||
fn to_delegate(self) -> IoDelegate<Self> {
|
||||
@@ -95,6 +97,8 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
|
||||
delegate.add_method("ethcore_nodeName", Ethcore::node_name);
|
||||
delegate.add_method("ethcore_defaultExtraData", Ethcore::default_extra_data);
|
||||
|
||||
delegate.add_method("ethcore_vmTraceCall", Ethcore::vm_trace_call);
|
||||
|
||||
delegate
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ mod tests {
|
||||
fn test_serialize_block_transactions() {
|
||||
let t = BlockTransactions::Full(vec![Transaction::default()]);
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x"}]"#);
|
||||
assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x","creates":null}]"#);
|
||||
|
||||
let t = BlockTransactions::Hashes(vec![H256::default()]);
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use util::numbers::*;
|
||||
use ethcore::contract_address;
|
||||
use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction};
|
||||
use v1::types::{Bytes, OptionalValue};
|
||||
|
||||
@@ -46,7 +47,9 @@ pub struct Transaction {
|
||||
/// Gas
|
||||
pub gas: U256,
|
||||
/// Data
|
||||
pub input: Bytes
|
||||
pub input: Bytes,
|
||||
/// Creates contract
|
||||
pub creates: OptionalValue<Address>,
|
||||
}
|
||||
|
||||
impl From<LocalizedTransaction> for Transaction {
|
||||
@@ -65,7 +68,11 @@ impl From<LocalizedTransaction> for Transaction {
|
||||
value: t.value,
|
||||
gas_price: t.gas_price,
|
||||
gas: t.gas,
|
||||
input: Bytes::new(t.data.clone())
|
||||
input: Bytes::new(t.data.clone()),
|
||||
creates: match t.action {
|
||||
Action::Create => OptionalValue::Value(contract_address(&t.sender().unwrap(), &t.nonce)),
|
||||
Action::Call(_) => OptionalValue::Null,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,7 +93,11 @@ impl From<SignedTransaction> for Transaction {
|
||||
value: t.value,
|
||||
gas_price: t.gas_price,
|
||||
gas: t.gas,
|
||||
input: Bytes::new(t.data.clone())
|
||||
input: Bytes::new(t.data.clone()),
|
||||
creates: match t.action {
|
||||
Action::Create => OptionalValue::Value(contract_address(&t.sender().unwrap(), &t.nonce)),
|
||||
Action::Call(_) => OptionalValue::Null,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +111,7 @@ mod tests {
|
||||
fn test_transaction_serialize() {
|
||||
let t = Transaction::default();
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x"}"#);
|
||||
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x","creates":null}"#);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user