use crate::BlockOverrides;
use cfx_bytes::Bytes;
use cfx_rpc_primitives::Bytes as RpcBytes;
use cfx_types::{Address, H256, U256, U64};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub type RpcStateOverride = HashMap<Address, RpcAccountOverride>;
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
pub struct RpcAccountOverride {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub balance: Option<U256>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub nonce: Option<U64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub code: Option<RpcBytes>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub state: Option<HashMap<H256, H256>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub state_diff: Option<HashMap<H256, H256>>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
rename = "movePrecompileToAddress"
)]
pub move_precompile_to: Option<Address>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AccountStateOverrideMode {
State(HashMap<H256, H256>),
Diff(HashMap<H256, H256>),
None,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AccountOverride {
pub balance: Option<U256>,
pub nonce: Option<U64>,
pub code: Option<Bytes>,
pub state: AccountStateOverrideMode,
pub move_precompile_to: Option<Address>,
}
impl TryFrom<RpcAccountOverride> for AccountOverride {
type Error = &'static str;
fn try_from(value: RpcAccountOverride) -> Result<Self, Self::Error> {
Ok(Self {
balance: value.balance,
nonce: value.nonce,
code: value.code.map(|v| v.into()),
state: match (value.state, value.state_diff) {
(Some(state), None) => AccountStateOverrideMode::State(state),
(None, Some(diff)) => AccountStateOverrideMode::Diff(diff),
(None, None) => AccountStateOverrideMode::None,
_ => return Err("state and stateDiff are mutually exclusive"),
},
move_precompile_to: value.move_precompile_to,
})
}
}
pub type StateOverride = HashMap<Address, AccountOverride>;
#[derive(Debug, Clone, Default)]
pub struct EvmOverrides {
pub state: Option<StateOverride>,
pub block: Option<Box<BlockOverrides>>,
}
impl EvmOverrides {
pub const fn new(
state: Option<StateOverride>, block: Option<Box<BlockOverrides>>,
) -> Self {
Self { state, block }
}
pub const fn state(state: Option<StateOverride>) -> Self {
Self { state, block: None }
}
pub const fn block(block: Option<Box<BlockOverrides>>) -> Self {
Self { state: None, block }
}
pub const fn has_state(&self) -> bool { self.state.is_some() }
pub const fn has_block(&self) -> bool { self.block.is_some() }
pub const fn is_none(&self) -> bool {
self.state.is_none() && self.block.is_none()
}
pub fn with_state(mut self, state: StateOverride) -> Self {
self.state = Some(state);
self
}
pub fn with_block(mut self, block: Box<BlockOverrides>) -> Self {
self.block = Some(block);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "serde")]
use cfx_types::address_util::hex_to_address;
use similar_asserts::assert_eq;
#[test]
fn test_default_account_override() {
let acc_override = RpcAccountOverride::default();
assert!(acc_override.balance.is_none());
assert!(acc_override.nonce.is_none());
assert!(acc_override.code.is_none());
assert!(acc_override.state.is_none());
assert!(acc_override.state_diff.is_none());
}
#[test]
#[cfg(feature = "serde")]
#[should_panic(expected = "invalid type")]
fn test_invalid_json_structure() {
let invalid_json = r#"{
"0x1234567890123456789012345678901234567890": {
"balance": true
}
}"#;
let _: RpcStateOverride = serde_json::from_str(invalid_json).unwrap();
}
#[test]
#[cfg(feature = "serde")]
fn test_large_values_in_override() {
let large_values_json = r#"{
"0x1234567890123456789012345678901234567890": {
"balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce": "0xffffffffffffffff"
}
}"#;
let state_override: RpcStateOverride =
serde_json::from_str(large_values_json).unwrap();
let acc = state_override
.get(
&hex_to_address("1234567890123456789012345678901234567890")
.unwrap(),
)
.unwrap();
assert_eq!(acc.balance, Some(U256::MAX));
assert_eq!(acc.nonce, Some(U64::from(u64::MAX)));
}
#[test]
#[cfg(feature = "serde")]
fn test_state_override() {
let s = r#"{
"0x0000000000000000000000000000000000000124": {
"code": "0x6080604052348015600e575f80fd5b50600436106026575f3560e01c80632096525514602a575b5f80fd5b60306044565b604051901515815260200160405180910390f35b5f604e600242605e565b5f0360595750600190565b505f90565b5f82607757634e487b7160e01b5f52601260045260245ffd5b50069056fea2646970667358221220287f77a4262e88659e3fb402138d2ee6a7ff9ba86bae487a95aa28156367d09c64736f6c63430008140033"
}
}"#;
let state_override: RpcStateOverride = serde_json::from_str(s).unwrap();
let acc = state_override
.get(
&hex_to_address("0000000000000000000000000000000000000124")
.unwrap(),
)
.unwrap();
assert!(acc.code.is_some());
}
#[test]
#[cfg(feature = "serde")]
fn test_state_override_state_diff() {
let s = r#"{
"0x1b5212AF6b76113afD94cD2B5a78a73B7d7A8222": {
"balance": "0x39726378b58c400000",
"stateDiff": {}
},
"0xdAC17F958D2ee523a2206206994597C13D831ec7": {
"stateDiff": {
"0xede27e4e7f3676edbf125879f17a896d6507958df3d57bda6219f1880cae8a41": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
}
}"#;
let state_override: RpcStateOverride = serde_json::from_str(s).unwrap();
let acc = state_override
.get(
&hex_to_address("1b5212AF6b76113afD94cD2B5a78a73B7d7A8222")
.unwrap(),
)
.unwrap();
assert!(acc.state_diff.is_some());
}
#[test]
fn test_evm_overrides_new() {
let state = StateOverride::default();
let block: Box<BlockOverrides> = Box::default();
let evm_overrides =
EvmOverrides::new(Some(state.clone()), Some(block.clone()));
assert!(evm_overrides.has_state());
assert!(evm_overrides.has_block());
assert_eq!(evm_overrides.state.unwrap(), state);
assert_eq!(*evm_overrides.block.unwrap(), *block);
}
#[test]
fn test_evm_overrides_state() {
let state = StateOverride::default();
let evm_overrides = EvmOverrides::state(Some(state.clone()));
assert!(evm_overrides.has_state());
assert!(!evm_overrides.has_block());
assert_eq!(evm_overrides.state.unwrap(), state);
}
#[test]
fn test_evm_overrides_block() {
let block: Box<BlockOverrides> = Box::default();
let evm_overrides = EvmOverrides::block(Some(block.clone()));
assert!(!evm_overrides.has_state());
assert!(evm_overrides.has_block());
assert_eq!(*evm_overrides.block.unwrap(), *block);
}
#[test]
fn test_evm_overrides_with_state() {
let state = StateOverride::default();
let mut evm_overrides = EvmOverrides::default();
assert!(!evm_overrides.has_state());
evm_overrides = evm_overrides.with_state(state.clone());
assert!(evm_overrides.has_state());
assert_eq!(evm_overrides.state.unwrap(), state);
}
#[test]
fn test_evm_overrides_with_block() {
let block: Box<BlockOverrides> = Box::default();
let mut evm_overrides = EvmOverrides::default();
assert!(!evm_overrides.has_block());
evm_overrides = evm_overrides.with_block(block.clone());
assert!(evm_overrides.has_block());
assert_eq!(*evm_overrides.block.unwrap(), *block);
}
}