refactor: Refactor evmbin CLI (#10742)
* docs: Add comments to run_transaction arguments * docs: Add general state test example from github.com/ethereum/test * docs: Add state test file used in ethjson * refactor: Reorder CLI options. Modify CLI descriptions. See commit comments * Reorder parity-evm CLI options * Update descriptions for CLI options * Change to `--chain PATH` (general) and `--chain CHAIN` (state test) * Remove unncessary 'Display result state dump in standardized JSON format. * refactor: Move function to be ordered after * refactor: Refactor run_state_test * refactor: Modify run_stats_jsontests_vm comment to be more specific * refactor: Refactor run_call * refactor: Update Args struct including rustdocs * refactor: Reorder functions in Args struct to match other orders * tests: Update tests for evmbin * revert unintentional changes * comply with style guide * docs: Info and Display Modules made public so appear in rustdocs * docs: Rename VM to EVM * docs: Update rustdocs * docs: Update state-test cli command comments Co-Authored-By: David <dvdplm@gmail.com> * docs: Update chain path cli command description Co-Authored-By: David <dvdplm@gmail.com> * docs: Prefix to specify only one chain type to be provided Co-Authored-By: David <dvdplm@gmail.com> * docs: Update to be lowercase fat Co-Authored-By: David <dvdplm@gmail.com> * rename err to stderr, out to stdout * revert to wei for gas price * review-fix: Do not expose private modules but still show docs View docs with: ``` cargo doc -p evmbin --document-private-items --open ``` * test: Read from file. Add initial tests for state-test CLI command * review-fix: Change to single TODO that links to new issue to create integration tests * refactor: Move run_transaction params into fields of a TxInput struct and make doc comments of its fields (#10769) * Question * refactor: Further changes for doc comments to be part of public struct * refactor: Rename InputData to TxInput for clarity in docs * docs: Change String to fixed length str Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * refactor: Update evmbin/src/info.rs moving mut into fn declaration Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * refactor: Update evmbin/src/info.rs moving mut into fn declaration part 2 Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * review-fix: Add missing docs to TxInput transaction and trie_spec * docs: Improve grammar * review-fix: Destructure tx_input * WIP * review-fix: Rename variables of InputTx * rename `spec_from_json` to `fork_spec_from_json` * rename `name` to `state_test_name` * rename `spec` to `fork_spec_name` * rename `spec_checked` to `fork_spec` * review-fix: Rename idx to tx_index * fix indentation * review-fix: Add missing part of tests. Yet to fix tests and add assertions * [evmbin] remove state-db dependency * [evmbin] run_transaction returns bool * [evmbin] more cleanup
This commit is contained in:
parent
46954527e7
commit
c689495826
@ -99,7 +99,7 @@ impl<'a> fmt::Debug for EvmTestClient<'a> {
|
||||
|
||||
impl<'a> EvmTestClient<'a> {
|
||||
/// Converts a json spec definition into spec.
|
||||
pub fn spec_from_json(spec: &ForkSpec) -> Option<spec::Spec> {
|
||||
pub fn fork_spec_from_json(spec: &ForkSpec) -> Option<spec::Spec> {
|
||||
match *spec {
|
||||
ForkSpec::Frontier => Some(ethereum::new_frontier_test()),
|
||||
ForkSpec::Homestead => Some(ethereum::new_homestead_test()),
|
||||
|
@ -65,7 +65,7 @@ pub fn json_chain_test<H: FnMut(&str, HookType)>(json_data: &[u8], start_stop_ho
|
||||
flush!(" - {}...", name);
|
||||
|
||||
let spec = {
|
||||
let mut spec = match EvmTestClient::spec_from_json(&blockchain.network) {
|
||||
let mut spec = match EvmTestClient::fork_spec_from_json(&blockchain.network) {
|
||||
Some(spec) => spec,
|
||||
None => {
|
||||
println!(" - {} | {:?} Ignoring tests because of missing spec", name, blockchain.network);
|
||||
|
@ -62,7 +62,7 @@ pub fn json_chain_test<H: FnMut(&str, HookType)>(json_data: &[u8], start_stop_ho
|
||||
|
||||
for (spec_name, states) in test.post_states {
|
||||
let total = states.len();
|
||||
let spec = match EvmTestClient::spec_from_json(&spec_name) {
|
||||
let spec = match EvmTestClient::fork_spec_from_json(&spec_name) {
|
||||
Some(spec) => spec,
|
||||
None => {
|
||||
println!(" - {} | {:?} Ignoring tests because of missing spec", name, spec_name);
|
||||
|
@ -47,7 +47,7 @@ fn do_json_test<H: FnMut(&str, HookType)>(json_data: &[u8], start_stop_hook: &mu
|
||||
start_stop_hook(&name, HookType::OnStart);
|
||||
|
||||
for (spec_name, result) in test.post_state {
|
||||
let spec = match EvmTestClient::spec_from_json(&spec_name) {
|
||||
let spec = match EvmTestClient::fork_spec_from_json(&spec_name) {
|
||||
Some(spec) => spec,
|
||||
None => {
|
||||
println!(" - {} | {:?} Ignoring tests because of missing spec", name, spec_name);
|
||||
|
@ -308,7 +308,7 @@ impl UnverifiedTransaction {
|
||||
self
|
||||
}
|
||||
|
||||
/// Checks is signature is empty.
|
||||
/// Checks if the signature is empty.
|
||||
pub fn is_unsigned(&self) -> bool {
|
||||
self.r.is_zero() && self.s.is_zero()
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ name = "parity-evm"
|
||||
path = "./src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
account-state = { path = "../ethcore/account-state" }
|
||||
common-types = { path = "../ethcore/types" }
|
||||
docopt = "1.0"
|
||||
env_logger = "0.5"
|
||||
@ -23,7 +24,6 @@ rustc-hex = "1.0"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
account-state = { path = "../ethcore/account-state" }
|
||||
trace = { path = "../ethcore/trace" }
|
||||
vm = { path = "../ethcore/vm" }
|
||||
|
||||
|
@ -30,7 +30,7 @@ Transaction options:
|
||||
--gas-price WEI Supplied gas price as hex (without 0x).
|
||||
|
||||
State test options:
|
||||
--only NAME Runs only a single test matching the name.
|
||||
--only NAME Runs only a single state test matching the name.
|
||||
--chain CHAIN Run only tests from specific chain.
|
||||
|
||||
General options:
|
||||
|
140
evmbin/res/create2callPrecompiles.json
Normal file
140
evmbin/res/create2callPrecompiles.json
Normal file
@ -0,0 +1,140 @@
|
||||
{
|
||||
"create2callPrecompiles": {
|
||||
"_info": {
|
||||
"comment": "CALL precompiles during init code of CREATE2 contract ",
|
||||
"filledwith": "testeth 1.5.0.dev2-73+commit.1bcd29e5",
|
||||
"lllcversion": "Version: 0.4.26-develop.2018.9.19+commit.785cbf40.Linux.g++",
|
||||
"source": "src/GeneralStateTestsFiller/stCreate2/create2callPrecompilesFiller.json",
|
||||
"sourceHash": "0dcd6d7b5819f61399ecfba9a67b7518c92c426866bd5b599516c184d194e51c"
|
||||
},
|
||||
"env": {
|
||||
"currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty": "0x20000",
|
||||
"currentGasLimit": "0xe8d4a51000",
|
||||
"currentNumber": "0x01",
|
||||
"currentTimestamp": "0x03e8",
|
||||
"previousHash": "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"post": {
|
||||
"Constantinople": [
|
||||
{
|
||||
"hash": "0x3dfdcd1d19badbbba8b0c953504e8b4685270ee5b86e155350b6ef1042c9ce43",
|
||||
"indexes": {
|
||||
"data": 0,
|
||||
"gas": 0,
|
||||
"value": 0
|
||||
},
|
||||
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
},
|
||||
{
|
||||
"hash": "0x88803085d3420aec76078e215f67fc5f7b6f297fbe19d85c2236ad685d0fc7fc",
|
||||
"indexes": {
|
||||
"data": 1,
|
||||
"gas": 0,
|
||||
"value": 0
|
||||
},
|
||||
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
},
|
||||
{
|
||||
"hash": "0x57181dda5c067cb31f084c4118791b40d5028c39071e83e60e7f7403d683527e",
|
||||
"indexes": {
|
||||
"data": 2,
|
||||
"gas": 0,
|
||||
"value": 0
|
||||
},
|
||||
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
},
|
||||
{
|
||||
"hash": "0xf04c1039893eb6959354c3c16e9fe025d4b9dc3981362f79c56cc427dca0d544",
|
||||
"indexes": {
|
||||
"data": 3,
|
||||
"gas": 0,
|
||||
"value": 0
|
||||
},
|
||||
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
},
|
||||
{
|
||||
"hash": "0x5d5db3d6c4377b34b74ecf8638f684acb220cc7ce286ae5f000ffa74faf38bae",
|
||||
"indexes": {
|
||||
"data": 4,
|
||||
"gas": 0,
|
||||
"value": 0
|
||||
},
|
||||
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
},
|
||||
{
|
||||
"hash": "0xf8343b2e05ae120bf25947de840cedf1ca2c1bcda1cdb89d218427d8a84d4798",
|
||||
"indexes": {
|
||||
"data": 5,
|
||||
"gas": 0,
|
||||
"value": 0
|
||||
},
|
||||
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
},
|
||||
{
|
||||
"hash": "0x305a8a8a7d9da97d14ed2259503d9373d803ea4b7fbf8c360f50b1b30a3d04ed",
|
||||
"indexes": {
|
||||
"data": 6,
|
||||
"gas": 0,
|
||||
"value": 0
|
||||
},
|
||||
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
},
|
||||
{
|
||||
"hash": "0xde1d3953b508913c6e3e9bd412cd50daf60bb177517e5d1e8ccb0dab193aed03",
|
||||
"indexes": {
|
||||
"data": 7,
|
||||
"gas": 0,
|
||||
"value": 0
|
||||
},
|
||||
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pre": {
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x0de0b6b3a7640000",
|
||||
"code": "",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
},
|
||||
"0xaddf5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x00",
|
||||
"code": "0x600035600052602035602052604035604052606035606052604060c860806000600060066207a120f260005560c85160015560e851600255",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
},
|
||||
"0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x00",
|
||||
"code": "0x60003560005260203560205260403560405260603560605260803560805260a03560a05260c03560c052604061012c60806000600060066207a120f2600055604061019060606080600060076207a120f260015561012c51600a5561014c51600b55610190516014556101b051601555601454600a5414600255601554600b5414600355",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction": {
|
||||
"data": [
|
||||
"0x6000609a80601260003960006000f55000fe7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f160025560a060020a60805106600055600054321460015500",
|
||||
"0x6000602380601260003960006000f55000fe64f34578907f6005526020600060256000600060026101f4f160025560005160005500",
|
||||
"0x6000601a80601260003960006000f55000fe602060006000600060006003610258f160025560005160005500",
|
||||
"0x6000602380601260003960006000f55000fe64f34578907f6000526020600060256000600060046101f4f160025560005160005500",
|
||||
"0x6000609580601260003960006000f55000fe6001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060965260206103e860976000600060055af26001556103e85160025500",
|
||||
"0x6000602180601260003960006000f55000fe600160005260206000610100600060006006620927c0f160025560005160005500",
|
||||
"0x600060b680601260003960006000f55000fe7f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d46060526000600060806000600073addf5374fce5edbc8e2a8697c15331677e6ebf0b6207a120f25000",
|
||||
"0x600060c580601260003960006000f55000fe7f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866000527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4602052600060405260006060527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866080527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d460a052600160c0526000600060e06000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6207a120f25000"
|
||||
],
|
||||
"gasLimit": [
|
||||
"0xe4e1c0"
|
||||
],
|
||||
"gasPrice": "0x01",
|
||||
"nonce": "0x00",
|
||||
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to": "",
|
||||
"value": [
|
||||
"0x01"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
144
evmbin/res/teststate.json
Normal file
144
evmbin/res/teststate.json
Normal file
@ -0,0 +1,144 @@
|
||||
{
|
||||
"add11": {
|
||||
"env": {
|
||||
"currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty": "0x0100",
|
||||
"currentGasLimit": "0x01c9c380",
|
||||
"currentNumber": "0x00",
|
||||
"currentTimestamp": "0x01",
|
||||
"previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"post": {
|
||||
"EIP150": [
|
||||
{
|
||||
"hash": "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f",
|
||||
"indexes": { "data": 0, "gas": 0, "value": 0 }
|
||||
},
|
||||
{
|
||||
"hash": "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764",
|
||||
"indexes": { "data": 0, "gas": 0, "value": 1 }
|
||||
}
|
||||
],
|
||||
"EIP158": [
|
||||
{
|
||||
"hash": "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f",
|
||||
"indexes": { "data": 0, "gas": 0, "value": 0 }
|
||||
},
|
||||
{
|
||||
"hash": "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764",
|
||||
"indexes": { "data": 0, "gas": 0, "value": 1 }
|
||||
}
|
||||
]
|
||||
},
|
||||
"pre": {
|
||||
"1000000000000000000000000000000000000000": {
|
||||
"balance": "0x0de0b6b3a7640000",
|
||||
"code": "0x6040600060406000600173100000000000000000000000000000000000000162055730f1600055",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
},
|
||||
"1000000000000000000000000000000000000001": {
|
||||
"balance": "0x0de0b6b3a7640000",
|
||||
"code": "0x604060006040600060027310000000000000000000000000000000000000026203d090f1600155",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
},
|
||||
"1000000000000000000000000000000000000002": {
|
||||
"balance": "0x00",
|
||||
"code": "0x600160025533600455346007553060e6553260e8553660ec553860ee553a60f055",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x0de0b6b3a7640000",
|
||||
"code": "0x",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction": {
|
||||
"data": [ "" ],
|
||||
"gasLimit": [ "285000", "100000", "6000" ],
|
||||
"gasPrice": "0x01",
|
||||
"nonce": "0x00",
|
||||
"secretKey": "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to": "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value": [ "10", "0" ]
|
||||
}
|
||||
},
|
||||
"add12": {
|
||||
"env": {
|
||||
"currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty": "0x0100",
|
||||
"currentGasLimit": "0x01c9c380",
|
||||
"currentNumber": "0x00",
|
||||
"currentTimestamp": "0x01",
|
||||
"previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"post": {
|
||||
"EIP150": [
|
||||
{
|
||||
"hash": "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f",
|
||||
"indexes": { "data": 0, "gas": 0, "value": 0 }
|
||||
},
|
||||
{
|
||||
"hash": "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764",
|
||||
"indexes": { "data": 0, "gas": 0, "value": 1 }
|
||||
}
|
||||
],
|
||||
"EIP158": [
|
||||
{
|
||||
"hash": "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f",
|
||||
"indexes": { "data": 0, "gas": 0, "value": 0 }
|
||||
},
|
||||
{
|
||||
"hash": "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764",
|
||||
"indexes": { "data": 0, "gas": 0, "value": 1 }
|
||||
}
|
||||
]
|
||||
},
|
||||
"pre": {
|
||||
"1000000000000000000000000000000000000000": {
|
||||
"balance": "0x0de0b6b3a7640000",
|
||||
"code": "0x6040600060406000600173100000000000000000000000000000000000000162055730f1600055",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
},
|
||||
"1000000000000000000000000000000000000001": {
|
||||
"balance": "0x0de0b6b3a7640000",
|
||||
"code": "0x604060006040600060027310000000000000000000000000000000000000026203d090f1600155",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
},
|
||||
"1000000000000000000000000000000000000002": {
|
||||
"balance": "0x00",
|
||||
"code": "0x600160025533600455346007553060e6553260e8553660ec553860ee553a60f055",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x0de0b6b3a7640000",
|
||||
"code": "0x",
|
||||
"nonce": "0x00",
|
||||
"storage": {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction": {
|
||||
"data": [ "" ],
|
||||
"gasLimit": [ "285000", "100000", "6000" ],
|
||||
"gasPrice": "0x01",
|
||||
"nonce": "0x00",
|
||||
"secretKey": "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to": "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value": [ "10", "0" ]
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! JSON VM output.
|
||||
//! Log EVM instruction output data traces from a JSON formatting informant.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! VM Output display utils.
|
||||
//! EVM output display utils.
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Simple VM output.
|
||||
//! Log EVM instruction output data traces from a simple formatting informant.
|
||||
|
||||
use trace;
|
||||
use bytes::ToPretty;
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Standardized JSON VM output.
|
||||
//! Log EVM instruction output data traces from a standardized JSON formatting informant.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
@ -117,14 +117,14 @@ impl Default for Informant<io::Stderr, io::Stdout> {
|
||||
}
|
||||
|
||||
impl Informant<io::Stdout, io::Stdout> {
|
||||
/// std json informant using out only.
|
||||
/// Standardized JSON formatting informant using stdout only.
|
||||
pub fn out_only() -> Self {
|
||||
Self::new(io::stdout(), io::stdout())
|
||||
}
|
||||
}
|
||||
|
||||
impl Informant<io::Stderr, io::Stderr> {
|
||||
/// std json informant using err only.
|
||||
/// Standardized JSON formatting informant using stderr only.
|
||||
pub fn err_only() -> Self {
|
||||
Self::new(io::stderr(), io::stderr())
|
||||
}
|
||||
|
@ -14,19 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! VM runner.
|
||||
//! EVM runner.
|
||||
|
||||
use std::time::{Instant, Duration};
|
||||
use ethereum_types::{H256, U256};
|
||||
use ethcore::client::{self, EvmTestClient, EvmTestError, TransactErr, TransactSuccess};
|
||||
use ethcore::{spec, TrieSpec};
|
||||
use trace;
|
||||
use ethereum_types::{H256, U256};
|
||||
use ethjson;
|
||||
use pod::PodState;
|
||||
use trace;
|
||||
use types::transaction;
|
||||
use vm::ActionParams;
|
||||
|
||||
/// VM execution informant
|
||||
/// EVM execution informant.
|
||||
pub trait Informant: trace::VMTracer {
|
||||
/// Sink to use with finish
|
||||
type Sink;
|
||||
@ -40,41 +40,41 @@ pub trait Informant: trace::VMTracer {
|
||||
fn finish(result: RunResult<Self::Output>, &mut Self::Sink);
|
||||
}
|
||||
|
||||
/// Execution finished correctly
|
||||
/// Execution finished correctly.
|
||||
#[derive(Debug)]
|
||||
pub struct Success<T> {
|
||||
/// State root
|
||||
/// State root.
|
||||
pub state_root: H256,
|
||||
/// Used gas
|
||||
/// Used gas.
|
||||
pub gas_used: U256,
|
||||
/// Output as bytes
|
||||
/// Output as bytes.
|
||||
pub output: Vec<u8>,
|
||||
/// Time Taken
|
||||
/// Time taken.
|
||||
pub time: Duration,
|
||||
/// Traces
|
||||
/// Traces.
|
||||
pub traces: Option<T>,
|
||||
/// Optional end state dump
|
||||
pub end_state: Option<PodState>,
|
||||
}
|
||||
|
||||
/// Execution failed
|
||||
/// Execution failed.
|
||||
#[derive(Debug)]
|
||||
pub struct Failure<T> {
|
||||
/// State root
|
||||
/// State root.
|
||||
pub state_root: H256,
|
||||
/// Used gas
|
||||
/// Used gas.
|
||||
pub gas_used: U256,
|
||||
/// Internal error
|
||||
/// Internal error.
|
||||
pub error: EvmTestError,
|
||||
/// Duration
|
||||
/// Duration.
|
||||
pub time: Duration,
|
||||
/// Traces
|
||||
/// Traces.
|
||||
pub traces: Option<T>,
|
||||
/// Optional end state dump
|
||||
pub end_state: Option<PodState>,
|
||||
}
|
||||
|
||||
/// EVM Execution result
|
||||
/// EVM execution result.
|
||||
pub type RunResult<T> = Result<Success<T>, Failure<T>>;
|
||||
|
||||
/// Execute given `ActionParams` and return the result.
|
||||
@ -102,35 +102,62 @@ pub fn run_action<T: Informant>(
|
||||
})
|
||||
}
|
||||
|
||||
/// Execute given Transaction and verify resulting state root.
|
||||
/// Input data to run transaction.
|
||||
#[derive(Debug)]
|
||||
pub struct TxInput<'a, T> {
|
||||
/// State test name associated with the transaction.
|
||||
pub state_test_name: &'a str,
|
||||
/// Transaction index from list of transactions within a state root hash corresponding to a chain.
|
||||
pub tx_index: usize,
|
||||
/// Fork specification (i.e. Constantinople, EIP150, EIP158, etc).
|
||||
pub fork_spec_name: &'a ethjson::spec::ForkSpec,
|
||||
/// State of all accounts in the system that is a binary tree mapping of each account address to account data
|
||||
/// that is expressed as Plain Old Data containing the account balance, account nonce, account code in bytes,
|
||||
/// and the account storage binary tree map.
|
||||
pub pre_state: &'a PodState,
|
||||
/// State root hash associated with the transaction.
|
||||
pub post_root: H256,
|
||||
/// Client environment information associated with the transaction's chain specification.
|
||||
pub env_info: &'a client::EnvInfo,
|
||||
/// Signed transaction accompanied by a signature that may be unverified and a successfully recovered
|
||||
/// sender address. The unverified transaction contains a recoverable ECDSA signature that has been encoded
|
||||
/// as RSV components and includes replay protection for the specified chain. Verification of the signed transaction
|
||||
/// with a valid secret of an account's keypair and a specific chain may be used to recover the sender's public key
|
||||
/// and their associated address by applying the Keccak-256 hash function.
|
||||
pub transaction: transaction::SignedTransaction,
|
||||
/// JSON formatting informant.
|
||||
pub informant: T,
|
||||
/// Trie specification (i.e. Generic trie, Secure trie, Secure with fat database).
|
||||
pub trie_spec: TrieSpec,
|
||||
}
|
||||
|
||||
/// Execute given transaction and verify resulting state root.
|
||||
/// Returns true if the transaction executes successfully.
|
||||
pub fn run_transaction<T: Informant>(
|
||||
name: &str,
|
||||
idx: usize,
|
||||
spec: ðjson::spec::ForkSpec,
|
||||
pre_state: &PodState,
|
||||
post_root: H256,
|
||||
env_info: &client::EnvInfo,
|
||||
transaction: transaction::SignedTransaction,
|
||||
mut informant: T,
|
||||
trie_spec: TrieSpec,
|
||||
) {
|
||||
let spec_name = format!("{:?}", spec).to_lowercase();
|
||||
let spec = match EvmTestClient::spec_from_json(spec) {
|
||||
tx_input: TxInput<T>
|
||||
) -> bool {
|
||||
let TxInput {
|
||||
state_test_name, tx_index, fork_spec_name, pre_state, post_root, env_info, transaction, mut informant, trie_spec, ..
|
||||
} = tx_input;
|
||||
let fork_spec_name_formatted = format!("{:?}", fork_spec_name).to_lowercase();
|
||||
let fork_spec = match EvmTestClient::fork_spec_from_json(&fork_spec_name) {
|
||||
Some(spec) => {
|
||||
informant.before_test(&format!("{}:{}:{}", name, spec_name, idx), "starting");
|
||||
informant.before_test(
|
||||
&format!("{}:{}:{}", &state_test_name, &fork_spec_name_formatted, tx_index), "starting");
|
||||
spec
|
||||
},
|
||||
None => {
|
||||
informant.before_test(&format!("{}:{}:{}", name, spec_name, idx), "skipping because of missing spec");
|
||||
return;
|
||||
informant.before_test(&format!("{}:{}:{}",
|
||||
&state_test_name, fork_spec_name_formatted, &tx_index), "skipping because of missing fork specification");
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
informant.set_gas(env_info.gas_limit);
|
||||
|
||||
let mut sink = informant.clone_sink();
|
||||
let result = run(&spec, trie_spec, transaction.gas, pre_state, |mut client| {
|
||||
let result = client.transact(env_info, transaction, trace::NoopTracer, informant);
|
||||
let result = run(&fork_spec, trie_spec, transaction.gas, &pre_state, |mut client| {
|
||||
let result = client.transact(&env_info, transaction, trace::NoopTracer, informant);
|
||||
match result {
|
||||
Ok(TransactSuccess { state_root, gas_left, output, vm_trace, end_state, .. }) => {
|
||||
if state_root != post_root {
|
||||
@ -151,10 +178,12 @@ pub fn run_transaction<T: Informant>(
|
||||
}
|
||||
});
|
||||
|
||||
T::finish(result, &mut sink)
|
||||
let ok = result.is_ok();
|
||||
T::finish(result, &mut sink);
|
||||
ok
|
||||
}
|
||||
|
||||
/// Execute VM with given `ActionParams`
|
||||
/// Execute EVM with given `ActionParams`.
|
||||
pub fn run<'a, F, X>(
|
||||
spec: &'a spec::Spec,
|
||||
trie_spec: TrieSpec,
|
||||
|
@ -34,24 +34,24 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate account_state;
|
||||
extern crate common_types as types;
|
||||
extern crate docopt;
|
||||
extern crate env_logger;
|
||||
extern crate ethcore;
|
||||
extern crate ethereum_types;
|
||||
extern crate ethjson;
|
||||
extern crate evm;
|
||||
extern crate panic_hook;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate pod;
|
||||
extern crate rustc_hex;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
extern crate docopt;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate ethereum_types;
|
||||
extern crate vm;
|
||||
extern crate evm;
|
||||
extern crate panic_hook;
|
||||
extern crate pod;
|
||||
extern crate env_logger;
|
||||
extern crate account_state;
|
||||
extern crate trace;
|
||||
extern crate vm;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
@ -73,24 +73,25 @@ use vm::{ActionParams, CallType};
|
||||
mod info;
|
||||
mod display;
|
||||
|
||||
use info::Informant;
|
||||
use info::{Informant, TxInput};
|
||||
|
||||
const USAGE: &'static str = r#"
|
||||
EVM implementation for Parity.
|
||||
Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||
|
||||
Usage:
|
||||
parity-evm state-test <file> [--json --std-json --std-dump-json --only NAME --chain CHAIN --std-out-only --std-err-only]
|
||||
parity-evm state-test <file> [--chain CHAIN --only NAME --json --std-json --std-dump-json --std-out-only --std-err-only]
|
||||
parity-evm stats [options]
|
||||
parity-evm stats-jsontests-vm <file>
|
||||
parity-evm [options]
|
||||
parity-evm [-h | --help]
|
||||
|
||||
Commands:
|
||||
state-test Run a state test from a json file.
|
||||
state-test Run a state test on a provided state test JSON file.
|
||||
stats Execute EVM runtime code and return the statistics.
|
||||
stats-jsontests-vm Execute standard json-tests format VMTests and return
|
||||
timing statistics in tsv format.
|
||||
stats-jsontests-vm Execute standard json-tests on a provided state test JSON
|
||||
file path, format VMTests, and return timing statistics
|
||||
in tsv format.
|
||||
|
||||
Transaction options:
|
||||
--code CODE Contract code as hex (without 0x).
|
||||
@ -101,18 +102,20 @@ Transaction options:
|
||||
--gas-price WEI Supplied gas price as hex (without 0x).
|
||||
|
||||
State test options:
|
||||
--chain CHAIN Run only from specific chain name (i.e. one of EIP150, EIP158,
|
||||
Frontier, Homestead, Byzantium, Constantinople,
|
||||
ConstantinopleFix, EIP158ToByzantiumAt5, FrontierToHomesteadAt5,
|
||||
HomesteadToDaoAt5, HomesteadToEIP150At5).
|
||||
--only NAME Runs only a single test matching the name.
|
||||
--chain CHAIN Run only tests from specific chain.
|
||||
|
||||
General options:
|
||||
--chain PATH Path to chain spec file.
|
||||
--json Display verbose results in JSON.
|
||||
--std-json Display results in standardized JSON format.
|
||||
--std-err-only With --std-json redirect to err output only.
|
||||
--std-out-only With --std-json redirect to out output only.
|
||||
--std-dump-json Display results in standardized JSON format
|
||||
with additional state dump.
|
||||
Display result state dump in standardized JSON format.
|
||||
--chain CHAIN Chain spec file path.
|
||||
--std-err-only With --std-json redirect to err output only.
|
||||
--std-out-only With --std-json redirect to out output only.
|
||||
-h, --help Display this message and exit.
|
||||
"#;
|
||||
|
||||
@ -141,12 +144,156 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_state_test(args: Args) {
|
||||
use ethjson::state::test::Test;
|
||||
|
||||
// Parse the specified state test JSON file provided to the command `state-test <file>`.
|
||||
let file = args.arg_file.expect("PATH to a state test JSON file is required");
|
||||
let mut file = match fs::File::open(&file) {
|
||||
Err(err) => die(format!("Unable to open path: {:?}: {}", file, err)),
|
||||
Ok(file) => file,
|
||||
};
|
||||
let state_test = match Test::load(&mut file) {
|
||||
Err(err) => die(format!("Unable to load the test file: {}", err)),
|
||||
Ok(test) => test,
|
||||
};
|
||||
// Parse the name CLI option `--only NAME`.
|
||||
let only_test = args.flag_only.map(|s| s.to_lowercase());
|
||||
// Parse the chain `--chain CHAIN`
|
||||
let only_chain = args.flag_chain.map(|s| s.to_lowercase());
|
||||
|
||||
// Iterate over 1st level (outer) key-value pair of the state test JSON file.
|
||||
// Skip to next iteration if CLI option `--only NAME` was parsed into `only_test` and does not match
|
||||
// the current key `state_test_name` (i.e. add11, create2callPrecompiles).
|
||||
for (state_test_name, test) in state_test {
|
||||
if let Some(false) = only_test.as_ref().map(|only_test| {
|
||||
&state_test_name.to_lowercase() == only_test
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Assign from 2nd level key-value pairs of the state test JSON file (i.e. env, post, pre, transaction).
|
||||
let multitransaction = test.transaction;
|
||||
let env_info = test.env.into();
|
||||
let pre = test.pre_state.into();
|
||||
|
||||
// Iterate over remaining "post" key of the 2nd level key-value pairs in the state test JSON file.
|
||||
// Skip to next iteration if CLI option `--chain CHAIN` was parsed into `only_chain` and does not match
|
||||
// the current key `fork_spec_name` (i.e. Constantinople, EIP150, EIP158).
|
||||
for (fork_spec_name, states) in test.post_states {
|
||||
if let Some(false) = only_chain.as_ref().map(|only_chain| {
|
||||
&format!("{:?}", fork_spec_name).to_lowercase() == only_chain
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Iterate over the 3rd level key-value pairs of the state test JSON file
|
||||
// (i.e. list of transactions and associated state roots hashes corresponding each chain).
|
||||
for (tx_index, state) in states.into_iter().enumerate() {
|
||||
let post_root = state.hash.into();
|
||||
let transaction = multitransaction.select(&state.indexes).into();
|
||||
|
||||
// Determine the type of trie with state root to create in the database.
|
||||
// The database is a key-value datastore implemented as a database-backend
|
||||
// modified Merkle tree.
|
||||
// Use a secure trie database specification when CLI option `--std-dump-json`
|
||||
// is specified, otherwise use secure trie with fat trie database.
|
||||
let trie_spec = if args.flag_std_dump_json {
|
||||
TrieSpec::Fat
|
||||
} else {
|
||||
TrieSpec::Secure
|
||||
};
|
||||
|
||||
// Execute the given transaction and verify resulting state root
|
||||
// for CLI option `--std-dump-json` or `--std-json`.
|
||||
if args.flag_std_dump_json || args.flag_std_json {
|
||||
if args.flag_std_err_only {
|
||||
let tx_input = TxInput {
|
||||
state_test_name: &state_test_name,
|
||||
tx_index,
|
||||
fork_spec_name: &fork_spec_name,
|
||||
pre_state: &pre,
|
||||
post_root,
|
||||
env_info: &env_info,
|
||||
transaction,
|
||||
informant: display::std_json::Informant::err_only(),
|
||||
trie_spec,
|
||||
};
|
||||
// Use Standard JSON informant with err only
|
||||
info::run_transaction(tx_input);
|
||||
} else if args.flag_std_out_only {
|
||||
let tx_input = TxInput {
|
||||
state_test_name: &state_test_name,
|
||||
tx_index,
|
||||
fork_spec_name: &fork_spec_name,
|
||||
pre_state: &pre,
|
||||
post_root,
|
||||
env_info: &env_info,
|
||||
transaction,
|
||||
informant: display::std_json::Informant::out_only(),
|
||||
trie_spec,
|
||||
};
|
||||
// Use Standard JSON informant with out only
|
||||
info::run_transaction(tx_input);
|
||||
} else {
|
||||
let tx_input = TxInput {
|
||||
state_test_name: &state_test_name,
|
||||
tx_index,
|
||||
fork_spec_name: &fork_spec_name,
|
||||
pre_state: &pre,
|
||||
post_root,
|
||||
env_info: &env_info,
|
||||
transaction,
|
||||
informant: display::std_json::Informant::default(),
|
||||
trie_spec,
|
||||
};
|
||||
// Use Standard JSON informant default
|
||||
info::run_transaction(tx_input);
|
||||
}
|
||||
} else {
|
||||
// Execute the given transaction and verify resulting state root
|
||||
// for CLI option `--json`.
|
||||
if args.flag_json {
|
||||
let tx_input = TxInput {
|
||||
state_test_name: &state_test_name,
|
||||
tx_index,
|
||||
fork_spec_name: &fork_spec_name,
|
||||
pre_state: &pre,
|
||||
post_root,
|
||||
env_info: &env_info,
|
||||
transaction,
|
||||
informant: display::json::Informant::default(),
|
||||
trie_spec,
|
||||
};
|
||||
// Use JSON informant
|
||||
info::run_transaction(tx_input);
|
||||
} else {
|
||||
let tx_input = TxInput {
|
||||
state_test_name: &state_test_name,
|
||||
tx_index,
|
||||
fork_spec_name: &fork_spec_name,
|
||||
pre_state: &pre,
|
||||
post_root,
|
||||
env_info: &env_info,
|
||||
transaction,
|
||||
informant: display::simple::Informant::default(),
|
||||
trie_spec,
|
||||
};
|
||||
// Use Simple informant
|
||||
info::run_transaction(tx_input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_stats_jsontests_vm(args: Args) {
|
||||
use json_tests::HookType;
|
||||
use std::collections::HashMap;
|
||||
use std::time::{Instant, Duration};
|
||||
|
||||
let file = args.arg_file.expect("FILE (or PATH) is required");
|
||||
let file = args.arg_file.expect("PATH to a state test JSON file is required");
|
||||
|
||||
let mut timings: HashMap<String, (Instant, Option<Duration>)> = HashMap::new();
|
||||
|
||||
@ -175,70 +322,15 @@ fn run_stats_jsontests_vm(args: Args) {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_state_test(args: Args) {
|
||||
use ethjson::state::test::Test;
|
||||
|
||||
let file = args.arg_file.expect("FILE is required");
|
||||
let mut file = match fs::File::open(&file) {
|
||||
Err(err) => die(format!("Unable to open: {:?}: {}", file, err)),
|
||||
Ok(file) => file,
|
||||
};
|
||||
let state_test = match Test::load(&mut file) {
|
||||
Err(err) => die(format!("Unable to load the test file: {}", err)),
|
||||
Ok(test) => test,
|
||||
};
|
||||
let only_test = args.flag_only.map(|s| s.to_lowercase());
|
||||
let only_chain = args.flag_chain.map(|s| s.to_lowercase());
|
||||
|
||||
for (name, test) in state_test {
|
||||
if let Some(false) = only_test.as_ref().map(|only_test| &name.to_lowercase() == only_test) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let multitransaction = test.transaction;
|
||||
let env_info = test.env.into();
|
||||
let pre = test.pre_state.into();
|
||||
|
||||
for (spec, states) in test.post_states {
|
||||
if let Some(false) = only_chain.as_ref().map(|only_chain| &format!("{:?}", spec).to_lowercase() == only_chain) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (idx, state) in states.into_iter().enumerate() {
|
||||
let post_root = state.hash.into();
|
||||
let transaction = multitransaction.select(&state.indexes).into();
|
||||
|
||||
let trie_spec = if args.flag_std_dump_json {
|
||||
TrieSpec::Fat
|
||||
} else {
|
||||
TrieSpec::Secure
|
||||
};
|
||||
if args.flag_json {
|
||||
info::run_transaction(&name, idx, &spec, &pre, post_root, &env_info, transaction, display::json::Informant::default(), trie_spec)
|
||||
} else if args.flag_std_dump_json || args.flag_std_json {
|
||||
if args.flag_std_err_only {
|
||||
info::run_transaction(&name, idx, &spec, &pre, post_root, &env_info, transaction, display::std_json::Informant::err_only(), trie_spec)
|
||||
} else if args.flag_std_out_only {
|
||||
info::run_transaction(&name, idx, &spec, &pre, post_root, &env_info, transaction, display::std_json::Informant::out_only(), trie_spec)
|
||||
} else {
|
||||
info::run_transaction(&name, idx, &spec, &pre, post_root, &env_info, transaction, display::std_json::Informant::default(), trie_spec)
|
||||
}
|
||||
} else {
|
||||
info::run_transaction(&name, idx, &spec, &pre, post_root, &env_info, transaction, display::simple::Informant::default(), trie_spec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CLI command `stats`
|
||||
fn run_call<T: Informant>(args: Args, informant: T) {
|
||||
let from = arg(args.from(), "--from");
|
||||
let to = arg(args.to(), "--to");
|
||||
let code = arg(args.code(), "--code");
|
||||
let spec = arg(args.spec(), "--chain");
|
||||
let to = arg(args.to(), "--to");
|
||||
let from = arg(args.from(), "--from");
|
||||
let data = arg(args.data(), "--input");
|
||||
let gas = arg(args.gas(), "--gas");
|
||||
let gas_price = arg(args.gas_price(), "--gas-price");
|
||||
let data = arg(args.data(), "--input");
|
||||
let spec = arg(args.spec(), "--chain");
|
||||
|
||||
if code.is_none() && to == Address::zero() {
|
||||
die("Either --code or --to is required.");
|
||||
@ -246,14 +338,14 @@ fn run_call<T: Informant>(args: Args, informant: T) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.call_type = if code.is_none() { CallType::Call } else { CallType::None };
|
||||
params.code = code.map(Arc::new);
|
||||
params.code_address = to;
|
||||
params.address = to;
|
||||
params.sender = from;
|
||||
params.origin = from;
|
||||
params.data = data;
|
||||
params.gas = gas;
|
||||
params.gas_price = gas_price;
|
||||
params.code = code.map(Arc::new);
|
||||
params.data = data;
|
||||
|
||||
let mut sink = informant.clone_sink();
|
||||
let result = if args.flag_std_dump_json {
|
||||
@ -270,13 +362,13 @@ struct Args {
|
||||
cmd_state_test: bool,
|
||||
cmd_stats_jsontests_vm: bool,
|
||||
arg_file: Option<PathBuf>,
|
||||
flag_only: Option<String>,
|
||||
flag_from: Option<String>,
|
||||
flag_to: Option<String>,
|
||||
flag_code: Option<String>,
|
||||
flag_to: Option<String>,
|
||||
flag_from: Option<String>,
|
||||
flag_input: Option<String>,
|
||||
flag_gas: Option<String>,
|
||||
flag_gas_price: Option<String>,
|
||||
flag_input: Option<String>,
|
||||
flag_only: Option<String>,
|
||||
flag_chain: Option<String>,
|
||||
flag_json: bool,
|
||||
flag_std_json: bool,
|
||||
@ -286,7 +378,44 @@ struct Args {
|
||||
}
|
||||
|
||||
impl Args {
|
||||
/// Set the gas limit. Defaults to max value to allow code to run for whatever time is required.
|
||||
// CLI option `--code CODE`
|
||||
/// Set the contract code in hex. Only send to either a contract code or a recipient address.
|
||||
pub fn code(&self) -> Result<Option<Bytes>, String> {
|
||||
match self.flag_code {
|
||||
Some(ref code) => code.from_hex().map(Some).map_err(to_string),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
// CLI option `--to ADDRESS`
|
||||
/// Set the recipient address in hex. Only send to either a contract code or a recipient address.
|
||||
pub fn to(&self) -> Result<Address, String> {
|
||||
match self.flag_to {
|
||||
Some(ref to) => to.parse().map_err(to_string),
|
||||
None => Ok(Address::zero()),
|
||||
}
|
||||
}
|
||||
|
||||
// CLI option `--from ADDRESS`
|
||||
/// Set the sender address.
|
||||
pub fn from(&self) -> Result<Address, String> {
|
||||
match self.flag_from {
|
||||
Some(ref from) => from.parse().map_err(to_string),
|
||||
None => Ok(Address::zero()),
|
||||
}
|
||||
}
|
||||
|
||||
// CLI option `--input DATA`
|
||||
/// Set the input data in hex.
|
||||
pub fn data(&self) -> Result<Option<Bytes>, String> {
|
||||
match self.flag_input {
|
||||
Some(ref input) => input.from_hex().map_err(to_string).map(Some),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
// CLI option `--gas GAS`
|
||||
/// Set the gas limit in units of gas. Defaults to max value to allow code to run for whatever time is required.
|
||||
pub fn gas(&self) -> Result<U256, String> {
|
||||
match self.flag_gas {
|
||||
Some(ref gas) => gas.parse().map_err(to_string),
|
||||
@ -294,6 +423,7 @@ impl Args {
|
||||
}
|
||||
}
|
||||
|
||||
// CLI option `--gas-price WEI`
|
||||
/// Set the gas price. Defaults to zero to allow the code to run even if an account with no balance
|
||||
/// is used, otherwise such accounts would not have sufficient funds to pay the transaction fee.
|
||||
/// Defaulting to zero also makes testing easier since it is not necessary to specify a special configuration file.
|
||||
@ -304,34 +434,8 @@ impl Args {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from(&self) -> Result<Address, String> {
|
||||
match self.flag_from {
|
||||
Some(ref from) => from.parse().map_err(to_string),
|
||||
None => Ok(Address::zero()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to(&self) -> Result<Address, String> {
|
||||
match self.flag_to {
|
||||
Some(ref to) => to.parse().map_err(to_string),
|
||||
None => Ok(Address::zero()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn code(&self) -> Result<Option<Bytes>, String> {
|
||||
match self.flag_code {
|
||||
Some(ref code) => code.from_hex().map(Some).map_err(to_string),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> Result<Option<Bytes>, String> {
|
||||
match self.flag_input {
|
||||
Some(ref input) => input.from_hex().map_err(to_string).map(Some),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
// CLI option `--chain PATH`
|
||||
/// Set the path of the chain specification JSON file.
|
||||
pub fn spec(&self) -> Result<spec::Spec, String> {
|
||||
Ok(match self.flag_chain {
|
||||
Some(ref filename) => {
|
||||
@ -360,8 +464,29 @@ fn die<T: fmt::Display>(msg: T) -> ! {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
use docopt::Docopt;
|
||||
use super::{Args, USAGE, Address};
|
||||
use ethjson::state::test::{State};
|
||||
use ethcore::{TrieSpec};
|
||||
use ethereum_types::{H256};
|
||||
use types::transaction;
|
||||
|
||||
use info;
|
||||
use info::{TxInput};
|
||||
use display;
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
pub struct SampleStateTests {
|
||||
pub add11: State,
|
||||
pub add12: State,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ConstantinopleStateTests {
|
||||
pub create2call_precompiles: State,
|
||||
}
|
||||
|
||||
fn run<T: AsRef<str>>(args: &[T]) -> Args {
|
||||
Docopt::new(USAGE).and_then(|d| d.argv(args.into_iter()).deserialize()).unwrap()
|
||||
@ -371,30 +496,32 @@ mod tests {
|
||||
fn should_parse_all_the_options() {
|
||||
let args = run(&[
|
||||
"parity-evm",
|
||||
"--code", "05",
|
||||
"--to", "0000000000000000000000000000000000000004",
|
||||
"--from", "0000000000000000000000000000000000000003",
|
||||
"--input", "06",
|
||||
"--gas", "1",
|
||||
"--gas-price", "2",
|
||||
"--chain", "./testfile.json",
|
||||
"--json",
|
||||
"--std-json",
|
||||
"--std-dump-json",
|
||||
"--gas", "1",
|
||||
"--gas-price", "2",
|
||||
"--from", "0000000000000000000000000000000000000003",
|
||||
"--to", "0000000000000000000000000000000000000004",
|
||||
"--code", "05",
|
||||
"--input", "06",
|
||||
"--chain", "./testfile", "--std-err-only", "--std-out-only"
|
||||
"--std-err-only",
|
||||
"--std-out-only",
|
||||
]);
|
||||
|
||||
assert_eq!(args.code(), Ok(Some(vec![05])));
|
||||
assert_eq!(args.to(), Ok(Address::from_low_u64_be(4)));
|
||||
assert_eq!(args.from(), Ok(Address::from_low_u64_be(3)));
|
||||
assert_eq!(args.data(), Ok(Some(vec![06]))); // input data
|
||||
assert_eq!(args.gas(), Ok(1.into()));
|
||||
assert_eq!(args.gas_price(), Ok(2.into()));
|
||||
assert_eq!(args.flag_chain, Some("./testfile.json".to_owned()));
|
||||
assert_eq!(args.flag_json, true);
|
||||
assert_eq!(args.flag_std_json, true);
|
||||
assert_eq!(args.flag_std_dump_json, true);
|
||||
assert_eq!(args.flag_std_err_only, true);
|
||||
assert_eq!(args.flag_std_out_only, true);
|
||||
assert_eq!(args.gas(), Ok(1.into()));
|
||||
assert_eq!(args.gas_price(), Ok(2.into()));
|
||||
assert_eq!(args.from(), Ok(Address::from_low_u64_be(3)));
|
||||
assert_eq!(args.to(), Ok(Address::from_low_u64_be(4)));
|
||||
assert_eq!(args.code(), Ok(Some(vec![05])));
|
||||
assert_eq!(args.data(), Ok(Some(vec![06])));
|
||||
assert_eq!(args.flag_chain, Some("./testfile".to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -407,15 +534,116 @@ mod tests {
|
||||
"--only=add11",
|
||||
"--json",
|
||||
"--std-json",
|
||||
"--std-dump-json"
|
||||
"--std-dump-json",
|
||||
"--std-out-only",
|
||||
"--std-err-only",
|
||||
]);
|
||||
|
||||
assert_eq!(args.cmd_state_test, true);
|
||||
assert!(args.arg_file.is_some());
|
||||
assert_eq!(args.flag_chain, Some("homestead".to_owned()));
|
||||
assert_eq!(args.flag_only, Some("add11".to_owned()));
|
||||
assert_eq!(args.flag_json, true);
|
||||
assert_eq!(args.flag_std_json, true);
|
||||
assert_eq!(args.flag_std_dump_json, true);
|
||||
assert_eq!(args.flag_chain, Some("homestead".to_owned()));
|
||||
assert_eq!(args.flag_only, Some("add11".to_owned()));
|
||||
assert_eq!(args.flag_std_out_only, true);
|
||||
assert_eq!(args.flag_std_err_only, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_verify_state_root_using_sample_state_test_json_file() {
|
||||
let state_tests = include_str!("../res/teststate.json");
|
||||
// Parse the specified state test JSON file to simulate the CLI command `state-test <file>`.
|
||||
let deserialized_state_tests: SampleStateTests = serde_json::from_str(state_tests)
|
||||
.expect("Serialization cannot fail; qed");
|
||||
|
||||
// Simulate the name CLI option `--only NAME`
|
||||
let state_test_name = "add11";
|
||||
// Simulate the chain `--chain CHAIN`
|
||||
let pre = deserialized_state_tests.add11.pre_state.into();
|
||||
let env_info = deserialized_state_tests.add11.env.into();
|
||||
let multitransaction = deserialized_state_tests.add11.transaction;
|
||||
|
||||
let post_roots = [
|
||||
// EIP-150
|
||||
[
|
||||
H256::from_str("f4455d9332a9e171fc41b48350457147c21fc0a92364d9925913f7421e15aa95").unwrap(),
|
||||
H256::from_str("a0bc824c4186c4c1543851894fbf707b5b1cf771d15e74f3517daf0a3415fe5b").unwrap(),
|
||||
],
|
||||
// EIP-158
|
||||
[
|
||||
H256::from_str("f4455d9332a9e171fc41b48350457147c21fc0a92364d9925913f7421e15aa95").unwrap(),
|
||||
H256::from_str("27682055e1899031c92d253ee1d22c40f70a6943724168c0b694a1a503664e0a").unwrap(),
|
||||
],
|
||||
];
|
||||
for (fork_index, (fork_spec_name, tx_states)) in deserialized_state_tests.add11.post_states.iter().enumerate() {
|
||||
for (tx_index, tx_state) in tx_states.into_iter().enumerate() {
|
||||
let post_root = post_roots[fork_index][tx_index];
|
||||
let informant = display::json::Informant::default();
|
||||
let trie_spec = TrieSpec::Secure; // TrieSpec::Fat for --std_dump_json
|
||||
let transaction: transaction::SignedTransaction = multitransaction.select(&tx_state.indexes).into();
|
||||
let tx_input = TxInput {
|
||||
state_test_name: &state_test_name,
|
||||
tx_index,
|
||||
fork_spec_name: &fork_spec_name,
|
||||
pre_state: &pre,
|
||||
post_root,
|
||||
env_info: &env_info,
|
||||
transaction,
|
||||
informant,
|
||||
trie_spec,
|
||||
};
|
||||
assert!(info::run_transaction(tx_input));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_verify_state_root_using_constantinople_state_test_json_file() {
|
||||
let state_tests = include_str!("../res/create2callPrecompiles.json");
|
||||
// Parse the specified state test JSON file to simulate the CLI command `state-test <file>`.
|
||||
let deserialized_state_tests: ConstantinopleStateTests = serde_json::from_str(state_tests)
|
||||
.expect("Serialization cannot fail; qed");
|
||||
|
||||
// Simulate the name CLI option `--only NAME`
|
||||
let state_test_name = "create2callPrecompiles";
|
||||
let post_roots = [
|
||||
// Constantinople
|
||||
[
|
||||
H256::from_str("3dfdcd1d19badbbba8b0c953504e8b4685270ee5b86e155350b6ef1042c9ce43").unwrap(),
|
||||
H256::from_str("88803085d3420aec76078e215f67fc5f7b6f297fbe19d85c2236ad685d0fc7fc").unwrap(),
|
||||
H256::from_str("57181dda5c067cb31f084c4118791b40d5028c39071e83e60e7f7403d683527e").unwrap(),
|
||||
H256::from_str("f04c1039893eb6959354c3c16e9fe025d4b9dc3981362f79c56cc427dca0d544").unwrap(),
|
||||
H256::from_str("5d5db3d6c4377b34b74ecf8638f684acb220cc7ce286ae5f000ffa74faf38bae").unwrap(),
|
||||
H256::from_str("f8343b2e05ae120bf25947de840cedf1ca2c1bcda1cdb89d218427d8a84d4798").unwrap(),
|
||||
H256::from_str("305a8a8a7d9da97d14ed2259503d9373d803ea4b7fbf8c360f50b1b30a3d04ed").unwrap(),
|
||||
H256::from_str("de1d3953b508913c6e3e9bd412cd50daf60bb177517e5d1e8ccb0dab193aed03").unwrap(),
|
||||
],
|
||||
];
|
||||
let pre = deserialized_state_tests.create2call_precompiles.pre_state.into();
|
||||
let env_info = deserialized_state_tests.create2call_precompiles.env.into();
|
||||
let multitransaction = deserialized_state_tests.create2call_precompiles.transaction;
|
||||
for (fork_index, (fork_spec_name, tx_states)) in
|
||||
deserialized_state_tests.create2call_precompiles.post_states.iter().enumerate() {
|
||||
for (tx_index, tx_state) in tx_states.into_iter().enumerate() {
|
||||
let informant = display::json::Informant::default();
|
||||
// Hash of latest transaction index in the chain
|
||||
let post_root = post_roots[fork_index][tx_index];
|
||||
let trie_spec = TrieSpec::Secure; // TrieSpec::Fat for --std_dump_json
|
||||
let transaction: transaction::SignedTransaction = multitransaction.select(&tx_state.indexes).into();
|
||||
let tx_input = TxInput {
|
||||
state_test_name: &state_test_name,
|
||||
tx_index,
|
||||
fork_spec_name: &fork_spec_name,
|
||||
pre_state: &pre,
|
||||
post_root,
|
||||
env_info: &env_info,
|
||||
transaction,
|
||||
informant,
|
||||
trie_spec,
|
||||
};
|
||||
assert!(info::run_transaction(tx_input));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user