From b6a11ac700716416e33b6e2c012793e6e1a2e596 Mon Sep 17 00:00:00 2001 From: Michael de Hoog Date: Fri, 13 Dec 2024 08:52:11 -1000 Subject: [PATCH] Add permissioned create --- core/vm/can_create.go | 31 +++++++++++++++++++++++++++++++ core/vm/can_create_test.go | 1 + core/vm/evm.go | 3 +++ 3 files changed, 35 insertions(+) create mode 100644 core/vm/can_create.go create mode 100644 core/vm/can_create_test.go diff --git a/core/vm/can_create.go b/core/vm/can_create.go new file mode 100644 index 0000000000..b4a361f342 --- /dev/null +++ b/core/vm/can_create.go @@ -0,0 +1,31 @@ +package vm + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" +) + +const canCreateGasLimit = uint64(1000000) + +// `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)` +var proxyImplementationSlot = common.HexToHash("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc") + +// Predeploy address (may or may not have an implementation behind it) +var letPredeploy = common.HexToAddress("0x42000000000000000000000000000000000001e7") + +// 4-byte signature of `canCreate(address contractCaller)` + 12-byte padding +var canCreatePrefix = common.FromHex("0x7804a5dc000000000000000000000000") + +func CanCreate(evm *EVM, caller ContractRef) error { + implementation := evm.StateDB.GetState(letPredeploy, proxyImplementationSlot) + if implementation == (common.Hash{}) { + return nil + } + var contractCaller common.Address + if contract, ok := caller.(*Contract); ok { + contractCaller = contract.Caller() + } + data := append(canCreatePrefix, contractCaller[:]...) + _, _, err := evm.Call(caller, letPredeploy, data, canCreateGasLimit, new(uint256.Int)) + return err +} diff --git a/core/vm/can_create_test.go b/core/vm/can_create_test.go new file mode 100644 index 0000000000..830a8f69d9 --- /dev/null +++ b/core/vm/can_create_test.go @@ -0,0 +1 @@ +package vm diff --git a/core/vm/evm.go b/core/vm/evm.go index 1945a3b4db..1fb0ca472e 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -459,6 +459,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, common.Address{}, gas, ErrInsufficientBalance } + if err := CanCreate(evm, caller); err != nil { + return nil, common.Address{}, gas, err + } nonce := evm.StateDB.GetNonce(caller.Address()) if nonce+1 < nonce { return nil, common.Address{}, gas, ErrNonceUintOverflow