diff --git a/actors/evm/tests/call.rs b/actors/evm/tests/call.rs index 40727175b..c6d64c2d3 100644 --- a/actors/evm/tests/call.rs +++ b/actors/evm/tests/call.rs @@ -1,18 +1,28 @@ mod asm; +use std::fmt::Debug; +use std::sync::Arc; + +use ethers::abi::Detokenize; +use ethers::prelude::builders::ContractCall; +use ethers::prelude::*; +use ethers::providers::{MockProvider, Provider}; +use ethers::types::Bytes; use evm::interpreter::address::EthAddress; use evm::interpreter::U256; use evm::EVM_CONTRACT_REVERTED; use fil_actor_evm as evm; -use fil_actors_runtime::test_utils::*; +use fil_actors_runtime::{test_utils::*, EAM_ACTOR_ID, INIT_ACTOR_ADDR}; use fvm_ipld_encoding::ipld_block::IpldBlock; -use fvm_ipld_encoding::{BytesSer, IPLD_RAW}; +use fvm_ipld_encoding::{BytesDe, BytesSer, IPLD_RAW}; use fvm_shared::address::Address as FILAddress; +use fvm_shared::address::Address; use fvm_shared::bigint::Zero; use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; use fvm_shared::sys::SendFlags; -use fvm_shared::{MethodNum, METHOD_SEND}; +use fvm_shared::{ActorID, MethodNum, METHOD_SEND}; +use once_cell::sync::Lazy; mod util; @@ -350,6 +360,11 @@ pub fn filecoin_fallback_contract() -> Vec { hex::decode(include_str!("contracts/FilecoinFallback.hex")).unwrap() } +#[allow(dead_code)] +pub fn filecoin_call_actor_contract() -> Vec { + hex::decode(include_str!("contracts/CallActorPrecompile.hex")).unwrap() +} + #[test] fn test_reserved_method() { let contract = filecoin_fallback_contract(); @@ -375,7 +390,7 @@ fn test_native_call() { rt.expect_validate_caller_any(); let err = rt.call::(1026, None).unwrap_err(); assert_eq!(err.exit_code().value(), 42); - assert_eq!(err.data(), &[]); + assert!(err.data().is_empty()); rt.expect_validate_caller_any(); let err = rt.call::(1027, None).unwrap_err(); @@ -446,6 +461,23 @@ fn test_callactor_revert() { test_callactor_inner(2048, EVM_CONTRACT_REVERTED, true) } +// Much taken from tests/env.rs +abigen!(CallActorPrecompile, "./tests/contracts/CallActorPrecompile.abi"); + +const OWNER_ID: ActorID = 1001; +const _OWNER: Address = Address::new_id(OWNER_ID); +static CONTRACT: Lazy>> = Lazy::new(|| { + // The owner of the contract is expected to be the 160 bit hash used on Ethereum. + // We're not going to use it during the tests. + let address = EthAddress::from_id(OWNER_ID); + let address = ethers::core::types::Address::from_slice(address.as_ref()); + // A dummy client that we don't intend to use to call the contract or send transactions. + let (client, _mock) = Provider::mocked(); + CallActorPrecompile::new(address, Arc::new(client)) +}); + +pub type TestContractCall = ContractCall, R>; + #[test] fn test_callactor_restrict() { // Should propagate the return value if the called actor fails. @@ -459,6 +491,7 @@ fn test_callactor_inner(method_num: MethodNum, exit_code: ExitCode, valid_call_i // construct the proxy let mut rt = util::construct_and_verify(contract); + // create a mock target and proxy a call through the proxy let target_id = 0x100; let target = FILAddress::new_id(target_id); @@ -603,6 +636,141 @@ fn make_raw_params(bytes: Vec) -> Option { if bytes.is_empty() { return None; } - Some(IpldBlock { codec: IPLD_RAW, data: bytes }) } + +#[test] +fn call_actor_solidity() { + // solidity + let contract_hex = include_str!("contracts/CallActorPrecompile.hex"); + // let mut contract_rt = new_call_actor_contract(); + let contract_address = EthAddress(util::CONTRACT_ADDRESS); + let mut tester = ContractTester::new(contract_address, contract_hex); + + // call_actor_id + { + let params = + CONTRACT.call_actor_id(0, ethers::types::U256::zero(), 0, 0, Bytes::default(), 101); + + let expected_return = vec![0xff, 0xfe]; + tester.rt.expect_send_generalized( + Address::new_id(101), + 0, + None, + TokenAmount::from_atto(0), + Some(9843750), + SendFlags::empty(), + Some(IpldBlock { codec: 0, data: expected_return.clone() }), + ExitCode::OK, + ); + + let (success, exit, codec, ret_val): (bool, ethers::types::I256, u64, Bytes) = + tester.call(params); + + assert!(success); + assert_eq!(exit, I256::from(0)); + assert_eq!(codec, 0); + assert_eq!(&ret_val, &expected_return, "got {}", hex::encode(&ret_val)); + } + tester.rt.reset(); + // call_actor + { + log::warn!("new test"); + // EVM actor + let evm_target = FILAddress::new_id(10101); + let evm_del = EthAddress(util::CONTRACT_ADDRESS).try_into().unwrap(); + tester.rt.add_delegated_address(evm_target, evm_del); + + let to_address = { + let subaddr = hex_literal::hex!("b0ba000000000000000000000000000000000000"); + Address::new_delegated(EAM_ACTOR_ID, &subaddr).unwrap() + }; + let params = CONTRACT.call_actor_address( + 0, + ethers::types::U256::zero(), + 0, + 0, + Bytes::default(), + to_address.to_bytes().into(), + ); + + let expected_return = vec![0xff, 0xfe]; + tester.rt.expect_send_generalized( + to_address, + 0, + None, + TokenAmount::from_atto(0), + Some(9843750), + SendFlags::empty(), + Some(IpldBlock { codec: 0, data: expected_return.clone() }), + ExitCode::OK, + ); + + let (success, exit, codec, ret_val): (bool, ethers::types::I256, u64, Bytes) = + tester.call(params); + + assert!(success); + assert_eq!(exit, I256::from(0)); + assert_eq!(codec, 0); + assert_eq!(&ret_val, &expected_return, "got {}", hex::encode(&ret_val)); + } +} + +pub(crate) struct ContractTester { + rt: MockRuntime, + _address: EthAddress, +} + +impl ContractTester { + fn new(addr: EthAddress, contract_hex: &str) -> Self { + init_logging().ok(); + + let mut rt = MockRuntime::default(); + let params = evm::ConstructorParams { + creator: EthAddress::from_id(EAM_ACTOR_ID), + initcode: hex::decode(contract_hex).unwrap().into(), + }; + // invoke constructor + rt.expect_validate_caller_addr(vec![INIT_ACTOR_ADDR]); + rt.set_caller(*INIT_ACTOR_CODE_ID, INIT_ACTOR_ADDR); + + rt.set_origin(FILAddress::new_id(0)); + // first actor created is 0 + rt.add_delegated_address( + Address::new_id(0), + Address::new_delegated(EAM_ACTOR_ID, &addr.0).unwrap(), + ); + + assert!(rt + .call::( + evm::Method::Constructor as u64, + IpldBlock::serialize_cbor(¶ms).unwrap(), + ) + .unwrap() + .is_none()); + + rt.verify(); + rt.reset(); + Self { rt, _address: addr } + } + + fn call(&mut self, call: TestContractCall) -> Returns { + let input = call.calldata().expect("Should have calldata."); + let input = + IpldBlock::serialize_cbor(&BytesSer(&input)).expect("failed to serialize input data"); + + self.rt.expect_validate_caller_any(); + self.rt.expect_gas_available(10_000_000); + self.rt.expect_gas_available(10_000_000); + + let BytesDe(result) = self + .rt + .call::(evm::Method::InvokeContract as u64, input) + .unwrap() + .unwrap() + .deserialize() + .unwrap(); + + decode_function_data(&call.function, result, false).unwrap() + } +} diff --git a/actors/evm/tests/contracts/CallActorPrecompile.abi b/actors/evm/tests/contracts/CallActorPrecompile.abi new file mode 100644 index 000000000..c503fef76 --- /dev/null +++ b/actors/evm/tests/contracts/CallActorPrecompile.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint64","name":"method","type":"uint64"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint64","name":"flags","type":"uint64"},{"internalType":"uint64","name":"codec","type":"uint64"},{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes","name":"filAddress","type":"bytes"}],"name":"call_actor_address","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"int256","name":"","type":"int256"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"method","type":"uint64"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint64","name":"flags","type":"uint64"},{"internalType":"uint64","name":"codec","type":"uint64"},{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"uint64","name":"id","type":"uint64"}],"name":"call_actor_id","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"int256","name":"","type":"int256"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/actors/evm/tests/contracts/CallActorPrecompile.bin b/actors/evm/tests/contracts/CallActorPrecompile.bin new file mode 100644 index 000000000..0384970a0 --- /dev/null +++ b/actors/evm/tests/contracts/CallActorPrecompile.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610994806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636aba510b1461003b5780637f18c2201461006e575b600080fd5b61005560048036038101906100509190610375565b6100a1565b60405161006594939291906104f7565b60405180910390f35b61008860048036038101906100839190610543565b610192565b60405161009894939291906104f7565b60405180910390f35b6000806000606060008073fe0000000000000000000000000000000000000573ffffffffffffffffffffffffffffffffffffffff168d8d8d8d8d8d8d6040516020016100f3979695949392919061065d565b60405160208183030381529060405260405161010f9190610703565b600060405180830381855af49150503d806000811461014a576040519150601f19603f3d011682016040523d82523d6000602084013e61014f565b606091505b509150915060008060008380602001905181019061016d919061087c565b9250925092508483838398509850985098505050505050975097509750979350505050565b6000806000606060008073fe0000000000000000000000000000000000000373ffffffffffffffffffffffffffffffffffffffff168e8e8e8e8e8e8e8e6040516020016101e69897969594939291906108eb565b6040516020818303038152906040526040516102029190610703565b600060405180830381855af49150503d806000811461023d576040519150601f19603f3d011682016040523d82523d6000602084013e610242565b606091505b5091509150600080600083806020019051810190610260919061087c565b925092509250848383839850985098509850505050505098509850985098945050505050565b6000604051905090565b600080fd5b600080fd5b600067ffffffffffffffff82169050919050565b6102b78161029a565b81146102c257600080fd5b50565b6000813590506102d4816102ae565b92915050565b6000819050919050565b6102ed816102da565b81146102f857600080fd5b50565b60008135905061030a816102e4565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261033557610334610310565b5b8235905067ffffffffffffffff81111561035257610351610315565b5b60208301915083600182028301111561036e5761036d61031a565b5b9250929050565b600080600080600080600060c0888a03121561039457610393610290565b5b60006103a28a828b016102c5565b97505060206103b38a828b016102fb565b96505060406103c48a828b016102c5565b95505060606103d58a828b016102c5565b945050608088013567ffffffffffffffff8111156103f6576103f5610295565b5b6104028a828b0161031f565b935093505060a06104158a828b016102c5565b91505092959891949750929550565b60008115159050919050565b61043981610424565b82525050565b6000819050919050565b6104528161043f565b82525050565b6104618161029a565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b838110156104a1578082015181840152602081019050610486565b60008484015250505050565b6000601f19601f8301169050919050565b60006104c982610467565b6104d38185610472565b93506104e3818560208601610483565b6104ec816104ad565b840191505092915050565b600060808201905061050c6000830187610430565b6105196020830186610449565b6105266040830185610458565b818103606083015261053881846104be565b905095945050505050565b60008060008060008060008060c0898b03121561056357610562610290565b5b60006105718b828c016102c5565b98505060206105828b828c016102fb565b97505060406105938b828c016102c5565b96505060606105a48b828c016102c5565b955050608089013567ffffffffffffffff8111156105c5576105c4610295565b5b6105d18b828c0161031f565b945094505060a089013567ffffffffffffffff8111156105f4576105f3610295565b5b6106008b828c0161031f565b92509250509295985092959890939650565b61061b816102da565b82525050565b82818337600083830152505050565b600061063c8385610472565b9350610649838584610621565b610652836104ad565b840190509392505050565b600060c082019050610672600083018a610458565b61067f6020830189610612565b61068c6040830188610458565b6106996060830187610458565b81810360808301526106ac818587610630565b90506106bb60a0830184610458565b98975050505050505050565b600081905092915050565b60006106dd82610467565b6106e781856106c7565b93506106f7818560208601610483565b80840191505092915050565b600061070f82846106d2565b915081905092915050565b6107238161043f565b811461072e57600080fd5b50565b6000815190506107408161071a565b92915050565b600081519050610755816102ae565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610798826104ad565b810181811067ffffffffffffffff821117156107b7576107b6610760565b5b80604052505050565b60006107ca610286565b90506107d6828261078f565b919050565b600067ffffffffffffffff8211156107f6576107f5610760565b5b6107ff826104ad565b9050602081019050919050565b600061081f61081a846107db565b6107c0565b90508281526020810184848401111561083b5761083a61075b565b5b610846848285610483565b509392505050565b600082601f83011261086357610862610310565b5b815161087384826020860161080c565b91505092915050565b60008060006060848603121561089557610894610290565b5b60006108a386828701610731565b93505060206108b486828701610746565b925050604084015167ffffffffffffffff8111156108d5576108d4610295565b5b6108e18682870161084e565b9150509250925092565b600060c082019050610900600083018b610458565b61090d602083018a610612565b61091a6040830189610458565b6109276060830188610458565b818103608083015261093a818688610630565b905081810360a083015261094f818486610630565b9050999850505050505050505056fea2646970667358221220515f7933bf6da59fa92065c38d853b75e241eda832bbaccdf9a8ca357aa6167964736f6c63430008110033 \ No newline at end of file diff --git a/actors/evm/tests/contracts/CallActorPrecompile.hex b/actors/evm/tests/contracts/CallActorPrecompile.hex new file mode 100644 index 000000000..0384970a0 --- /dev/null +++ b/actors/evm/tests/contracts/CallActorPrecompile.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610994806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636aba510b1461003b5780637f18c2201461006e575b600080fd5b61005560048036038101906100509190610375565b6100a1565b60405161006594939291906104f7565b60405180910390f35b61008860048036038101906100839190610543565b610192565b60405161009894939291906104f7565b60405180910390f35b6000806000606060008073fe0000000000000000000000000000000000000573ffffffffffffffffffffffffffffffffffffffff168d8d8d8d8d8d8d6040516020016100f3979695949392919061065d565b60405160208183030381529060405260405161010f9190610703565b600060405180830381855af49150503d806000811461014a576040519150601f19603f3d011682016040523d82523d6000602084013e61014f565b606091505b509150915060008060008380602001905181019061016d919061087c565b9250925092508483838398509850985098505050505050975097509750979350505050565b6000806000606060008073fe0000000000000000000000000000000000000373ffffffffffffffffffffffffffffffffffffffff168e8e8e8e8e8e8e8e6040516020016101e69897969594939291906108eb565b6040516020818303038152906040526040516102029190610703565b600060405180830381855af49150503d806000811461023d576040519150601f19603f3d011682016040523d82523d6000602084013e610242565b606091505b5091509150600080600083806020019051810190610260919061087c565b925092509250848383839850985098509850505050505098509850985098945050505050565b6000604051905090565b600080fd5b600080fd5b600067ffffffffffffffff82169050919050565b6102b78161029a565b81146102c257600080fd5b50565b6000813590506102d4816102ae565b92915050565b6000819050919050565b6102ed816102da565b81146102f857600080fd5b50565b60008135905061030a816102e4565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261033557610334610310565b5b8235905067ffffffffffffffff81111561035257610351610315565b5b60208301915083600182028301111561036e5761036d61031a565b5b9250929050565b600080600080600080600060c0888a03121561039457610393610290565b5b60006103a28a828b016102c5565b97505060206103b38a828b016102fb565b96505060406103c48a828b016102c5565b95505060606103d58a828b016102c5565b945050608088013567ffffffffffffffff8111156103f6576103f5610295565b5b6104028a828b0161031f565b935093505060a06104158a828b016102c5565b91505092959891949750929550565b60008115159050919050565b61043981610424565b82525050565b6000819050919050565b6104528161043f565b82525050565b6104618161029a565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b838110156104a1578082015181840152602081019050610486565b60008484015250505050565b6000601f19601f8301169050919050565b60006104c982610467565b6104d38185610472565b93506104e3818560208601610483565b6104ec816104ad565b840191505092915050565b600060808201905061050c6000830187610430565b6105196020830186610449565b6105266040830185610458565b818103606083015261053881846104be565b905095945050505050565b60008060008060008060008060c0898b03121561056357610562610290565b5b60006105718b828c016102c5565b98505060206105828b828c016102fb565b97505060406105938b828c016102c5565b96505060606105a48b828c016102c5565b955050608089013567ffffffffffffffff8111156105c5576105c4610295565b5b6105d18b828c0161031f565b945094505060a089013567ffffffffffffffff8111156105f4576105f3610295565b5b6106008b828c0161031f565b92509250509295985092959890939650565b61061b816102da565b82525050565b82818337600083830152505050565b600061063c8385610472565b9350610649838584610621565b610652836104ad565b840190509392505050565b600060c082019050610672600083018a610458565b61067f6020830189610612565b61068c6040830188610458565b6106996060830187610458565b81810360808301526106ac818587610630565b90506106bb60a0830184610458565b98975050505050505050565b600081905092915050565b60006106dd82610467565b6106e781856106c7565b93506106f7818560208601610483565b80840191505092915050565b600061070f82846106d2565b915081905092915050565b6107238161043f565b811461072e57600080fd5b50565b6000815190506107408161071a565b92915050565b600081519050610755816102ae565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610798826104ad565b810181811067ffffffffffffffff821117156107b7576107b6610760565b5b80604052505050565b60006107ca610286565b90506107d6828261078f565b919050565b600067ffffffffffffffff8211156107f6576107f5610760565b5b6107ff826104ad565b9050602081019050919050565b600061081f61081a846107db565b6107c0565b90508281526020810184848401111561083b5761083a61075b565b5b610846848285610483565b509392505050565b600082601f83011261086357610862610310565b5b815161087384826020860161080c565b91505092915050565b60008060006060848603121561089557610894610290565b5b60006108a386828701610731565b93505060206108b486828701610746565b925050604084015167ffffffffffffffff8111156108d5576108d4610295565b5b6108e18682870161084e565b9150509250925092565b600060c082019050610900600083018b610458565b61090d602083018a610612565b61091a6040830189610458565b6109276060830188610458565b818103608083015261093a818688610630565b905081810360a083015261094f818486610630565b9050999850505050505050505056fea2646970667358221220515f7933bf6da59fa92065c38d853b75e241eda832bbaccdf9a8ca357aa6167964736f6c63430008110033 \ No newline at end of file diff --git a/actors/evm/tests/contracts/CallActorPrecompile.signatures b/actors/evm/tests/contracts/CallActorPrecompile.signatures new file mode 100644 index 000000000..3a5271ecf --- /dev/null +++ b/actors/evm/tests/contracts/CallActorPrecompile.signatures @@ -0,0 +1,3 @@ +Function signatures: +7f18c220: call_actor_address(uint64,uint256,uint64,uint64,bytes,bytes) +6aba510b: call_actor_id(uint64,uint256,uint64,uint64,bytes,uint64) diff --git a/actors/evm/tests/contracts/CallActorPrecompile.sol b/actors/evm/tests/contracts/CallActorPrecompile.sol new file mode 100644 index 000000000..a10f604b0 --- /dev/null +++ b/actors/evm/tests/contracts/CallActorPrecompile.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 MIT +pragma solidity >=0.4.25 <=0.8.17; + +contract CallActorPrecompile { + address constant CALL_ACTOR_ADDRESS = 0xfe00000000000000000000000000000000000003; + address constant CALL_ACTOR_ID = 0xfe00000000000000000000000000000000000005; + + function call_actor_id(uint64 method, uint256 value, uint64 flags, uint64 codec, bytes calldata params, uint64 id) public returns (bool, int256, uint64, bytes memory) { + (bool success, bytes memory data) = address(CALL_ACTOR_ID).delegatecall(abi.encode(method, value, flags, codec, params, id)); + (int256 exit, uint64 return_codec, bytes memory return_value) = abi.decode(data, (int256, uint64, bytes)); + return (success, exit, return_codec, return_value); + } + + function call_actor_address(uint64 method, uint256 value, uint64 flags, uint64 codec, bytes calldata params, bytes calldata filAddress) public returns (bool, int256, uint64, bytes memory) { + (bool success, bytes memory data) = address(CALL_ACTOR_ADDRESS).delegatecall(abi.encode(method, value, flags, codec, params, filAddress)); + (int256 exit, uint64 return_codec, bytes memory return_value) = abi.decode(data, (int256, uint64, bytes)); + return (success, exit, return_codec, return_value); + } +} diff --git a/actors/evm/tests/contracts/CallActorPrecompile_storage.json b/actors/evm/tests/contracts/CallActorPrecompile_storage.json new file mode 100644 index 000000000..325d0043f --- /dev/null +++ b/actors/evm/tests/contracts/CallActorPrecompile_storage.json @@ -0,0 +1 @@ +{"storage":[]} \ No newline at end of file