Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
deuduplicated a few functions (#992)
Browse files Browse the repository at this point in the history
* deuduplicated a few functions

* deduplicated parse_calldata and parse_code

* fixed clippy errors

* fix log copyrwc when is_persistent false (#1015)

* fix to check account empty for existence in `BALANCE` bus mapping (#1007)

* Fix to check account empty for existence in `BALANCE` bus-mapping.

* Add a test case for empty account.

Co-authored-by: Chih Cheng Liang <chihchengliang@gmail.com>
Co-authored-by: DreamWuGit <wwuwwei@126.com>
Co-authored-by: Steven <asongala@163.com>
  • Loading branch information
4 people authored Dec 29, 2022
1 parent b51eded commit 325a58f
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 291 deletions.
215 changes: 29 additions & 186 deletions testool/src/statetest/json.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(dead_code, unused_imports)]

use super::parse;
use super::spec::{AccountMatch, Env, StateTest};
use crate::abi;
use crate::compiler::Compiler;
Expand Down Expand Up @@ -113,31 +114,31 @@ impl<'a> JsonStateTestBuilder<'a> {
let env = Self::parse_env(&test.env)?;
let pre = self.parse_accounts_pre(&test.pre)?;

let to = Self::parse_to_address(&test.transaction.to)?;
let secret_key = Self::parse_bytes(&test.transaction.secret_key)?;
let to = parse::parse_to_address(&test.transaction.to)?;
let secret_key = parse::parse_bytes(&test.transaction.secret_key)?;
let from = secret_key_to_address(&SigningKey::from_bytes(&secret_key.to_vec())?);
let nonce = Self::parse_u256(&test.transaction.nonce)?;
let gas_price = Self::parse_u256(&test.transaction.gas_price)?;
let nonce = parse::parse_u256(&test.transaction.nonce)?;
let gas_price = parse::parse_u256(&test.transaction.gas_price)?;

let data_s: Vec<_> = test
.transaction
.data
.iter()
.map(|item| self.parse_calldata(item))
.map(|item| parse::parse_calldata(self.compiler, item))
.collect::<Result<_>>()?;

let gas_limit_s: Vec<_> = test
.transaction
.gas_limit
.iter()
.map(|item| Self::parse_u64(item))
.map(|item| parse::parse_u64(item))
.collect::<Result<_>>()?;

let value_s: Vec<_> = test
.transaction
.value
.iter()
.map(|item| Self::parse_u256(item))
.map(|item| parse::parse_u256(item))
.collect::<Result<_>>()?;

let mut expects = Vec::new();
Expand Down Expand Up @@ -184,7 +185,7 @@ impl<'a> JsonStateTestBuilder<'a> {
gas_price,
gas_limit: *gas_limit,
value: *value,
data: eth_types::Bytes(data.0.clone()),
data: data.0.clone(),
exception: false, // TODO: check
});
}
Expand All @@ -199,12 +200,12 @@ impl<'a> JsonStateTestBuilder<'a> {
/// parse env section
fn parse_env(env: &TestEnv) -> Result<Env> {
Ok(Env {
current_coinbase: Self::parse_address(&env.current_coinbase)?,
current_difficulty: Self::parse_u256(&env.current_difficulty)?,
current_gas_limit: Self::parse_u64(&env.current_gas_limit)?,
current_number: Self::parse_u64(&env.current_number)?,
current_timestamp: Self::parse_u64(&env.current_timestamp)?,
previous_hash: Self::parse_hash(&env.previous_hash)?,
current_coinbase: parse::parse_address(&env.current_coinbase)?,
current_difficulty: parse::parse_u256(&env.current_difficulty)?,
current_gas_limit: parse::parse_u64(&env.current_gas_limit)?,
current_number: parse::parse_u64(&env.current_number)?,
current_timestamp: parse::parse_u64(&env.current_timestamp)?,
previous_hash: parse::parse_hash(&env.previous_hash)?,
})
}

Expand All @@ -215,16 +216,16 @@ impl<'a> JsonStateTestBuilder<'a> {
) -> Result<HashMap<Address, Account>> {
let mut accounts = HashMap::new();
for (address, acc) in accounts_pre {
let address = Self::parse_address(address)?;
let address = parse::parse_address(address)?;
let mut storage = HashMap::new();
for (k, v) in &acc.storage {
storage.insert(Self::parse_u256(k)?, Self::parse_u256(v)?);
storage.insert(parse::parse_u256(k)?, parse::parse_u256(v)?);
}
let account = Account {
address,
balance: Self::parse_u256(&acc.balance)?,
nonce: Self::parse_u256(&acc.nonce)?,
code: self.parse_code(&acc.code)?,
balance: parse::parse_u256(&acc.balance)?,
nonce: parse::parse_u256(&acc.nonce)?,
code: parse::parse_code(self.compiler, &acc.code)?,
storage,
};
accounts.insert(address, account);
Expand All @@ -239,25 +240,29 @@ impl<'a> JsonStateTestBuilder<'a> {
) -> Result<HashMap<Address, AccountMatch>> {
let mut accounts = HashMap::new();
for (address, acc) in accounts_post {
let address = Self::parse_address(address)?;
let address = parse::parse_address(address)?;
let mut storage: HashMap<U256, U256> = HashMap::new();
if let Some(acc_storage) = &acc.storage {
for (k, v) in acc_storage {
storage.insert(Self::parse_u256(k)?, Self::parse_u256(v)?);
storage.insert(parse::parse_u256(k)?, parse::parse_u256(v)?);
}
}
let account = AccountMatch {
address,
balance: acc
.balance
.as_ref()
.map(|v| Self::parse_u256(v))
.map(|v| parse::parse_u256(v))
.transpose()?,
code: acc
.code
.as_ref()
.map(|v| parse::parse_code(self.compiler, v))
.transpose()?,
code: acc.code.as_ref().map(|v| self.parse_code(v)).transpose()?,
nonce: acc
.nonce
.as_ref()
.map(|v| Self::parse_u256(v))
.map(|v| parse::parse_u256(v))
.transpose()?,
storage,
};
Expand All @@ -266,168 +271,6 @@ impl<'a> JsonStateTestBuilder<'a> {
Ok(accounts)
}

/// converts list of tagged values string into a map
/// if there's no tags, an entry with an empty tag and the full string is
/// returned
fn decompose_tags(expr: &str) -> HashMap<String, String> {
let mut tags = HashMap::new();
let mut it = expr.trim();
if it.is_empty() {
tags.insert("".to_string(), "".to_string());
} else {
while !it.is_empty() {
if it.starts_with(':') {
let tag = &it[..it.find(&[' ', '\n']).expect("unable to find end tag")];
it = &it[tag.len() + 1..];
let value_len = if tag == ":yul" || tag == ":solidity" || tag == ":asm" {
it.len()
} else {
it.find(':').unwrap_or(it.len())
};
tags.insert(tag.to_string(), it[..value_len].trim().to_string());
it = &it[value_len..];
} else {
tags.insert("".to_string(), it.trim().to_string());
it = &it[it.len()..]
}
}
}
tags
}
/// returns the element as an address
fn parse_address(as_str: &str) -> Result<Address> {
if let Some(hex) = as_str.strip_prefix("0x") {
Ok(Address::from_slice(
&hex::decode(hex).context("parse_address")?,
))
} else {
Ok(Address::from_slice(
&hex::decode(as_str).context("parse_address")?,
))
}
}

/// returns the element as a to address
fn parse_to_address(as_str: &str) -> Result<Option<Address>> {
if as_str.trim().is_empty() {
return Ok(None);
}
Self::parse_address(as_str).map(|x| Ok(Some(x)))?
}

/// returns the element as an array of bytes
fn parse_bytes(as_str: &str) -> Result<Bytes> {
if let Some(hex) = as_str.strip_prefix("0x") {
Ok(Bytes::from(hex::decode(hex).context("parse_bytes")?))
} else {
Ok(Bytes::from(hex::decode(as_str).context("parse_bytes")?))
}
}

/// parse entry as code, can be 0x, :raw or { LLL }
fn parse_code(&mut self, as_str: &str) -> Result<Bytes> {
let tags = Self::decompose_tags(as_str);

let mut code = if let Some(notag) = tags.get("") {
if notag.starts_with("0x") {
Bytes::from(hex::decode(&tags[""][2..]).context("parse_code")?)
} else if notag.starts_with('{') {
self.compiler.lll(notag)?
} else if notag.trim().is_empty() {
Bytes::default()
} else {
bail!(
"do not know what to do with code(1) {:?} '{}'",
as_str,
notag
);
}
} else if let Some(raw) = tags.get(":raw") {
Bytes::from(hex::decode(&raw[2..])?)
} else if let Some(yul) = tags.get(":yul") {
self.compiler.yul(yul)?
} else if let Some(solidity) = tags.get(":solidity") {
self.compiler.solidity(solidity)?
} else if let Some(asm) = tags.get(":asm") {
self.compiler.asm(asm)?
} else {
bail!("do not know what to do with code(2) '{:?}'", as_str);
};

// TODO: remote the finish with STOP if does not finish with it when fixed
if !code.0.is_empty() && code.0[code.0.len() - 1] != OpcodeId::STOP.as_u8() {
let mut code_stop = Vec::new();
code_stop.extend_from_slice(&code.0);
code_stop.push(OpcodeId::STOP.as_u8());
code = Bytes::from(code_stop);
}

Ok(code)
}

/// returns the element as calldata bytes, supports :raw and :abi
fn parse_calldata(&mut self, as_str: &str) -> Result<Bytes> {
let tags = Self::decompose_tags(as_str);

if let Some(notag) = tags.get("") {
let notag = notag.trim();
if notag.is_empty() {
Ok(Bytes::default())
} else if notag.starts_with('{') {
Ok(self.compiler.lll(notag)?)
} else if let Some(hex) = notag.strip_prefix("0x") {
Ok(Bytes::from(hex::decode(hex)?))
} else {
bail!("do not know what to do with calldata (1): '{:?}'", as_str);
}
} else if let Some(raw) = tags.get(":raw") {
Ok(Bytes::from(hex::decode(&raw[2..])?))
} else if let Some(abi) = tags.get(":abi") {
Ok(abi::encode_funccall(abi)?)
} else if let Some(yul) = tags.get(":yul") {
Ok(self.compiler.yul(yul)?)
} else {
bail!(
"do not know what to do with calldata: (2) {:?} '{:?}'",
tags,
as_str
)
}
}

/// parse a hash entry
fn parse_hash(value: &str) -> Result<H256> {
if let Some(hex) = value.strip_prefix("0x") {
Ok(H256::from_slice(&hex::decode(hex).context("parse_hash")?))
} else {
Ok(H256::from_slice(&hex::decode(value).context("parse_hash")?))
}
}

/// parse an uint256 entry
fn parse_u256(as_str: &str) -> Result<U256> {
if let Some(stripped) = as_str.strip_prefix("0x") {
Ok(U256::from_str_radix(stripped, 16)?)
} else if as_str
.to_lowercase()
.contains(['a', 'b', 'c', 'd', 'e', 'f'])
{
Ok(U256::from_str_radix(as_str, 16)?)
} else {
Ok(U256::from_str_radix(as_str, 10)?)
}
}

/// parse u64 entry
#[allow(clippy::cast_sign_loss)]
fn parse_u64(as_str: &str) -> Result<u64> {
if let Some(stripped) = as_str.strip_prefix("0x") {
Ok(U256::from_str_radix(stripped, 16)?.as_u64())
} else {
Ok(U256::from_str_radix(as_str, 10)?.as_u64())
}
}

/// parse a unique or a list of references,
/// -1 => Ref::Any
/// a int value => Ref::Index(value)
Expand Down
1 change: 1 addition & 0 deletions testool/src/statetest/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod executor;
mod json;
mod parse;
mod results;
pub mod spec;
mod suite;
Expand Down
Loading

0 comments on commit 325a58f

Please sign in to comment.