Skip to content

Commit 158888c

Browse files
committed
feat!: RulesHooks.CanCreateContract() accepts and returns gas
1 parent 4e385e6 commit 158888c

File tree

5 files changed

+25
-18
lines changed

5 files changed

+25
-18
lines changed

core/vm/evm.libevm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func (evm *EVM) canCreateContract(
1414
) ([]byte, common.Address, uint64, error) {
1515
if err == nil && address != (common.Address{}) { // NOTE `err ==` not !=
1616
addrs := &libevm.AddressContext{Origin: evm.Origin, Caller: caller.Address(), Self: address}
17-
err = evm.chainRules.Hooks().CanCreateContract(addrs, evm.StateDB)
17+
gas, err = evm.chainRules.Hooks().CanCreateContract(addrs, gas, evm.StateDB)
1818
}
1919
return deployedCode, address, gas, err
2020
}

core/vm/evm.libevm_test.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,23 @@ func TestCanCreateContract(t *testing.T) {
1919
account := rng.Address()
2020
slot := rng.Hash()
2121

22+
const gasLimit uint64 = 1e6
23+
gasUsage := rng.Uint64n(gasLimit)
24+
2225
makeErr := func(cc *libevm.AddressContext, stateVal common.Hash) error {
2326
return fmt.Errorf("Origin: %v Caller: %v Contract: %v State: %v", cc.Origin, cc.Caller, cc.Self, stateVal)
2427
}
2528
hooks := &hookstest.Stub{
26-
CanCreateContractFn: func(cc *libevm.AddressContext, s libevm.StateReader) error {
27-
return makeErr(cc, s.GetState(account, slot))
29+
CanCreateContractFn: func(cc *libevm.AddressContext, gas uint64, s libevm.StateReader) (uint64, error) {
30+
return gas - gasUsage, makeErr(cc, s.GetState(account, slot))
2831
},
2932
}
3033
hooks.Register(t)
3134

3235
origin := rng.Address()
3336
caller := rng.Address()
3437
value := rng.Hash()
35-
code := rng.Bytes(8)
38+
code := []byte{byte(vm.STOP)}
3639
salt := rng.Hash()
3740

3841
create := crypto.CreateAddress(caller, 0)
@@ -46,14 +49,14 @@ func TestCanCreateContract(t *testing.T) {
4649
{
4750
name: "Create",
4851
create: func(evm *vm.EVM) ([]byte, common.Address, uint64, error) {
49-
return evm.Create(vm.AccountRef(caller), code, 1e6, uint256.NewInt(0))
52+
return evm.Create(vm.AccountRef(caller), code, gasLimit, uint256.NewInt(0))
5053
},
5154
wantErr: makeErr(&libevm.AddressContext{Origin: origin, Caller: caller, Self: create}, value),
5255
},
5356
{
5457
name: "Create2",
5558
create: func(evm *vm.EVM) ([]byte, common.Address, uint64, error) {
56-
return evm.Create2(vm.AccountRef(caller), code, 1e6, uint256.NewInt(0), new(uint256.Int).SetBytes(salt[:]))
59+
return evm.Create2(vm.AccountRef(caller), code, gasLimit, uint256.NewInt(0), new(uint256.Int).SetBytes(salt[:]))
5760
},
5861
wantErr: makeErr(&libevm.AddressContext{Origin: origin, Caller: caller, Self: create2}, value),
5962
},
@@ -65,8 +68,10 @@ func TestCanCreateContract(t *testing.T) {
6568
state.SetState(account, slot, value)
6669
evm.TxContext.Origin = origin
6770

68-
_, _, _, err := tt.create(evm)
71+
_, _, gasRemaining, err := tt.create(evm)
6972
require.EqualError(t, err, tt.wantErr.Error())
73+
// require prints uint64s in hex
74+
require.Equal(t, int(gasLimit-gasUsage), int(gasRemaining), "gas remaining")
7075
})
7176
}
7277
}

libevm/hookstest/stub.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func Register[C params.ChainConfigHooks, R params.RulesHooks](tb testing.TB, ext
2727
type Stub struct {
2828
PrecompileOverrides map[common.Address]libevm.PrecompiledContract
2929
CanExecuteTransactionFn func(common.Address, *common.Address, libevm.StateReader) error
30-
CanCreateContractFn func(*libevm.AddressContext, libevm.StateReader) error
30+
CanCreateContractFn func(*libevm.AddressContext, uint64, libevm.StateReader) (uint64, error)
3131
}
3232

3333
// Register is a convenience wrapper for registering s as both the
@@ -63,11 +63,11 @@ func (s Stub) CanExecuteTransaction(from common.Address, to *common.Address, sr
6363

6464
// CanCreateContract proxies arguments to the s.CanCreateContractFn function if
6565
// non-nil, otherwise it acts as a noop.
66-
func (s Stub) CanCreateContract(cc *libevm.AddressContext, sr libevm.StateReader) error {
66+
func (s Stub) CanCreateContract(cc *libevm.AddressContext, gas uint64, sr libevm.StateReader) (uint64, error) {
6767
if f := s.CanCreateContractFn; f != nil {
68-
return f(cc, sr)
68+
return f(cc, gas, sr)
6969
}
70-
return nil
70+
return gas, nil
7171
}
7272

7373
var _ interface {

params/example.libevm_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,12 @@ func (r RulesExtra) PrecompileOverride(addr common.Address) (_ libevm.Precompile
105105
// CanCreateContract implements the required [params.RuleHooks] method. Access
106106
// to state allows it to be configured on-chain however this is an optional
107107
// implementation detail.
108-
func (r RulesExtra) CanCreateContract(*libevm.AddressContext, libevm.StateReader) error {
108+
func (r RulesExtra) CanCreateContract(_ *libevm.AddressContext, gas uint64, _ libevm.StateReader) (uint64, error) {
109109
if time.Unix(int64(r.timestamp), 0).UTC().Day() != int(time.Tuesday) { //nolint:gosec // G115 timestamp won't overflow int64 for millions of years so this is someone else's problem
110-
return errors.New("uh oh")
110+
// Consumes all remaining gas.
111+
return 0, errors.New("uh oh")
111112
}
112-
return nil
113+
return gas, nil
113114
}
114115

115116
// This example demonstrates how the rest of this file would be used from a

params/hooks.libevm.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type RulesHooks interface {
3232
// RulesAllowlistHooks are a subset of [RulesHooks] that gate actions, signalled
3333
// by returning a nil (allowed) or non-nil (blocked) error.
3434
type RulesAllowlistHooks interface {
35-
CanCreateContract(*libevm.AddressContext, libevm.StateReader) error
35+
CanCreateContract(_ *libevm.AddressContext, gas uint64, _ libevm.StateReader) (gasRemaining uint64, _ error)
3636
CanExecuteTransaction(from common.Address, to *common.Address, _ libevm.StateReader) error
3737
}
3838

@@ -71,9 +71,10 @@ func (NOOPHooks) CanExecuteTransaction(_ common.Address, _ *common.Address, _ li
7171
return nil
7272
}
7373

74-
// CanCreateContract allows all (otherwise valid) contract deployment.
75-
func (NOOPHooks) CanCreateContract(*libevm.AddressContext, libevm.StateReader) error {
76-
return nil
74+
// CanCreateContract allows all (otherwise valid) contract deployment, not
75+
// consuming any more gas.
76+
func (NOOPHooks) CanCreateContract(_ *libevm.AddressContext, gas uint64, _ libevm.StateReader) (uint64, error) {
77+
return gas, nil
7778
}
7879

7980
// PrecompileOverride instructs the EVM interpreter to use the default

0 commit comments

Comments
 (0)