Skip to content

Commit

Permalink
add precompile test contract, use it for actor_type
Browse files Browse the repository at this point in the history
  • Loading branch information
mriise committed Jan 13, 2023
1 parent b9333d2 commit 03feb36
Showing 1 changed file with 109 additions and 31 deletions.
140 changes: 109 additions & 31 deletions actors/evm/tests/precompile.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod asm;

use std::fmt::Debug;

use evm::interpreter::{address::EthAddress, U256};
use fil_actor_evm as evm;
use fil_actors_runtime::test_utils::{
Expand Down Expand Up @@ -63,58 +65,126 @@ fn test_precompile_hash() {
);
}

#[test]
fn test_native_actor_type() {
let bytecode = {
struct PrecompileTest {
pub expected_return: Vec<u8>,
pub expected_exit_code: PrecompileExit,
pub precompile_number: u8,
pub output_size: u8,
pub input: Vec<u8>,
pub gas_avaliable: u64,
}

#[repr(u8)]
enum PrecompileExit {
Reverted = 0,
Success = 1,
}

impl Debug for PrecompileTest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PrecompileTest")
.field("expected_return", &hex::encode(&self.expected_return))
.field("expected_exit_code", &(self.expected_exit_code as u8))
.field("precompile_number", &format!("{:x}", self.precompile_number))
.field("output_size", &self.output_size)
.field("precompile_number", &self.output_size)
.field("input", &hex::encode(&self.input))
.field("gas_avaliable", &self.gas_avaliable)
.finish()
}
}

impl PrecompileTest {
fn run_test(&self, rt: &mut MockRuntime) {
rt.expect_gas_available(self.gas_avaliable);
log::trace!("{:#?}", &self);
// first byte is precompile number, second is output buffer size, rest is input to precompile
let result = util::invoke_contract(
rt,
&[vec![self.precompile_number, self.output_size], self.input.clone()].concat(),
);
log::trace!("returned: {:?}", hex::encode(&result));
rt.verify();
assert_eq!(self.expected_exit_code as u8, result[0]);
assert_eq!(&self.expected_return, &result[1..]);
rt.reset();
}

fn test_runner_bytecode() -> Vec<u8> {
let init = "";
let body = r#"
# get call payload size
calldatasize
# store payload to mem 0x00
push1 0x00
push1 0x00
calldatasize
push1 0x00 # input offset
push1 0x00 # dst offset
calldatacopy
# out size
push1 0x01 # second byte of input
mload
push1 0x08
push1 0x1f
mul # 31*8 bits
shr
# out off
push1 0x20
push1 0xA0
push2 0xA0
# in size
# in off
push1 0x02
calldatasize
push1 0x00
sub
# in off
push1 0x02
# value
push1 0x00
# dst (get_actor_type precompile)
push20 0xfe00000000000000000000000000000000000004
# precompile address
push20 0xfe00000000000000000000000000000000000000
push1 0x00 # first byte of input is index
mload
push1 0x08
push1 0x1f
mul # 31*8 bits
shr
add
# gas
push1 0x00
call
# copy result to mem 0x00 (overwrites input data)
# write exit code memory
push1 0x00 # offset
mstore8
# write precompile return to memory
returndatasize
push1 0x00
push1 0x00
push1 0x00 # input offset
push1 0x01 # dst offset
returndatacopy
# return
# size
returndatasize
push1 0x01
add
# offset
push1 0x00
return
"#;

asm::new_contract("native_actor_type", init, body).unwrap()
};
asm::new_contract("precompile_tester", init, body).unwrap()
}
}

#[test]
fn test_native_actor_type() {
use evm::interpreter::precompiles::NativeType;

let mut rt = util::construct_and_verify(bytecode);
let mut rt = util::construct_and_verify(PrecompileTest::test_runner_bytecode());

// 0x88 is an EVM actor
let evm_target = FILAddress::new_id(0x88);
Expand All @@ -141,11 +211,15 @@ return
rt.set_address_actor_type(other_target, *MULTISIG_ACTOR_CODE_ID);

fn test_type(rt: &mut MockRuntime, id: FILAddress, expected: NativeType) {
rt.expect_gas_available(10_000_000_000u64);
let result = util::invoke_contract(rt, &id_to_vec(&id));
rt.verify();
assert_eq!(&U256::from(expected as u32).to_bytes(), result.as_slice());
rt.reset();
let test = PrecompileTest {
precompile_number: 4,
input: id_to_vec(&id),
output_size: 32,
expected_exit_code: PrecompileExit::Success,
expected_return: U256::from(expected as u32).to_bytes().to_vec(),
gas_avaliable: 10_000_000_000,
};
test.run_test(rt);
}

test_type(&mut rt, evm_target, NativeType::EVMContract);
Expand All @@ -157,11 +231,15 @@ return
test_type(&mut rt, FILAddress::new_id(10101), NativeType::NonExistent);

// invalid format address
rt.expect_gas_available(10_000_000_000u64);
let result = util::invoke_contract(&mut rt, &[0xff; 64]);
rt.verify();
assert!(result.is_empty());
rt.reset();
let test = PrecompileTest {
precompile_number: 4,
input: vec![0xff; 64],
output_size: 32,
expected_exit_code: PrecompileExit::Reverted,
expected_return: vec![],
gas_avaliable: 10_000_000_000,
};
test.run_test(&mut rt);
}

fn resolve_address_contract() -> Vec<u8> {
Expand Down

0 comments on commit 03feb36

Please sign in to comment.