Backport commits to beta (#1763)
* Don't try to sync to ancient blocks * Parallel block body download * Fixed reading chunked EIP8 handshake (#1712) * Fixed reading chunked EIP8 handshake * Added missing break * Disconnect peers on a fork * Updated json-ipc-server * Combine mining queue and enabled into single locked datum (#1749) * Combine mining queue and enabled into single locked datum Additional tracing. * Fix bug uncovered by test. * Fix typo * Remove unneeded log initialisation in test. * fix failing test (#1756) * Fixed test * Suicides tracing (#1688) * tracing suicide * fixed #1635 * fixed typo * Stackoverflow #1686 (#1698) * flat trace serialization * tracing finds transaction which creates contract * flatten traces before inserting them to the db * Trace other types of calls (#1727) * Trace through DELEGATECALL and CALLCODE Add them to the JSON output and RLP database store. * Fix tests. * Fix all tests. * Fix one more test. * filtering transactions toAddress includes contract creation (#1697) * tracing finds transaction which creates contract * comma cleanup Remove when following `}`s, add to final entries. * Various improvements to tracing & diagnostics. (#1707) * Various improvements to tracing & diagnostics. - Manage possibility of `Account` not having code for `PodAccount` - New RPC: `trace_sendRawTransaction` - See raw transaction dump when inspecting over RPC * Fix test * Remove one of the dupe error messages * Remove unneeded `&`s * Reformat and extremely minor optimisation * Minor optimisation * Remove unneeded let * Fix tests. * Additional fix. * Minor rename. * Bowing to the pressure. * Stackoverflow fix (#1742) * executive tracer builds flat traces without intermediate struct * temporarilt commented out tests for traces * fixed new way of building trace address * fixed new way of building trace address * updating state tests with flat tracing in progress * fixed flat tracing tests * fixed compiling ethcore-rpc with new flat traces * removed warnings from ethcore module * remove unused data structures
This commit is contained in:
committed by
Gav Wood
parent
429c83f92f
commit
8017daf47c
@@ -18,13 +18,13 @@
|
||||
|
||||
use std::sync::{Weak, Arc};
|
||||
use jsonrpc_core::*;
|
||||
use std::collections::BTreeMap;
|
||||
use util::H256;
|
||||
use util::rlp::{UntrustedRlp, View};
|
||||
use ethcore::client::{BlockChainClient, CallAnalytics, TransactionID, TraceId};
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
|
||||
use v1::traits::Traces;
|
||||
use v1::types::{TraceFilter, LocalizedTrace, Trace, BlockNumber, Index, CallRequest, Bytes, StateDiff, VMTrace};
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults};
|
||||
|
||||
/// Traces api implementation.
|
||||
pub struct TracesClient<C, M> where C: BlockChainClient, M: MinerService {
|
||||
@@ -113,22 +113,30 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
|
||||
state_diffing: flags.contains(&("stateDiff".to_owned())),
|
||||
};
|
||||
let signed = try!(self.sign_call(request));
|
||||
let r = take_weak!(self.client).call(&signed, analytics);
|
||||
if let Ok(executed) = r {
|
||||
// TODO maybe add other stuff to this?
|
||||
let mut ret = map!["output".to_owned() => to_value(&Bytes(executed.output)).unwrap()];
|
||||
if let Some(trace) = executed.trace {
|
||||
ret.insert("trace".to_owned(), to_value(&Trace::from(trace)).unwrap());
|
||||
}
|
||||
if let Some(vm_trace) = executed.vm_trace {
|
||||
ret.insert("vmTrace".to_owned(), to_value(&VMTrace::from(vm_trace)).unwrap());
|
||||
}
|
||||
if let Some(state_diff) = executed.state_diff {
|
||||
ret.insert("stateDiff".to_owned(), to_value(&StateDiff::from(state_diff)).unwrap());
|
||||
}
|
||||
return Ok(Value::Object(ret))
|
||||
match take_weak!(self.client).call(&signed, analytics) {
|
||||
Ok(e) => to_value(&TraceResults::from(e)),
|
||||
_ => Ok(Value::Null),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn raw_transaction(&self, params: Params) -> Result<Value, Error> {
|
||||
trace!(target: "jsonrpc", "call: {:?}", params);
|
||||
from_params::<(Bytes, Vec<String>)>(params)
|
||||
.and_then(|(raw_transaction, flags)| {
|
||||
let raw_transaction = raw_transaction.to_vec();
|
||||
let analytics = CallAnalytics {
|
||||
transaction_tracing: flags.contains(&("trace".to_owned())),
|
||||
vm_tracing: flags.contains(&("vmTrace".to_owned())),
|
||||
state_diffing: flags.contains(&("stateDiff".to_owned())),
|
||||
};
|
||||
match UntrustedRlp::new(&raw_transaction).as_val() {
|
||||
Ok(signed) => match take_weak!(self.client).call(&signed, analytics) {
|
||||
Ok(e) => to_value(&TraceResults::from(e)),
|
||||
_ => Ok(Value::Null),
|
||||
},
|
||||
Err(_) => Err(Error::invalid_params()),
|
||||
}
|
||||
Ok(Value::Null)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +366,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,"creates":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","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"value":"0x0a"},"id":1}"#;
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getTransactionByHash",
|
||||
@@ -430,7 +430,7 @@ fn rpc_eth_call() {
|
||||
logs: vec![],
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: None,
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
});
|
||||
@@ -465,7 +465,7 @@ fn rpc_eth_call_default_block() {
|
||||
logs: vec![],
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: None,
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
});
|
||||
@@ -499,7 +499,7 @@ fn rpc_eth_estimate_gas() {
|
||||
logs: vec![],
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: None,
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
});
|
||||
@@ -534,7 +534,7 @@ fn rpc_eth_estimate_gas_default_block() {
|
||||
logs: vec![],
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: None,
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
});
|
||||
|
||||
@@ -35,6 +35,9 @@ pub trait Traces: Sized + Send + Sync + 'static {
|
||||
/// Executes the given call and returns a number of possible traces for it.
|
||||
fn call(&self, _: Params) -> Result<Value, Error>;
|
||||
|
||||
/// Executes the given raw transaction and returns a number of possible traces for it.
|
||||
fn raw_transaction(&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));
|
||||
@@ -43,6 +46,7 @@ pub trait Traces: Sized + Send + Sync + 'static {
|
||||
delegate.add_method("trace_transaction", Traces::transaction_traces);
|
||||
delegate.add_method("trace_block", Traces::block_traces);
|
||||
delegate.add_method("trace_call", Traces::call);
|
||||
delegate.add_method("trace_rawTransaction", Traces::raw_transaction);
|
||||
|
||||
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","creates":null}]"#);
|
||||
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,"raw":"0x"}]"#);
|
||||
|
||||
let t = BlockTransactions::Hashes(vec![H256::default()]);
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
|
||||
@@ -41,5 +41,5 @@ pub use self::transaction::Transaction;
|
||||
pub use self::transaction_request::{TransactionRequest, TransactionConfirmation, TransactionModification};
|
||||
pub use self::call_request::CallRequest;
|
||||
pub use self::receipt::Receipt;
|
||||
pub use self::trace::{Trace, LocalizedTrace, StateDiff, VMTrace};
|
||||
pub use self::trace::{LocalizedTrace, TraceResults};
|
||||
pub use self::trace_filter::TraceFilter;
|
||||
|
||||
@@ -18,11 +18,13 @@ use std::collections::BTreeMap;
|
||||
use util::{Address, U256, H256, Uint};
|
||||
use serde::{Serialize, Serializer};
|
||||
use ethcore::trace::trace;
|
||||
use ethcore::trace::{Trace as EthTrace, LocalizedTrace as EthLocalizedTrace};
|
||||
use ethcore::trace::{FlatTrace, LocalizedTrace as EthLocalizedTrace};
|
||||
use ethcore::trace as et;
|
||||
use ethcore::state_diff;
|
||||
use ethcore::account_diff;
|
||||
use v1::types::Bytes;
|
||||
use v1::types::{Bytes};
|
||||
use ethcore::client::Executed;
|
||||
use ethcore::executed;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
/// A diff of some chunk of memory.
|
||||
@@ -193,6 +195,7 @@ impl From<account_diff::AccountDiff> for AccountDiff {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Serde-friendly `StateDiff` shadow.
|
||||
pub struct StateDiff(BTreeMap<Address, AccountDiff>);
|
||||
|
||||
@@ -233,6 +236,34 @@ impl From<trace::Create> for Create {
|
||||
}
|
||||
}
|
||||
|
||||
/// Call type.
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum CallType {
|
||||
/// None
|
||||
#[serde(rename="none")]
|
||||
None,
|
||||
/// Call
|
||||
#[serde(rename="call")]
|
||||
Call,
|
||||
/// Call code
|
||||
#[serde(rename="callcode")]
|
||||
CallCode,
|
||||
/// Delegate call
|
||||
#[serde(rename="delegatecall")]
|
||||
DelegateCall,
|
||||
}
|
||||
|
||||
impl From<executed::CallType> for CallType {
|
||||
fn from(c: executed::CallType) -> Self {
|
||||
match c {
|
||||
executed::CallType::None => CallType::None,
|
||||
executed::CallType::Call => CallType::Call,
|
||||
executed::CallType::CallCode => CallType::CallCode,
|
||||
executed::CallType::DelegateCall => CallType::DelegateCall,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Call response
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Call {
|
||||
@@ -246,6 +277,9 @@ pub struct Call {
|
||||
gas: U256,
|
||||
/// Input data
|
||||
input: Bytes,
|
||||
/// The type of the call.
|
||||
#[serde(rename="callType")]
|
||||
call_type: CallType,
|
||||
}
|
||||
|
||||
impl From<trace::Call> for Call {
|
||||
@@ -256,6 +290,29 @@ impl From<trace::Call> for Call {
|
||||
value: c.value,
|
||||
gas: c.gas,
|
||||
input: Bytes::new(c.input),
|
||||
call_type: c.call_type.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Suicide
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Suicide {
|
||||
/// Address.
|
||||
pub address: Address,
|
||||
/// Refund address.
|
||||
#[serde(rename="refundAddress")]
|
||||
pub refund_address: Address,
|
||||
/// Balance.
|
||||
pub balance: U256,
|
||||
}
|
||||
|
||||
impl From<trace::Suicide> for Suicide {
|
||||
fn from(s: trace::Suicide) -> Self {
|
||||
Suicide {
|
||||
address: s.address.into(),
|
||||
refund_address: s.refund_address.into(),
|
||||
balance: s.balance.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,13 +326,17 @@ pub enum Action {
|
||||
/// Create
|
||||
#[serde(rename="create")]
|
||||
Create(Create),
|
||||
/// Suicide
|
||||
#[serde(rename="suicide")]
|
||||
Suicide(Suicide),
|
||||
}
|
||||
|
||||
impl From<trace::Action> for Action {
|
||||
fn from(c: trace::Action) -> Self {
|
||||
match c {
|
||||
trace::Action::Call(call) => Action::Call(Call::from(call)),
|
||||
trace::Action::Create(create) => Action::Create(Create::from(create)),
|
||||
trace::Action::Call(call) => Action::Call(call.into()),
|
||||
trace::Action::Create(create) => Action::Create(create.into()),
|
||||
trace::Action::Suicide(suicide) => Action::Suicide(suicide.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,6 +397,9 @@ pub enum Res {
|
||||
/// Creation failure
|
||||
#[serde(rename="failedCreate")]
|
||||
FailedCreate,
|
||||
/// None
|
||||
#[serde(rename="none")]
|
||||
None,
|
||||
}
|
||||
|
||||
impl From<trace::Res> for Res {
|
||||
@@ -345,6 +409,7 @@ impl From<trace::Res> for Res {
|
||||
trace::Res::Create(create) => Res::Create(CreateResult::from(create)),
|
||||
trace::Res::FailedCall => Res::FailedCall,
|
||||
trace::Res::FailedCreate => Res::FailedCreate,
|
||||
trace::Res::None => Res::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -393,23 +458,50 @@ impl From<EthLocalizedTrace> for LocalizedTrace {
|
||||
/// Trace
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Trace {
|
||||
/// Depth within the call trace tree.
|
||||
depth: usize,
|
||||
/// Trace address
|
||||
#[serde(rename="traceAddress")]
|
||||
trace_address: Vec<U256>,
|
||||
/// Subtraces
|
||||
subtraces: U256,
|
||||
/// Action
|
||||
action: Action,
|
||||
/// Result
|
||||
result: Res,
|
||||
/// Subtraces
|
||||
subtraces: Vec<Trace>,
|
||||
}
|
||||
|
||||
impl From<EthTrace> for Trace {
|
||||
fn from(t: EthTrace) -> Self {
|
||||
impl From<FlatTrace> for Trace {
|
||||
fn from(t: FlatTrace) -> Self {
|
||||
Trace {
|
||||
depth: t.depth.into(),
|
||||
trace_address: t.trace_address.into_iter().map(Into::into).collect(),
|
||||
subtraces: t.subtraces.into(),
|
||||
action: t.action.into(),
|
||||
result: t.result.into(),
|
||||
subtraces: t.subs.into_iter().map(From::from).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
/// A diff of some chunk of memory.
|
||||
pub struct TraceResults {
|
||||
/// The output of the call/create
|
||||
pub output: Vec<u8>,
|
||||
/// The transaction trace.
|
||||
pub trace: Vec<Trace>,
|
||||
/// The transaction trace.
|
||||
#[serde(rename="vmTrace")]
|
||||
pub vm_trace: Option<VMTrace>,
|
||||
/// The transaction trace.
|
||||
#[serde(rename="stateDiff")]
|
||||
pub state_diff: Option<StateDiff>,
|
||||
}
|
||||
|
||||
impl From<Executed> for TraceResults {
|
||||
fn from(t: Executed) -> Self {
|
||||
TraceResults {
|
||||
output: t.output.into(),
|
||||
trace: t.trace.into_iter().map(Into::into).collect(),
|
||||
vm_trace: t.vm_trace.map(Into::into),
|
||||
state_diff: t.state_diff.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -422,6 +514,18 @@ mod tests {
|
||||
use v1::types::Bytes;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_serialize_trace_results() {
|
||||
let r = TraceResults {
|
||||
output: vec![0x60],
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
};
|
||||
let serialized = serde_json::to_string(&r).unwrap();
|
||||
assert_eq!(serialized, r#"{"output":[96],"trace":[],"vmTrace":null,"stateDiff":null}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trace_serialize() {
|
||||
let t = LocalizedTrace {
|
||||
@@ -431,6 +535,7 @@ mod tests {
|
||||
value: U256::from(6),
|
||||
gas: U256::from(7),
|
||||
input: Bytes::new(vec![0x12, 0x34]),
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: Res::Call(CallResult {
|
||||
gas_used: U256::from(8),
|
||||
@@ -444,7 +549,7 @@ mod tests {
|
||||
block_hash: H256::from(14),
|
||||
};
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
assert_eq!(serialized, r#"{"action":{"call":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","input":"0x1234"}},"result":{"call":{"gasUsed":"0x08","output":"0x5678"}},"traceAddress":["0x0a"],"subtraces":"0x01","transactionPosition":"0x0b","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0x0d","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||
assert_eq!(serialized, r#"{"action":{"call":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","input":"0x1234","callType":{"call":[]}}},"result":{"call":{"gasUsed":"0x08","output":"0x5678"}},"traceAddress":["0x0a"],"subtraces":"0x01","transactionPosition":"0x0b","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0x0d","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -520,6 +625,7 @@ mod tests {
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: Bytes::new(vec![0x12, 0x34]),
|
||||
call_type: CallType::Call,
|
||||
}), Action::Create(Create {
|
||||
from: Address::from(5),
|
||||
value: U256::from(6),
|
||||
@@ -528,7 +634,7 @@ mod tests {
|
||||
})];
|
||||
|
||||
let serialized = serde_json::to_string(&actions).unwrap();
|
||||
assert_eq!(serialized, r#"[{"call":{"from":"0x0000000000000000000000000000000000000001","to":"0x0000000000000000000000000000000000000002","value":"0x03","gas":"0x04","input":"0x1234"}},{"create":{"from":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","init":"0x5678"}}]"#);
|
||||
assert_eq!(serialized, r#"[{"call":{"from":"0x0000000000000000000000000000000000000001","to":"0x0000000000000000000000000000000000000002","value":"0x03","gas":"0x04","input":"0x1234","callType":{"call":[]}}},{"create":{"from":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","init":"0x5678"}}]"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use util::numbers::*;
|
||||
use util::rlp::encode;
|
||||
use ethcore::contract_address;
|
||||
use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction};
|
||||
use v1::types::{Bytes, OptionalValue};
|
||||
@@ -50,6 +51,8 @@ pub struct Transaction {
|
||||
pub input: Bytes,
|
||||
/// Creates contract
|
||||
pub creates: OptionalValue<Address>,
|
||||
/// Raw transaction data
|
||||
pub raw: Bytes,
|
||||
}
|
||||
|
||||
impl From<LocalizedTransaction> for Transaction {
|
||||
@@ -73,6 +76,7 @@ impl From<LocalizedTransaction> for Transaction {
|
||||
Action::Create => OptionalValue::Value(contract_address(&t.sender().unwrap(), &t.nonce)),
|
||||
Action::Call(_) => OptionalValue::Null,
|
||||
},
|
||||
raw: encode(&t.signed).to_vec().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,6 +102,7 @@ impl From<SignedTransaction> for Transaction {
|
||||
Action::Create => OptionalValue::Value(contract_address(&t.sender().unwrap(), &t.nonce)),
|
||||
Action::Call(_) => OptionalValue::Null,
|
||||
},
|
||||
raw: encode(&t).to_vec().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,7 +116,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","creates":null}"#);
|
||||
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,"raw":"0x"}"#);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user