mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-29 08:57:56 +00:00
pallet_revive: Account20 (#41)
Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
Generated
+373
-348
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -66,7 +66,7 @@ log = { version = "0.4" }
|
||||
# polkadot-sdk and friends
|
||||
codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" }
|
||||
scale-info = { version = "2.11.1", default-features = false }
|
||||
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "1c4141abeb4c581e503f07af2a3522e6918db591" }
|
||||
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "d7b575338b2c647e04fc48bfbe00ea8f492fb580" }
|
||||
|
||||
# llvm
|
||||
[workspace.dependencies.inkwell]
|
||||
|
||||
@@ -7,7 +7,7 @@ pub fn create_specs(contract: &revive_integration::cases::Contract) -> revive_ru
|
||||
actions: vec![
|
||||
Instantiate {
|
||||
code: Code::Bytes(contract.pvm_runtime.to_vec()),
|
||||
origin: TestAccountId::Alice,
|
||||
origin: TestAddress::Alice,
|
||||
data: Default::default(),
|
||||
value: Default::default(),
|
||||
gas_limit: Default::default(),
|
||||
@@ -15,8 +15,8 @@ pub fn create_specs(contract: &revive_integration::cases::Contract) -> revive_ru
|
||||
salt: Default::default(),
|
||||
},
|
||||
Call {
|
||||
origin: TestAccountId::Alice,
|
||||
dest: TestAccountId::Instantiated(0),
|
||||
origin: TestAddress::Alice,
|
||||
dest: TestAddress::Instantiated(0),
|
||||
data: contract.calldata.to_vec(),
|
||||
value: Default::default(),
|
||||
gas_limit: Default::default(),
|
||||
@@ -59,7 +59,6 @@ pub fn measure_evm(code: &[u8], input: &[u8], iters: u64) -> std::time::Duration
|
||||
let log = revive_differential::Evm::default()
|
||||
.code_blob(code.as_bytes().to_vec())
|
||||
.input(input.to_vec().into())
|
||||
.genesis_path("/tmp/genesis.json".into())
|
||||
.bench(true)
|
||||
.run();
|
||||
assert!(log.output.run_success(), "evm run failed: {log:?}");
|
||||
|
||||
@@ -12,7 +12,7 @@ macro_rules! test_spec {
|
||||
fn $test_name() {
|
||||
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("should always exist");
|
||||
let path = format!("{manifest_dir}/../integration/contracts/{}", $source_file);
|
||||
specs_from_comment($contract_name, &path).remove(0).run();
|
||||
Specs::from_comment($contract_name, &path).remove(0).run();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -36,7 +36,7 @@ test_spec!(mstore8, "MStore8", "MStore8.sol");
|
||||
|
||||
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
||||
vec![Instantiate {
|
||||
origin: TestAccountId::Alice,
|
||||
origin: TestAddress::Alice,
|
||||
value: 0,
|
||||
gas_limit: Some(GAS_LIMIT),
|
||||
storage_deposit_limit: None,
|
||||
@@ -47,15 +47,15 @@ fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
||||
pipeline: None,
|
||||
},
|
||||
data: vec![],
|
||||
salt: vec![],
|
||||
salt: OptionalHex::default(),
|
||||
}]
|
||||
}
|
||||
|
||||
fn run_differential(actions: Vec<SpecsAction>) {
|
||||
Specs {
|
||||
differential: true,
|
||||
balances: vec![(ALICE, 1_000_000_000)],
|
||||
actions,
|
||||
..Default::default()
|
||||
}
|
||||
.run();
|
||||
}
|
||||
@@ -80,8 +80,8 @@ fn bitwise_byte() {
|
||||
])
|
||||
{
|
||||
actions.push(Call {
|
||||
origin: TestAccountId::Alice,
|
||||
dest: TestAccountId::Instantiated(0),
|
||||
origin: TestAddress::Alice,
|
||||
dest: TestAddress::Instantiated(0),
|
||||
value: 0,
|
||||
gas_limit: None,
|
||||
storage_deposit_limit: None,
|
||||
@@ -107,8 +107,8 @@ fn unsigned_division() {
|
||||
(one, U256::ZERO),
|
||||
] {
|
||||
actions.push(Call {
|
||||
origin: TestAccountId::Alice,
|
||||
dest: TestAccountId::Instantiated(0),
|
||||
origin: TestAddress::Alice,
|
||||
dest: TestAddress::Instantiated(0),
|
||||
value: 0,
|
||||
gas_limit: None,
|
||||
storage_deposit_limit: None,
|
||||
@@ -142,8 +142,8 @@ fn signed_division() {
|
||||
(one, I256::ZERO),
|
||||
] {
|
||||
actions.push(Call {
|
||||
origin: TestAccountId::Alice,
|
||||
dest: TestAccountId::Instantiated(0),
|
||||
origin: TestAddress::Alice,
|
||||
dest: TestAddress::Instantiated(0),
|
||||
value: 0,
|
||||
gas_limit: None,
|
||||
storage_deposit_limit: None,
|
||||
@@ -171,8 +171,8 @@ fn unsigned_remainder() {
|
||||
(U256::MAX, U256::ZERO),
|
||||
] {
|
||||
actions.push(Call {
|
||||
origin: TestAccountId::Alice,
|
||||
dest: TestAccountId::Instantiated(0),
|
||||
origin: TestAddress::Alice,
|
||||
dest: TestAddress::Instantiated(0),
|
||||
value: 0,
|
||||
gas_limit: None,
|
||||
storage_deposit_limit: None,
|
||||
@@ -212,8 +212,8 @@ fn signed_remainder() {
|
||||
(I256::ZERO, I256::ZERO),
|
||||
] {
|
||||
actions.push(Call {
|
||||
origin: TestAccountId::Alice,
|
||||
dest: TestAccountId::Instantiated(0),
|
||||
origin: TestAddress::Alice,
|
||||
dest: TestAddress::Instantiated(0),
|
||||
value: 0,
|
||||
gas_limit: None,
|
||||
storage_deposit_limit: None,
|
||||
|
||||
@@ -714,7 +714,7 @@ where
|
||||
&[
|
||||
self.xlen_type().const_int(transient as u64, false).into(),
|
||||
storage_key_pointer_casted.into(),
|
||||
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
||||
self.xlen_type().const_all_ones().into(),
|
||||
storage_value_pointer.to_int(self).into(),
|
||||
storage_value_length_pointer.to_int(self).into(),
|
||||
],
|
||||
@@ -813,7 +813,7 @@ where
|
||||
&[
|
||||
self.xlen_type().const_int(transient as u64, false).into(),
|
||||
storage_key_pointer_casted.into(),
|
||||
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
||||
self.xlen_type().const_all_ones().into(),
|
||||
storage_value_pointer_casted.into(),
|
||||
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
||||
],
|
||||
@@ -1249,7 +1249,7 @@ where
|
||||
self.llvm.custom_width_int_type(crate::polkavm::XLEN as u32)
|
||||
}
|
||||
|
||||
/// Returns the register witdh sized type.
|
||||
/// Returns the sentinel pointer value.
|
||||
pub fn sentinel_pointer(&self) -> Pointer<'ctx> {
|
||||
let sentinel_pointer = self
|
||||
.xlen_type()
|
||||
|
||||
+46
-77
@@ -11,13 +11,13 @@
|
||||
//! differential: false,
|
||||
//! balances: vec![(ALICE, 1_000_000_000)],
|
||||
//! actions: vec![Instantiate {
|
||||
//! origin: TestAccountId::Alice,
|
||||
//! origin: TestAddress::Alice,
|
||||
//! value: 0,
|
||||
//! gas_limit: Some(GAS_LIMIT),
|
||||
//! storage_deposit_limit: Some(DEPOSIT_LIMIT),
|
||||
//! code: Code::Bytes(include_bytes!("../fixtures/Baseline.pvm").to_vec()),
|
||||
//! data: vec![],
|
||||
//! salt: vec![],
|
||||
//! salt: Default::default(),
|
||||
//! }],
|
||||
//! }
|
||||
//! .run();
|
||||
@@ -25,41 +25,52 @@
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use hex::{FromHex, FromHexError, ToHex};
|
||||
use hex::{FromHex, ToHex};
|
||||
use pallet_revive::AddressMapper;
|
||||
use polkadot_sdk::*;
|
||||
use polkadot_sdk::{
|
||||
pallet_revive::{CollectEvents, ContractExecResult, ContractInstantiateResult, DebugInfo},
|
||||
polkadot_runtime_common::BuildStorage,
|
||||
polkadot_sdk_frame::testing_prelude::*,
|
||||
sp_core::H160,
|
||||
sp_keystore::{testing::MemoryKeystore, KeystoreExt},
|
||||
sp_runtime::AccountId32,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
mod runtime;
|
||||
mod specs;
|
||||
|
||||
use crate::runtime::*;
|
||||
pub use crate::specs::*;
|
||||
|
||||
pub const ALICE: AccountId = AccountId::new([1u8; 32]);
|
||||
pub const BOB: AccountId = AccountId::new([2u8; 32]);
|
||||
pub const CHARLIE: AccountId = AccountId::new([3u8; 32]);
|
||||
mod runtime;
|
||||
mod specs;
|
||||
|
||||
const SPEC_MARKER_BEGIN: &str = "/* runner.json";
|
||||
const SPEC_MARKER_END: &str = "*/";
|
||||
/// The alice test account
|
||||
pub const ALICE: H160 = H160([1u8; 20]);
|
||||
/// The bob test account
|
||||
pub const BOB: H160 = H160([2u8; 20]);
|
||||
/// The charlie test account
|
||||
pub const CHARLIE: H160 = H160([3u8; 20]);
|
||||
/// Default gas limit
|
||||
pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 1024);
|
||||
/// Default deposit limit
|
||||
pub const DEPOSIT_LIMIT: Balance = 10_000_000;
|
||||
|
||||
/// Externalities builder
|
||||
#[derive(Default)]
|
||||
pub struct ExtBuilder {
|
||||
/// List of endowments at genesis
|
||||
balance_genesis_config: Vec<(AccountId, Balance)>,
|
||||
balance_genesis_config: Vec<(AccountId32, Balance)>,
|
||||
}
|
||||
|
||||
impl ExtBuilder {
|
||||
/// Set the balance of an account at genesis
|
||||
fn balance_genesis_config(mut self, value: Vec<(AccountId, Balance)>) -> Self {
|
||||
self.balance_genesis_config = value;
|
||||
self
|
||||
fn balance_genesis_config(self, value: Vec<(H160, Balance)>) -> Self {
|
||||
Self {
|
||||
balance_genesis_config: value
|
||||
.iter()
|
||||
.map(|(address, balance)| (AccountId::to_account_id(address), *balance))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the externalities
|
||||
@@ -81,12 +92,6 @@ impl ExtBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Default gas limit
|
||||
pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 1024);
|
||||
|
||||
/// Default deposit limit
|
||||
pub const DEPOSIT_LIMIT: Balance = 10_000_000;
|
||||
|
||||
/// Expectation for a call
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VerifyCallExpectation {
|
||||
@@ -94,45 +99,45 @@ pub struct VerifyCallExpectation {
|
||||
pub gas_consumed: Option<Weight>,
|
||||
/// When provided, the expected output
|
||||
#[serde(default, with = "hex")]
|
||||
pub output: OptionalHex,
|
||||
pub output: OptionalHex<Vec<u8>>,
|
||||
///Expected call result
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct OptionalHex(Option<Vec<u8>>);
|
||||
pub struct OptionalHex<T>(Option<T>);
|
||||
|
||||
impl FromHex for OptionalHex {
|
||||
type Error = FromHexError;
|
||||
impl<I: FromHex + AsRef<[u8]>> FromHex for OptionalHex<I> {
|
||||
type Error = <I as FromHex>::Error;
|
||||
|
||||
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
|
||||
let value = hex::decode(hex)?;
|
||||
let value = I::from_hex(hex)?;
|
||||
Ok(Self(Some(value)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHex for &OptionalHex {
|
||||
impl<I: AsRef<[u8]>> ToHex for &OptionalHex<I> {
|
||||
fn encode_hex<T: std::iter::FromIterator<char>>(&self) -> T {
|
||||
match self.0.as_ref() {
|
||||
None => T::from_iter("".chars()),
|
||||
Some(data) => T::from_iter(hex::encode(data).chars()),
|
||||
Some(data) => I::encode_hex::<T>(data),
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_hex_upper<T: std::iter::FromIterator<char>>(&self) -> T {
|
||||
match self.0.as_ref() {
|
||||
None => T::from_iter("".chars()),
|
||||
Some(data) => T::from_iter(hex::encode_upper(data).chars()),
|
||||
Some(data) => I::encode_hex_upper(data),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<alloy_primitives::Bytes> for OptionalHex {
|
||||
fn from(value: alloy_primitives::Bytes) -> Self {
|
||||
if value.is_empty() {
|
||||
impl<T: AsRef<[u8]>> From<T> for OptionalHex<T> {
|
||||
fn from(value: T) -> Self {
|
||||
if value.as_ref().is_empty() {
|
||||
OptionalHex(None)
|
||||
} else {
|
||||
OptionalHex(Some(value.into()))
|
||||
OptionalHex(Some(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,9 +160,11 @@ impl VerifyCallExpectation {
|
||||
result.is_ok(),
|
||||
"contract execution result mismatch: {result:?}"
|
||||
);
|
||||
|
||||
if let Some(gas_consumed) = self.gas_consumed {
|
||||
assert_eq!(gas_consumed, result.gas_consumed());
|
||||
}
|
||||
|
||||
if let OptionalHex(Some(data)) = self.output {
|
||||
assert_eq!(data, result.output());
|
||||
}
|
||||
@@ -172,7 +179,7 @@ pub enum CallResult {
|
||||
wall_time: Duration,
|
||||
},
|
||||
Instantiate {
|
||||
result: ContractInstantiateResult<AccountId, Balance, EventRecord>,
|
||||
result: ContractInstantiateResult<Balance, EventRecord>,
|
||||
wall_time: Duration,
|
||||
},
|
||||
}
|
||||
@@ -209,7 +216,7 @@ impl CallResult {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum Code {
|
||||
/// Compile a single solidity source and use the blob of `contract`
|
||||
Solidity {
|
||||
@@ -232,7 +239,7 @@ impl Default for Code {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Code> for pallet_revive::Code<Hash> {
|
||||
impl From<Code> for pallet_revive::Code {
|
||||
fn from(val: Code) -> Self {
|
||||
match val {
|
||||
Code::Solidity {
|
||||
@@ -261,44 +268,6 @@ impl From<Code> for pallet_revive::Code<Hash> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn specs_from_comment(contract_name: &str, path: &str) -> Vec<Specs> {
|
||||
let solidity = match std::fs::read_to_string(path) {
|
||||
Err(err) => panic!("unable to read {path}: {err}"),
|
||||
Ok(solidity) => solidity,
|
||||
};
|
||||
let mut json_string = String::with_capacity(solidity.len());
|
||||
let mut is_reading = false;
|
||||
let mut specs = Vec::new();
|
||||
|
||||
for line in solidity.lines() {
|
||||
if line.starts_with(SPEC_MARKER_BEGIN) {
|
||||
is_reading = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if is_reading {
|
||||
if line.starts_with(SPEC_MARKER_END) {
|
||||
match serde_json::from_str::<Specs>(&json_string) {
|
||||
Ok(mut spec) => {
|
||||
spec.replace_empty_code(contract_name, path);
|
||||
specs.push(spec);
|
||||
}
|
||||
Err(e) => panic!("invalid spec JSON: {e}"),
|
||||
}
|
||||
is_reading = false;
|
||||
json_string.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
json_string.push_str(line)
|
||||
}
|
||||
}
|
||||
|
||||
assert!(!specs.is_empty(), "source does not contain any test spec");
|
||||
|
||||
specs
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::*;
|
||||
@@ -310,13 +279,13 @@ mod tests {
|
||||
differential: false,
|
||||
balances: vec![(ALICE, 1_000_000_000)],
|
||||
actions: vec![Instantiate {
|
||||
origin: TestAccountId::Alice,
|
||||
origin: TestAddress::Alice,
|
||||
value: 0,
|
||||
gas_limit: Some(GAS_LIMIT),
|
||||
storage_deposit_limit: Some(DEPOSIT_LIMIT),
|
||||
code: Code::Bytes(include_bytes!("../fixtures/Baseline.pvm").to_vec()),
|
||||
data: vec![],
|
||||
salt: vec![],
|
||||
salt: OptionalHex::default(),
|
||||
}],
|
||||
};
|
||||
specs.run();
|
||||
@@ -328,7 +297,7 @@ mod tests {
|
||||
r#"
|
||||
{
|
||||
"balances": [
|
||||
[ "5C62Ck4UrFPiBtoCmeSrgF7x9yv9mn38446dhCpsi2mLHiFT", 1000000000 ]
|
||||
[ "0101010101010101010101010101010101010101", 1000000000 ]
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ use polkadot_sdk::{
|
||||
};
|
||||
|
||||
pub type Balance = u128;
|
||||
pub type AccountId = AccountId32;
|
||||
pub type AccountId = pallet_revive::DefaultAddressMapper;
|
||||
pub type Block = frame_system::mocking::MockBlock<Runtime>;
|
||||
pub type Hash = <Runtime as frame_system::Config>::Hash;
|
||||
pub type EventRecord =
|
||||
@@ -45,7 +45,7 @@ mod runtime {
|
||||
#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
type Block = Block;
|
||||
type AccountId = AccountId;
|
||||
type AccountId = AccountId32;
|
||||
type AccountData = pallet_balances::AccountData<<Runtime as pallet_balances::Config>::Balance>;
|
||||
}
|
||||
|
||||
@@ -74,10 +74,10 @@ impl pallet_revive::Config for Runtime {
|
||||
type ChainExtension = ();
|
||||
type DepositPerByte = DepositPerByte;
|
||||
type DepositPerItem = DepositPerItem;
|
||||
type AddressGenerator = pallet_revive::DefaultAddressGenerator;
|
||||
type AddressMapper = AccountId;
|
||||
type UnsafeUnstableInterface = UnstableInterface;
|
||||
type UploadOrigin = EnsureSigned<AccountId>;
|
||||
type InstantiateOrigin = EnsureSigned<AccountId>;
|
||||
type UploadOrigin = EnsureSigned<AccountId32>;
|
||||
type InstantiateOrigin = EnsureSigned<AccountId32>;
|
||||
type Migrations = ();
|
||||
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
|
||||
type Debug = ();
|
||||
|
||||
+85
-49
@@ -1,5 +1,6 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use pallet_revive::AddressMapper;
|
||||
use revive_differential::{Evm, EvmLog};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -7,13 +8,16 @@ use crate::*;
|
||||
use alloy_primitives::Address;
|
||||
use revive_solidity::test_utils::*;
|
||||
|
||||
const SPEC_MARKER_BEGIN: &str = "/* runner.json";
|
||||
const SPEC_MARKER_END: &str = "*/";
|
||||
|
||||
/// An action to perform in a contract test
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum SpecsAction {
|
||||
/// Instantiate a contract
|
||||
Instantiate {
|
||||
#[serde(default)]
|
||||
origin: TestAccountId,
|
||||
origin: TestAddress,
|
||||
#[serde(default)]
|
||||
value: Balance,
|
||||
#[serde(default)]
|
||||
@@ -25,13 +29,13 @@ pub enum SpecsAction {
|
||||
#[serde(default, with = "hex::serde")]
|
||||
data: Vec<u8>,
|
||||
#[serde(default, with = "hex::serde")]
|
||||
salt: Vec<u8>,
|
||||
salt: OptionalHex<[u8; 32]>,
|
||||
},
|
||||
/// Call a contract
|
||||
Call {
|
||||
#[serde(default)]
|
||||
origin: TestAccountId,
|
||||
dest: TestAccountId,
|
||||
origin: TestAddress,
|
||||
dest: TestAddress,
|
||||
#[serde(default)]
|
||||
value: Balance,
|
||||
#[serde(default)]
|
||||
@@ -46,16 +50,16 @@ pub enum SpecsAction {
|
||||
|
||||
/// Verify the balance of an account
|
||||
VerifyBalance {
|
||||
origin: TestAccountId,
|
||||
origin: TestAddress,
|
||||
expected: Balance,
|
||||
},
|
||||
/// Verify the storage of a contract
|
||||
VerifyStorage {
|
||||
contract: TestAccountId,
|
||||
contract: TestAddress,
|
||||
#[serde(with = "hex::serde")]
|
||||
key: Vec<u8>,
|
||||
key: [u8; 32],
|
||||
#[serde(default, with = "hex::serde")]
|
||||
expected: Vec<u8>,
|
||||
expected: [u8; 32],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -64,7 +68,7 @@ impl SpecsAction {
|
||||
pub fn derive_verification(
|
||||
log: &EvmLog,
|
||||
address_evm: Address,
|
||||
account_pvm: TestAccountId,
|
||||
account_pvm: TestAddress,
|
||||
) -> Vec<Self> {
|
||||
let account = log
|
||||
.state_dump
|
||||
@@ -76,7 +80,7 @@ impl SpecsAction {
|
||||
Self::VerifyCall(VerifyCallExpectation {
|
||||
gas_consumed: None,
|
||||
success: log.output.run_success(),
|
||||
output: log.output.output.clone().into(),
|
||||
output: log.output.output.to_vec().into(),
|
||||
}),
|
||||
Self::VerifyBalance {
|
||||
origin: account_pvm.clone(),
|
||||
@@ -92,9 +96,9 @@ impl SpecsAction {
|
||||
};
|
||||
|
||||
for (key, expected) in storage {
|
||||
let mut key = key.to_vec();
|
||||
let mut key = **key;
|
||||
let mut expected = **expected;
|
||||
key.reverse();
|
||||
let mut expected = expected.to_vec();
|
||||
expected.reverse();
|
||||
actions.push(Self::VerifyStorage {
|
||||
contract: account_pvm.clone(),
|
||||
@@ -108,7 +112,7 @@ impl SpecsAction {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||
pub enum TestAccountId {
|
||||
pub enum TestAddress {
|
||||
/// The ALICE account
|
||||
#[default]
|
||||
Alice,
|
||||
@@ -119,30 +123,31 @@ pub enum TestAccountId {
|
||||
/// AccountID that was created during the nth call in this run.
|
||||
Instantiated(usize),
|
||||
/// Arbitrary AccountID
|
||||
AccountId(AccountId),
|
||||
AccountId(H160),
|
||||
}
|
||||
|
||||
impl TestAccountId {
|
||||
fn to_account_id(&self, results: &[CallResult]) -> AccountId {
|
||||
impl TestAddress {
|
||||
fn to_eth_addr(&self, results: &[CallResult]) -> H160 {
|
||||
match self {
|
||||
TestAccountId::Alice => ALICE,
|
||||
TestAccountId::Bob => BOB,
|
||||
TestAccountId::Charlie => CHARLIE,
|
||||
TestAccountId::AccountId(account_id) => account_id.clone(),
|
||||
TestAccountId::Instantiated(n) => match results
|
||||
TestAddress::Alice => ALICE,
|
||||
TestAddress::Bob => BOB,
|
||||
TestAddress::Charlie => CHARLIE,
|
||||
TestAddress::AccountId(account_id) => *account_id,
|
||||
TestAddress::Instantiated(n) => match results
|
||||
.get(*n)
|
||||
.expect("should provide valid index into call results")
|
||||
{
|
||||
CallResult::Exec { .. } => panic!("call #{n} should be an instantiation"),
|
||||
CallResult::Instantiate { result, .. } => result
|
||||
.result
|
||||
.as_ref()
|
||||
.expect("call #{n} reverted")
|
||||
.account_id
|
||||
.clone(),
|
||||
CallResult::Instantiate { result, .. } => {
|
||||
result.result.as_ref().expect("call #{n} reverted").addr
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn to_account_id(&self, results: &[CallResult]) -> AccountId32 {
|
||||
AccountId::to_account_id(&self.to_eth_addr(results))
|
||||
}
|
||||
}
|
||||
|
||||
/// Specs for a contract test
|
||||
@@ -153,7 +158,7 @@ pub struct Specs {
|
||||
#[serde(default)]
|
||||
pub differential: bool,
|
||||
/// List of endowments at genesis
|
||||
pub balances: Vec<(AccountId, Balance)>,
|
||||
pub balances: Vec<(H160, Balance)>,
|
||||
/// List of actions to perform
|
||||
pub actions: Vec<SpecsAction>,
|
||||
}
|
||||
@@ -263,8 +268,8 @@ impl Specs {
|
||||
assert_ne!(solc_optimizer, Some(false), "solc_optimizer must be enabled in differntial mode");
|
||||
assert_ne!(pipeline, Some(revive_solidity::SolcPipeline::EVMLA), "yul pipeline must be enabled in differntial mode");
|
||||
assert!(storage_deposit_limit.is_none(), "storage deposit limit is not supported in differential mode");
|
||||
assert!(salt.is_empty(), "salt is not supported in differential mode");
|
||||
assert_eq!(origin, TestAccountId::default(), "configuring the origin is not supported in differential mode");
|
||||
assert!(salt.0.is_none(), "salt is not supported in differential mode");
|
||||
assert_eq!(origin, TestAddress::default(), "configuring the origin is not supported in differential mode");
|
||||
let deploy_code = match std::fs::read_to_string(&path) {
|
||||
Ok(solidity_source) => compile_evm_deploy_code(&contract, &solidity_source),
|
||||
Err(err) => panic!(
|
||||
@@ -287,7 +292,7 @@ impl Specs {
|
||||
let mut log = vm.run();
|
||||
log.output.output = Default::default(); // PVM will not have constructor output
|
||||
let deployed_account = log.account_deployed.expect("no account was created");
|
||||
let account_pvm = TestAccountId::Instantiated(deployed_accounts.len());
|
||||
let account_pvm = TestAddress::Instantiated(deployed_accounts.len());
|
||||
deployed_accounts.push(deployed_account);
|
||||
derived_specs.actions.append(&mut SpecsAction::derive_verification(&log, deployed_account, account_pvm));
|
||||
evm = Evm::from_genesis(log.state_dump.into());
|
||||
@@ -300,9 +305,9 @@ impl Specs {
|
||||
storage_deposit_limit,
|
||||
data,
|
||||
} => {
|
||||
assert_eq!(origin, TestAccountId::default(), "configuring the origin is not supported in differential mode");
|
||||
assert_eq!(origin, TestAddress::default(), "configuring the origin is not supported in differential mode");
|
||||
assert!(storage_deposit_limit.is_none(), "storage deposit limit is not supported in differential mode");
|
||||
let TestAccountId::Instantiated(n) = dest else {
|
||||
let TestAddress::Instantiated(n) = dest else {
|
||||
panic!("the differential runner requires TestAccountId::Instantiated(n) as dest");
|
||||
};
|
||||
let address = deployed_accounts.get(n).unwrap_or_else(|| panic!("no account at index {n} "));
|
||||
@@ -357,7 +362,7 @@ impl Specs {
|
||||
storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT),
|
||||
code.into(),
|
||||
data,
|
||||
salt,
|
||||
salt.0,
|
||||
DebugInfo::Skip,
|
||||
CollectEvents::Skip,
|
||||
);
|
||||
@@ -374,12 +379,10 @@ impl Specs {
|
||||
storage_deposit_limit,
|
||||
data,
|
||||
} => {
|
||||
let origin = RuntimeOrigin::signed(origin.to_account_id(&results));
|
||||
let dest = dest.to_account_id(&results);
|
||||
let time_start = Instant::now();
|
||||
let result = Contracts::bare_call(
|
||||
origin,
|
||||
dest,
|
||||
RuntimeOrigin::signed(origin.to_account_id(&results)),
|
||||
dest.to_eth_addr(&results),
|
||||
value,
|
||||
gas_limit.unwrap_or(GAS_LIMIT),
|
||||
storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT),
|
||||
@@ -404,16 +407,15 @@ impl Specs {
|
||||
key,
|
||||
expected,
|
||||
} => {
|
||||
let Ok(storage) = Contracts::get_storage(
|
||||
contract.to_account_id(&results),
|
||||
key.clone(),
|
||||
) else {
|
||||
panic!("Error reading storage");
|
||||
let address = contract.to_eth_addr(&results);
|
||||
dbg!(contract.to_account_id(&results));
|
||||
let Ok(value) = Contracts::get_storage(address, key) else {
|
||||
panic!("error reading storage for address {address}");
|
||||
};
|
||||
let Some(value) = storage else {
|
||||
panic!("No value for storage key 0x{}", hex::encode(key));
|
||||
let Some(value) = value else {
|
||||
panic!("no value at {address} key 0x{}", hex::encode(key));
|
||||
};
|
||||
assert_eq!(value, expected, "at key {}", hex::encode(&key));
|
||||
assert_eq!(value, expected, "at key 0x{}", hex::encode(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -421,8 +423,42 @@ impl Specs {
|
||||
|
||||
results
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SpecsRunner {
|
||||
fn run_action(&mut self, spec: &mut Specs) -> Vec<CallResult>;
|
||||
pub fn from_comment(contract_name: &str, path: &str) -> Vec<Self> {
|
||||
let solidity = match std::fs::read_to_string(path) {
|
||||
Err(err) => panic!("unable to read {path}: {err}"),
|
||||
Ok(solidity) => solidity,
|
||||
};
|
||||
let mut json_string = String::with_capacity(solidity.len());
|
||||
let mut is_reading = false;
|
||||
let mut specs = Vec::new();
|
||||
|
||||
for line in solidity.lines() {
|
||||
if line.starts_with(SPEC_MARKER_BEGIN) {
|
||||
is_reading = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if is_reading {
|
||||
if line.starts_with(SPEC_MARKER_END) {
|
||||
match serde_json::from_str::<Specs>(&json_string) {
|
||||
Ok(mut spec) => {
|
||||
spec.replace_empty_code(contract_name, path);
|
||||
specs.push(spec);
|
||||
}
|
||||
Err(e) => panic!("invalid spec JSON: {e}"),
|
||||
}
|
||||
is_reading = false;
|
||||
json_string.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
json_string.push_str(line)
|
||||
}
|
||||
}
|
||||
|
||||
assert!(!specs.is_empty(), "source does not contain any test spec");
|
||||
|
||||
specs
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user