@@ -12,6 +12,7 @@ import (
1212
1313 "github.com/ethereum/go-ethereum/common"
1414 "github.com/ethereum/go-ethereum/core/vm"
15+ "github.com/ethereum/go-ethereum/crypto"
1516 "github.com/ethereum/go-ethereum/libevm"
1617 "github.com/ethereum/go-ethereum/libevm/ethtest"
1718 "github.com/ethereum/go-ethereum/libevm/hookstest"
@@ -289,3 +290,65 @@ func contractCode(ops []vm.OpCode) []byte {
289290 }
290291 return ret
291292}
293+
294+ func TestCanCreateContract (t * testing.T ) {
295+ rng := ethtest .NewPseudoRand (142857 )
296+ account := rng .Address ()
297+ slot := rng .Hash ()
298+
299+ const gasLimit uint64 = 1e6
300+ gasUsage := rng .Uint64n (gasLimit )
301+
302+ makeErr := func (cc * libevm.AddressContext , stateVal common.Hash ) error {
303+ return fmt .Errorf ("Origin: %v Caller: %v Contract: %v State: %v" , cc .Origin , cc .Caller , cc .Self , stateVal )
304+ }
305+ hooks := & hookstest.Stub {
306+ CanCreateContractFn : func (cc * libevm.AddressContext , gas uint64 , s libevm.StateReader ) (uint64 , error ) {
307+ return gas - gasUsage , makeErr (cc , s .GetState (account , slot ))
308+ },
309+ }
310+ hooks .Register (t )
311+
312+ origin := rng .Address ()
313+ caller := rng .Address ()
314+ value := rng .Hash ()
315+ code := []byte {byte (vm .STOP )}
316+ salt := rng .Hash ()
317+
318+ create := crypto .CreateAddress (caller , 0 )
319+ create2 := crypto .CreateAddress2 (caller , salt , crypto .Keccak256 (code ))
320+
321+ tests := []struct {
322+ name string
323+ create func (* vm.EVM ) ([]byte , common.Address , uint64 , error )
324+ wantErr error
325+ }{
326+ {
327+ name : "Create" ,
328+ create : func (evm * vm.EVM ) ([]byte , common.Address , uint64 , error ) {
329+ return evm .Create (vm .AccountRef (caller ), code , gasLimit , uint256 .NewInt (0 ))
330+ },
331+ wantErr : makeErr (& libevm.AddressContext {Origin : origin , Caller : caller , Self : create }, value ),
332+ },
333+ {
334+ name : "Create2" ,
335+ create : func (evm * vm.EVM ) ([]byte , common.Address , uint64 , error ) {
336+ return evm .Create2 (vm .AccountRef (caller ), code , gasLimit , uint256 .NewInt (0 ), new (uint256.Int ).SetBytes (salt [:]))
337+ },
338+ wantErr : makeErr (& libevm.AddressContext {Origin : origin , Caller : caller , Self : create2 }, value ),
339+ },
340+ }
341+
342+ for _ , tt := range tests {
343+ t .Run (tt .name , func (t * testing.T ) {
344+ state , evm := ethtest .NewZeroEVM (t )
345+ state .SetState (account , slot , value )
346+ evm .TxContext .Origin = origin
347+
348+ _ , _ , gasRemaining , err := tt .create (evm )
349+ require .EqualError (t , err , tt .wantErr .Error ())
350+ // require prints uint64s in hex
351+ require .Equal (t , int (gasLimit - gasUsage ), int (gasRemaining ), "gas remaining" )
352+ })
353+ }
354+ }
0 commit comments