2020-09-22 14:53:52 +02:00
|
|
|
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
|
|
// This file is part of OpenEthereum.
|
2016-03-25 13:08:57 +01:00
|
|
|
|
2020-09-22 14:53:52 +02:00
|
|
|
// OpenEthereum is free software: you can redistribute it and/or modify
|
2016-03-25 13:08:57 +01:00
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
2020-09-22 14:53:52 +02:00
|
|
|
// OpenEthereum is distributed in the hope that it will be useful,
|
2016-03-25 13:08:57 +01:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2020-09-22 14:53:52 +02:00
|
|
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
2016-03-25 13:08:57 +01:00
|
|
|
|
2017-04-12 13:33:49 +02:00
|
|
|
//! General test deserialization.
|
2016-03-25 13:08:57 +01:00
|
|
|
|
2017-04-12 13:33:49 +02:00
|
|
|
use bytes::Bytes;
|
2021-03-03 15:57:25 +01:00
|
|
|
use ethkey::Secret;
|
2017-04-12 13:33:49 +02:00
|
|
|
use hash::{Address, H256};
|
|
|
|
use maybe::MaybeEmpty;
|
|
|
|
use serde_json::{self, Error};
|
2018-09-10 22:38:30 +02:00
|
|
|
use spec::ForkSpec;
|
2021-03-03 15:57:25 +01:00
|
|
|
use state::{AccountState, Env};
|
2017-04-12 13:33:49 +02:00
|
|
|
use std::{collections::BTreeMap, io::Read};
|
2021-03-03 15:57:25 +01:00
|
|
|
use types::transaction::{AccessListTx, Action, SignedTransaction, Transaction, TypedTransaction};
|
2017-04-12 13:33:49 +02:00
|
|
|
use uint::Uint;
|
2016-03-25 13:08:57 +01:00
|
|
|
|
2021-03-03 15:57:25 +01:00
|
|
|
use crate::blockchain::transaction::AccessList;
|
|
|
|
|
2016-03-25 13:08:57 +01:00
|
|
|
/// State test deserializer.
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
|
|
|
pub struct Test(BTreeMap<String, State>);
|
|
|
|
|
|
|
|
impl IntoIterator for Test {
|
|
|
|
type Item = <BTreeMap<String, State> as IntoIterator>::Item;
|
|
|
|
type IntoIter = <BTreeMap<String, State> as IntoIterator>::IntoIter;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
|
|
self.0.into_iter()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Test {
|
|
|
|
/// Loads test from json.
|
|
|
|
pub fn load<R>(reader: R) -> Result<Self, Error>
|
|
|
|
where
|
|
|
|
R: Read,
|
|
|
|
{
|
|
|
|
serde_json::from_reader(reader)
|
|
|
|
}
|
|
|
|
}
|
2017-04-12 13:33:49 +02:00
|
|
|
|
|
|
|
/// State test deserialization.
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
|
|
|
pub struct State {
|
|
|
|
/// Environment.
|
|
|
|
pub env: Env,
|
|
|
|
/// Pre state.
|
2018-10-29 16:49:04 +01:00
|
|
|
#[serde(rename = "pre")]
|
2017-04-12 13:33:49 +02:00
|
|
|
pub pre_state: AccountState,
|
|
|
|
/// Post state.
|
2018-10-29 16:49:04 +01:00
|
|
|
#[serde(rename = "post")]
|
2017-04-12 13:33:49 +02:00
|
|
|
pub post_states: BTreeMap<ForkSpec, Vec<PostStateResult>>,
|
|
|
|
/// Transaction.
|
|
|
|
pub transaction: MultiTransaction,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// State test transaction deserialization.
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
2018-10-29 16:49:04 +01:00
|
|
|
#[serde(rename_all = "camelCase")]
|
2017-04-12 13:33:49 +02:00
|
|
|
pub struct MultiTransaction {
|
|
|
|
/// Transaction data set.
|
|
|
|
pub data: Vec<Bytes>,
|
2021-03-03 15:57:25 +01:00
|
|
|
/// Optional access list
|
|
|
|
pub access_lists: Option<Vec<Option<AccessList>>>,
|
2017-04-12 13:33:49 +02:00
|
|
|
/// Gas limit set.
|
|
|
|
pub gas_limit: Vec<Uint>,
|
|
|
|
/// Gas price.
|
|
|
|
pub gas_price: Uint,
|
|
|
|
/// Nonce.
|
|
|
|
pub nonce: Uint,
|
|
|
|
/// Secret key.
|
2018-10-29 16:49:04 +01:00
|
|
|
#[serde(rename = "secretKey")]
|
2017-04-19 14:30:00 +02:00
|
|
|
pub secret: Option<H256>,
|
2017-04-12 13:33:49 +02:00
|
|
|
/// To.
|
|
|
|
pub to: MaybeEmpty<Address>,
|
|
|
|
/// Value set.
|
|
|
|
pub value: Vec<Uint>,
|
|
|
|
}
|
|
|
|
|
2021-03-03 15:57:25 +01:00
|
|
|
fn sign_with_secret(tx: TypedTransaction, secret: Option<Secret>) -> SignedTransaction {
|
|
|
|
match secret {
|
|
|
|
Some(s) => tx.sign(&s, None),
|
|
|
|
None => tx.null_sign(1),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-12 13:33:49 +02:00
|
|
|
impl MultiTransaction {
|
|
|
|
/// Build transaction with given indexes.
|
2021-03-03 15:57:25 +01:00
|
|
|
pub fn select(&self, indexes: &PostStateIndexes) -> SignedTransaction {
|
|
|
|
let secret = self.secret.clone().map(|s| Secret::from(s.0));
|
|
|
|
let to: Option<Address> = self.to.clone().into();
|
|
|
|
let transaction = Transaction {
|
|
|
|
nonce: self.nonce.clone().into(),
|
|
|
|
gas_price: self.gas_price.clone().into(),
|
|
|
|
gas: self.gas_limit[indexes.gas as usize].clone().into(),
|
|
|
|
action: match to {
|
|
|
|
Some(to) => Action::Call(to.into()),
|
|
|
|
None => Action::Create,
|
|
|
|
},
|
|
|
|
value: self.value[indexes.value as usize].clone().into(),
|
|
|
|
data: self.data[indexes.data as usize].clone().into(),
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(access_lists) = self.access_lists.as_ref() {
|
|
|
|
if access_lists.len() > indexes.data as usize {
|
|
|
|
if let Some(access_list) = access_lists[indexes.data as usize].clone() {
|
|
|
|
//access list type of transaction
|
|
|
|
|
|
|
|
let access_list = access_list
|
|
|
|
.into_iter()
|
|
|
|
.map(|elem| {
|
|
|
|
(
|
|
|
|
elem.address.into(),
|
|
|
|
elem.storage_keys.into_iter().map(Into::into).collect(),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let tx = TypedTransaction::AccessList(AccessListTx {
|
|
|
|
transaction,
|
|
|
|
access_list,
|
|
|
|
});
|
|
|
|
|
|
|
|
return sign_with_secret(tx, secret);
|
|
|
|
}
|
|
|
|
}
|
2017-04-12 13:33:49 +02:00
|
|
|
}
|
2021-03-03 15:57:25 +01:00
|
|
|
|
|
|
|
let tx = TypedTransaction::Legacy(transaction);
|
|
|
|
sign_with_secret(tx, secret)
|
2017-04-12 13:33:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// State test indexes deserialization.
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
|
|
|
pub struct PostStateIndexes {
|
|
|
|
/// Index into transaction data set.
|
|
|
|
pub data: u64,
|
|
|
|
/// Index into transaction gas limit set.
|
|
|
|
pub gas: u64,
|
|
|
|
/// Index into transaction value set.
|
|
|
|
pub value: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// State test indexed state result deserialization.
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
|
|
|
pub struct PostStateResult {
|
|
|
|
/// Post state hash
|
|
|
|
pub hash: H256,
|
|
|
|
/// Indexes
|
|
|
|
pub indexes: PostStateIndexes,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::{MultiTransaction, State};
|
|
|
|
use serde_json;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multi_transaction_deserialization() {
|
|
|
|
let s = r#"{
|
|
|
|
"data" : [ "" ],
|
|
|
|
"gasLimit" : [ "0x2dc6c0", "0x222222" ],
|
|
|
|
"gasPrice" : "0x01",
|
|
|
|
"nonce" : "0x00",
|
|
|
|
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
|
|
|
"to" : "1000000000000000000000000000000000000000",
|
|
|
|
"value" : [ "0x00", "0x01", "0x02" ]
|
|
|
|
}"#;
|
|
|
|
let _deserialized: MultiTransaction = serde_json::from_str(s).unwrap();
|
|
|
|
}
|
|
|
|
|
2021-03-03 15:57:25 +01:00
|
|
|
#[test]
|
|
|
|
fn multi_transaction_deserialization_with_access_list() {
|
|
|
|
let s = r#"{
|
|
|
|
"data" : [ "" ],
|
|
|
|
"accessLists" : [
|
|
|
|
null,
|
|
|
|
[
|
|
|
|
],
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"address" : "0x0000000000000000000000000000000000000102",
|
|
|
|
"storageKeys" : [
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"address" : "0x0000000000000000000000000000000000000101",
|
|
|
|
"storageKeys" : [
|
|
|
|
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
|
|
"0x0000000000000000000000000000000000000000000000000000000000000010"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
],
|
|
|
|
"gasLimit" : [ "0x2dc6c0", "0x222222" ],
|
|
|
|
"gasPrice" : "0x01",
|
|
|
|
"nonce" : "0x00",
|
|
|
|
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
|
|
|
"to" : "1000000000000000000000000000000000000000",
|
|
|
|
"value" : [ "0x00", "0x01", "0x02" ]
|
|
|
|
}"#;
|
|
|
|
let _deserialized: MultiTransaction = serde_json::from_str(s).unwrap();
|
|
|
|
}
|
|
|
|
|
2017-04-12 13:33:49 +02:00
|
|
|
#[test]
|
|
|
|
fn state_deserialization() {
|
|
|
|
let s = r#"{
|
|
|
|
"env" : {
|
|
|
|
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
|
|
|
"currentDifficulty" : "0x0100",
|
|
|
|
"currentGasLimit" : "0x01c9c380",
|
|
|
|
"currentNumber" : "0x00",
|
|
|
|
"currentTimestamp" : "0x01",
|
|
|
|
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
|
|
|
},
|
|
|
|
"post" : {
|
|
|
|
"EIP150" : [
|
|
|
|
{
|
|
|
|
"hash" : "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f",
|
2017-08-28 14:25:16 +02:00
|
|
|
"indexes" : { "data" : 0, "gas" : 0, "value" : 0 }
|
2017-04-12 13:33:49 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"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" ]
|
|
|
|
}
|
|
|
|
}"#;
|
|
|
|
let _deserialized: State = serde_json::from_str(s).unwrap();
|
|
|
|
// TODO: validate all fields
|
|
|
|
}
|
|
|
|
}
|