@@ -577,6 +577,190 @@ func TestEVMRun(t *testing.T) {
577577 },
578578 )
579579 })
580+
581+ t .Run ("testing EVM.run failed with gas limit validation error" , func (t * testing.T ) {
582+ t .Parallel ()
583+
584+ RunWithNewEnvironment (t ,
585+ chain , func (
586+ ctx fvm.Context ,
587+ vm fvm.VM ,
588+ snapshot snapshot.SnapshotTree ,
589+ testContract * TestContract ,
590+ testAccount * EOATestAccount ,
591+ ) {
592+ sc := systemcontracts .SystemContractsForChain (chain .ChainID ())
593+ code := []byte (fmt .Sprintf (
594+ `
595+ import EVM from %s
596+ transaction(tx: [UInt8], coinbaseBytes: [UInt8; 20]){
597+ prepare(account: &Account) {
598+ let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
599+ let res = EVM.run(tx: tx, coinbase: coinbase)
600+ assert(res.status == EVM.Status.invalid, message: "unexpected status")
601+ assert(res.errorCode == 100, message: "unexpected error code: \(res.errorCode)")
602+ assert(res.errorMessage == "transaction gas limit too high (cap: 16777216, tx: 16777220)")
603+ }
604+ }
605+ ` ,
606+ sc .EVMContract .Address .HexWithPrefix (),
607+ ))
608+
609+ coinbaseAddr := types.Address {1 , 2 , 3 }
610+ coinbaseBalance := getEVMAccountBalance (t , ctx , vm , snapshot , coinbaseAddr )
611+ require .Zero (t , types .BalanceToBigInt (coinbaseBalance ).Uint64 ())
612+
613+ num := int64 (12 )
614+ innerTxBytes := testAccount .PrepareSignAndEncodeTx (t ,
615+ testContract .DeployedAt .ToCommon (),
616+ testContract .MakeCallData (t , "store" , big .NewInt (num )),
617+ big .NewInt (0 ),
618+ uint64 (16_777_220 ), // max is 16,777,216
619+ big .NewInt (1 ),
620+ )
621+
622+ innerTx := cadence .NewArray (
623+ unittest .BytesToCdcUInt8 (innerTxBytes ),
624+ ).WithType (stdlib .EVMTransactionBytesCadenceType )
625+
626+ coinbase := cadence .NewArray (
627+ unittest .BytesToCdcUInt8 (coinbaseAddr .Bytes ()),
628+ ).WithType (stdlib .EVMAddressBytesCadenceType )
629+
630+ txBody , err := flow .NewTransactionBodyBuilder ().
631+ SetScript (code ).
632+ SetPayer (sc .FlowServiceAccount .Address ).
633+ AddAuthorizer (sc .FlowServiceAccount .Address ).
634+ AddArgument (json .MustEncode (innerTx )).
635+ AddArgument (json .MustEncode (coinbase )).
636+ Build ()
637+ require .NoError (t , err )
638+
639+ tx := fvm .Transaction (txBody , 0 )
640+
641+ state , output , err := vm .Run (
642+ ctx ,
643+ tx ,
644+ snapshot ,
645+ )
646+ require .NoError (t , err )
647+ require .NoError (t , output .Err )
648+ require .NotEmpty (t , state .WriteSet )
649+
650+ // assert no events were produced from an invalid EVM transaction
651+ require .Len (t , output .Events , 0 )
652+ })
653+ })
654+
655+ t .Run ("testing EVM.run with max gas limit cap" , func (t * testing.T ) {
656+ t .Parallel ()
657+
658+ RunWithNewEnvironment (t ,
659+ chain , func (
660+ ctx fvm.Context ,
661+ vm fvm.VM ,
662+ snapshot snapshot.SnapshotTree ,
663+ testContract * TestContract ,
664+ testAccount * EOATestAccount ,
665+ ) {
666+ sc := systemcontracts .SystemContractsForChain (chain .ChainID ())
667+ code := []byte (fmt .Sprintf (
668+ `
669+ import EVM from %s
670+ transaction(tx: [UInt8], coinbaseBytes: [UInt8; 20]){
671+ prepare(account: &Account) {
672+ let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
673+ let res = EVM.run(tx: tx, coinbase: coinbase)
674+ assert(res.status == EVM.Status.successful, message: "unexpected status")
675+ assert(res.errorCode == 0, message: "unexpected error code: \(res.errorCode)")
676+ }
677+ }
678+ ` ,
679+ sc .EVMContract .Address .HexWithPrefix (),
680+ ))
681+
682+ coinbaseAddr := types.Address {1 , 2 , 3 }
683+ coinbaseBalance := getEVMAccountBalance (t , ctx , vm , snapshot , coinbaseAddr )
684+ require .Zero (t , types .BalanceToBigInt (coinbaseBalance ).Uint64 ())
685+
686+ num := int64 (12 )
687+ innerTxBytes := testAccount .PrepareSignAndEncodeTx (t ,
688+ testContract .DeployedAt .ToCommon (),
689+ testContract .MakeCallData (t , "store" , big .NewInt (num )),
690+ big .NewInt (0 ),
691+ uint64 (16_777_216 ),
692+ big .NewInt (1 ),
693+ )
694+
695+ innerTx := cadence .NewArray (
696+ unittest .BytesToCdcUInt8 (innerTxBytes ),
697+ ).WithType (stdlib .EVMTransactionBytesCadenceType )
698+
699+ coinbase := cadence .NewArray (
700+ unittest .BytesToCdcUInt8 (coinbaseAddr .Bytes ()),
701+ ).WithType (stdlib .EVMAddressBytesCadenceType )
702+
703+ txBody , err := flow .NewTransactionBodyBuilder ().
704+ SetScript (code ).
705+ SetPayer (sc .FlowServiceAccount .Address ).
706+ AddAuthorizer (sc .FlowServiceAccount .Address ).
707+ AddArgument (json .MustEncode (innerTx )).
708+ AddArgument (json .MustEncode (coinbase )).
709+ Build ()
710+ require .NoError (t , err )
711+
712+ tx := fvm .Transaction (txBody , 0 )
713+
714+ state , output , err := vm .Run (
715+ ctx ,
716+ tx ,
717+ snapshot ,
718+ )
719+ require .NoError (t , err )
720+ require .NoError (t , output .Err )
721+ require .NotEmpty (t , state .WriteSet )
722+ snapshot = snapshot .Append (state )
723+
724+ // assert event fields are correct
725+ require .Len (t , output .Events , 2 )
726+ txEvent := output .Events [0 ]
727+ txEventPayload := TxEventToPayload (t , txEvent , sc .EVMContract .Address )
728+ require .NoError (t , err )
729+
730+ // fee transfer event
731+ feeTransferEvent := output .Events [1 ]
732+ feeTranferEventPayload := TxEventToPayload (t , feeTransferEvent , sc .EVMContract .Address )
733+ require .NoError (t , err )
734+ require .Equal (t , uint16 (types .ErrCodeNoError ), feeTranferEventPayload .ErrorCode )
735+ require .Equal (t , uint16 (1 ), feeTranferEventPayload .Index )
736+ require .Equal (t , uint64 (21000 ), feeTranferEventPayload .GasConsumed )
737+
738+ // commit block
739+ blockEventPayload , _ := callEVMHeartBeat (t ,
740+ ctx ,
741+ vm ,
742+ snapshot ,
743+ )
744+
745+ require .NotEmpty (t , blockEventPayload .Hash )
746+ require .Equal (t , uint64 (64785 ), blockEventPayload .TotalGasUsed )
747+ require .NotEmpty (t , blockEventPayload .Hash )
748+
749+ txHashes := types.TransactionHashes {txEventPayload .Hash , feeTranferEventPayload .Hash }
750+ require .Equal (t ,
751+ txHashes .RootHash (),
752+ blockEventPayload .TransactionHashRoot ,
753+ )
754+ require .NotEmpty (t , blockEventPayload .ReceiptRoot )
755+
756+ require .Equal (t , innerTxBytes , txEventPayload .Payload )
757+ require .Equal (t , uint16 (types .ErrCodeNoError ), txEventPayload .ErrorCode )
758+ require .Equal (t , uint16 (0 ), txEventPayload .Index )
759+ require .Equal (t , blockEventPayload .Height , txEventPayload .BlockHeight )
760+ require .Equal (t , blockEventPayload .TotalGasUsed - feeTranferEventPayload .GasConsumed , txEventPayload .GasConsumed )
761+ require .Empty (t , txEventPayload .ContractAddress )
762+ })
763+ })
580764}
581765
582766func TestEVMBatchRun (t * testing.T ) {
0 commit comments