Skip to content

Commit

Permalink
Create protected storage on the CREATE2 opcode
Browse files Browse the repository at this point in the history
Create the protected storage contract on the CREATE2 opcode. Add the
create2.sol example that shows CREATE2 contract creation. Also, show
that recreating a contract via CREATE2(including its associated
protected storage) works and the address is the same deterministic one.

For more information, please see:
https://docs.soliditylang.org/en/v0.8.17/control-structures.html?highlight=create2#salted-contract-creations-create2
  • Loading branch information
dartdart26 committed Dec 6, 2022
1 parent cebcc47 commit daea23d
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 4 deletions.
18 changes: 15 additions & 3 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,9 +518,21 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
codeAndHash := &codeAndHash{code: code}
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
actualCodeAndHash := &codeAndHash{code: code}

// Create the actual contract.
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), actualCodeAndHash.Hash().Bytes())

ret, contractAddr, leftOverGas, err = evm.create(caller, actualCodeAndHash, gas, endowment, contractAddr, CREATE2)
if err != nil {
return
}

// Create a separate contract that would be used for protected storage.
// Return the actual contract's return value and contract address.
protectedStorageContractAddr := crypto.CreateProtectedStorageContractAddress(contractAddr)
_, _, leftOverGas, err = evm.create(caller, &codeAndHash{}, gas, endowment, protectedStorageContractAddr, CREATE2)
return
}

// ChainConfig returns the environment's chain configuration
Expand Down
50 changes: 50 additions & 0 deletions tests/solidity/zama/create2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear

pragma solidity >=0.7.0 <0.9.0;

contract Contract {
uint256 public value;

constructor(uint256 v) {
value = v;
}

function get() public view returns (uint256) {
return value;
}

function destruct() public {
selfdestruct(payable(tx.origin));
}
}

// Salt: 0x0102abcdef0102abcdef0102abcdef0102abcdef0102abcdef0102abcdefaaaa

// Creates a member contract via the CREATE2 opcode.
contract Factory {
Contract public c;
bytes32 public original_salt;
uint256 public original_value;
address public original_address;

constructor(bytes32 salt, uint256 value) {
c = new Contract{salt: salt}(value);
original_salt = salt;
original_value = value;
original_address = address(c);
}

function get() public view returns (uint256) {
return c.get();
}

function destruct() public {
c.destruct();
}

// After `destruct()` is called, `recreate()` must succeed and `c` must have the same address as before.
function recreate() public {
c = new Contract{salt: original_salt}(original_value);
require(original_address == address(c));
}
}
2 changes: 1 addition & 1 deletion tests/solidity/zama/handles.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-3.0
// SPDX-License-Identifier: BSD-3-Clause-Clear

pragma solidity >=0.7.0 <0.9.0;

Expand Down

0 comments on commit daea23d

Please sign in to comment.