Merge pull request #10163 from filecoin-project/mikers/create2test2

tests: itests: test create2 and destroy
This commit is contained in:
Łukasz Magiera 2023-02-09 18:33:54 +01:00 committed by GitHub
commit 4f5fea848c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 1 deletions

File diff suppressed because one or more lines are too long

View 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
View File

@ -12,7 +12,7 @@ find . -name \*.sol -print0 |
#for these contracts we have 2 contracts in the same solidity file
#this command grabs the correct bytecode for us
for filename in Constructor TestApp ValueSender DeployValueTest; do
for filename in Constructor TestApp ValueSender Create2Factory DeployValueTest; do
echo $filename
solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex
done

View File

@ -3,6 +3,7 @@ package itests
import (
"bytes"
"context"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"fmt"
@ -730,3 +731,58 @@ func TestFEVMDeployWithValue(t *testing.T) {
//require balance of NewContract is testValue
require.Equal(t, testValue.Uint64(), contractBalance)
}
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)
}