tests that use create2 and destroy to validate evm state
This commit is contained in:
parent
9060c474da
commit
c6bd9bc9e0
1
itests/contracts/Create2Factory.hex
Normal file
1
itests/contracts/Create2Factory.hex
Normal file
File diff suppressed because one or more lines are too long
67
itests/contracts/Create2Factory.sol
Normal file
67
itests/contracts/Create2Factory.sol
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.17;
|
||||||
|
contract Create2Factory {
|
||||||
|
|
||||||
|
bytes32 savedSalt;
|
||||||
|
|
||||||
|
// Returns the address of the newly deployed contract
|
||||||
|
function deploy(
|
||||||
|
bytes32 _salt
|
||||||
|
) public returns (address) {
|
||||||
|
// This syntax is a newer way to invoke create2 without assembly, you just need to pass salt
|
||||||
|
// https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2
|
||||||
|
savedSalt = _salt;
|
||||||
|
(bool success, address ret) = deployDelegateCall(_salt);
|
||||||
|
require(success);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deployDelegateCall(
|
||||||
|
bytes32 _salt
|
||||||
|
) public returns (bool, address) {
|
||||||
|
bytes memory data = abi.encodeWithSignature("_deploy(bytes32)", _salt);
|
||||||
|
(bool success, bytes memory returnedData) = address(this).delegatecall(data);
|
||||||
|
if(success){
|
||||||
|
(address ret) = abi.decode(returnedData, (address));
|
||||||
|
return (success, ret);
|
||||||
|
}else{
|
||||||
|
return (success, address(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _deploy(bytes32 _salt) public returns (address) {
|
||||||
|
// https://solidity-by-example.org/app/create1/
|
||||||
|
// This syntax is a newer way to invoke create2 without assembly, you just need to pass salt
|
||||||
|
// https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2
|
||||||
|
return address(new SelfDestruct{salt: _salt}(_salt));
|
||||||
|
}
|
||||||
|
|
||||||
|
function test(address _address) public returns (address){
|
||||||
|
|
||||||
|
// run destroy() on _address
|
||||||
|
SelfDestruct selfDestruct = SelfDestruct(_address);
|
||||||
|
selfDestruct.destroy();
|
||||||
|
|
||||||
|
//verify data can still be accessed
|
||||||
|
address ret = selfDestruct.sender();
|
||||||
|
|
||||||
|
// attempt and fail to deploy contract using salt
|
||||||
|
(bool success, ) = deployDelegateCall(selfDestruct.salt());
|
||||||
|
require(!success);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract SelfDestruct {
|
||||||
|
address public sender;
|
||||||
|
bytes32 public salt;
|
||||||
|
constructor(bytes32 _salt) {
|
||||||
|
sender = tx.origin;
|
||||||
|
salt=_salt;
|
||||||
|
}
|
||||||
|
function destroy() public {
|
||||||
|
selfdestruct(payable(msg.sender));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2
itests/contracts/compile.sh
Executable file → Normal file
2
itests/contracts/compile.sh
Executable file → Normal file
@ -12,7 +12,7 @@ find . -name \*.sol -print0 |
|
|||||||
|
|
||||||
#for these contracts we have 2 contracts in the same solidity file
|
#for these contracts we have 2 contracts in the same solidity file
|
||||||
#this command grabs the correct bytecode for us
|
#this command grabs the correct bytecode for us
|
||||||
for filename in Constructor TestApp ValueSender ; do
|
for filename in Constructor TestApp ValueSender Create2Factory; do
|
||||||
echo $filename
|
echo $filename
|
||||||
solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex
|
solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex
|
||||||
done
|
done
|
||||||
|
@ -3,6 +3,7 @@ package itests
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -606,3 +607,58 @@ func TestFEVMRecursiveActorCall(t *testing.T) {
|
|||||||
t.Run("n=0,r=255-fails", testN(0, 255, exitcode.ExitCode(33))) // 33 means transaction reverted
|
t.Run("n=0,r=255-fails", testN(0, 255, exitcode.ExitCode(33))) // 33 means transaction reverted
|
||||||
t.Run("n=251,r=171-fails", testN(251, 171, exitcode.ExitCode(33)))
|
t.Run("n=251,r=171-fails", testN(251, 171, exitcode.ExitCode(33)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFEVMDestroyCreate2(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//deploy create2 factory contract
|
||||||
|
filename := "contracts/Create2Factory.hex"
|
||||||
|
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
||||||
|
|
||||||
|
//construct salt for create2
|
||||||
|
salt := make([]byte, 32)
|
||||||
|
_, err := rand.Read(salt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
//deploy contract using create2 factory
|
||||||
|
selfDestructAddress, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "deploy(bytes32)", salt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
//convert to filecoin actor address so we can call InvokeContractByFuncName
|
||||||
|
ea, err := ethtypes.CastEthAddress(selfDestructAddress[12:])
|
||||||
|
require.NoError(t, err)
|
||||||
|
selfDestructAddressActor, err := ea.ToFilecoinAddress()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
//read sender property from contract
|
||||||
|
ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, selfDestructAddressActor, "sender()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
//assert contract has correct data
|
||||||
|
ethFromAddr := inputDataFromFrom(ctx, t, client, fromAddr)
|
||||||
|
require.Equal(t, ethFromAddr, ret)
|
||||||
|
|
||||||
|
//run test() which 1.calls sefldestruct 2. verifies sender() is the correct value 3. attempts and fails to deploy via create2
|
||||||
|
testSenderAddress, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "test(address)", selfDestructAddress)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, testSenderAddress, ethFromAddr)
|
||||||
|
|
||||||
|
//read sender() but get response of 0x0 because of self destruct
|
||||||
|
senderAfterDestroy, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, selfDestructAddressActor, "sender()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []byte{}, senderAfterDestroy)
|
||||||
|
|
||||||
|
// deploy new contract at same address usign same salt
|
||||||
|
newAddressSelfDestruct, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "deploy(bytes32)", salt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, newAddressSelfDestruct, selfDestructAddress)
|
||||||
|
|
||||||
|
//verify sender() property is correct
|
||||||
|
senderSecondCall, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, selfDestructAddressActor, "sender()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
//assert contract has correct data
|
||||||
|
require.Equal(t, ethFromAddr, senderSecondCall)
|
||||||
|
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user