@@ -548,3 +548,238 @@ func TestEvmDoubleSpendNonceHandlingE2E(t *testing.T) {
548548 t .Logf (" - EVM correctly rejected duplicate nonce transaction" )
549549 t .Logf (" - System maintains transaction integrity and prevents double-spending" )
550550}
551+
552+ // TestEvmInvalidTransactionRejectionE2E tests the system's ability to properly reject
553+ // various types of invalid transactions and ensure they are not included in any blocks.
554+ //
555+ // Test Purpose:
556+ // - Confirm that invalid transactions are rejected and not included in blocks
557+ // - Test various types of invalid transactions (bad signature, insufficient funds, malformed data)
558+ // - Ensure system stability when processing invalid transactions
559+ // - Validate that valid transactions still work after invalid ones are rejected
560+ //
561+ // Test Flow:
562+ // 1. Sets up Local DA layer and EVM sequencer
563+ // 2. Submits various invalid transactions:
564+ // a. Transaction with invalid signature
565+ // b. Transaction with insufficient funds (from empty account)
566+ // c. Transaction with invalid nonce (too high)
567+ // d. Transaction with invalid gas limit (too low)
568+ // 3. Verifies that all invalid transactions are rejected
569+ // 4. Submits a valid transaction to confirm system stability
570+ // 5. Ensures the valid transaction is processed correctly
571+ //
572+ // Expected Behavior:
573+ // - All invalid transactions should be rejected at submission or processing
574+ // - No invalid transactions should appear in any blocks
575+ // - Valid transactions should continue to work normally
576+ // - System should remain stable and responsive after rejecting invalid transactions
577+ //
578+ // This test validates Rollkit's transaction validation and rejection mechanisms.
579+ func TestEvmInvalidTransactionRejectionE2E (t * testing.T ) {
580+ flag .Parse ()
581+ workDir := t .TempDir ()
582+ nodeHome := filepath .Join (workDir , "evm-agg" )
583+ sut := NewSystemUnderTest (t )
584+
585+ // 1. Start local DA
586+ localDABinary := "local-da"
587+ if evmSingleBinaryPath != "evm-single" {
588+ localDABinary = filepath .Join (filepath .Dir (evmSingleBinaryPath ), "local-da" )
589+ }
590+ sut .ExecCmd (localDABinary )
591+ t .Log ("Started local DA" )
592+ time .Sleep (200 * time .Millisecond )
593+
594+ // 2. Start EVM (Reth) via Docker Compose
595+ jwtSecret := setupTestRethEngineE2E (t )
596+
597+ // 3. Get genesis hash from EVM node
598+ genesisHash := evm .GetGenesisHash (t )
599+ t .Logf ("Genesis hash: %s" , genesisHash )
600+
601+ // 4. Initialize sequencer node
602+ output , err := sut .RunCmd (evmSingleBinaryPath ,
603+ "init" ,
604+ "--rollkit.node.aggregator=true" ,
605+ "--rollkit.signer.passphrase" , "secret" ,
606+ "--home" , nodeHome ,
607+ )
608+ require .NoError (t , err , "failed to init sequencer" , output )
609+ t .Log ("Initialized sequencer node" )
610+
611+ // 5. Start sequencer node
612+ sut .ExecCmd (evmSingleBinaryPath ,
613+ "start" ,
614+ "--evm.jwt-secret" , jwtSecret ,
615+ "--evm.genesis-hash" , genesisHash ,
616+ "--rollkit.node.block_time" , "1s" ,
617+ "--rollkit.node.aggregator=true" ,
618+ "--rollkit.signer.passphrase" , "secret" ,
619+ "--home" , nodeHome ,
620+ "--rollkit.da.address" , "http://localhost:7980" ,
621+ "--rollkit.da.block_time" , "1m" ,
622+ )
623+ sut .AwaitNodeUp (t , "http://127.0.0.1:7331" , 10 * time .Second )
624+ t .Log ("Sequencer node is up" )
625+
626+ // 6. Connect to EVM
627+ client , err := ethclient .Dial ("http://localhost:8545" )
628+ require .NoError (t , err , "Should be able to connect to EVM" )
629+ defer client .Close ()
630+
631+ ctx := context .Background ()
632+ var invalidTxHashes []common.Hash
633+ var invalidTxErrors []string
634+
635+ t .Log ("Testing various invalid transaction types..." )
636+
637+ // 7a. Test invalid signature transaction
638+ t .Log ("7a. Testing transaction with invalid signature..." )
639+ func () {
640+ defer func () {
641+ if r := recover (); r != nil {
642+ invalidTxErrors = append (invalidTxErrors , fmt .Sprintf ("Invalid signature tx: %v" , r ))
643+ t .Logf ("✅ Invalid signature transaction rejected as expected: %v" , r )
644+ }
645+ }()
646+
647+ // Try to submit with a bad signature by creating a transaction with wrong private key
648+ badPrivKey := "1111111111111111111111111111111111111111111111111111111111111111"
649+ lastNonce := uint64 (0 )
650+ badTx := evm .GetRandomTransaction (t , badPrivKey , "0x944fDcD1c868E3cC566C78023CcB38A32cDA836E" , "1234" , 22000 , & lastNonce )
651+
652+ err := client .SendTransaction (ctx , badTx )
653+ if err != nil {
654+ invalidTxErrors = append (invalidTxErrors , fmt .Sprintf ("Invalid signature tx: %v" , err ))
655+ t .Logf ("✅ Invalid signature transaction rejected as expected: %v" , err )
656+ } else {
657+ invalidTxHashes = append (invalidTxHashes , badTx .Hash ())
658+ t .Logf ("⚠️ Invalid signature transaction was submitted: %s" , badTx .Hash ().Hex ())
659+ }
660+ }()
661+
662+ // 7b. Test insufficient funds transaction
663+ t .Log ("7b. Testing transaction with insufficient funds..." )
664+ func () {
665+ defer func () {
666+ if r := recover (); r != nil {
667+ invalidTxErrors = append (invalidTxErrors , fmt .Sprintf ("Insufficient funds tx: %v" , r ))
668+ t .Logf ("✅ Insufficient funds transaction rejected as expected: %v" , r )
669+ }
670+ }()
671+
672+ // Use an empty account that has no funds
673+ emptyAccountPrivKey := "2222222222222222222222222222222222222222222222222222222222222222"
674+ lastNonce := uint64 (0 )
675+ tx := evm .GetRandomTransaction (t , emptyAccountPrivKey , "0x944fDcD1c868E3cC566C78023CcB38A32cDA836E" , "1234" , 22000 , & lastNonce )
676+
677+ err := client .SendTransaction (ctx , tx )
678+ if err != nil {
679+ invalidTxErrors = append (invalidTxErrors , fmt .Sprintf ("Insufficient funds tx: %v" , err ))
680+ t .Logf ("✅ Insufficient funds transaction rejected as expected: %v" , err )
681+ } else {
682+ invalidTxHashes = append (invalidTxHashes , tx .Hash ())
683+ t .Logf ("⚠️ Insufficient funds transaction was submitted: %s" , tx .Hash ().Hex ())
684+ }
685+ }()
686+
687+ // 7c. Test invalid nonce transaction (way too high)
688+ t .Log ("7c. Testing transaction with invalid nonce..." )
689+ func () {
690+ defer func () {
691+ if r := recover (); r != nil {
692+ invalidTxErrors = append (invalidTxErrors , fmt .Sprintf ("Invalid nonce tx: %v" , r ))
693+ t .Logf ("✅ Invalid nonce transaction rejected as expected: %v" , r )
694+ }
695+ }()
696+
697+ // Use a very high nonce that's way ahead of the current account nonce
698+ lastNonce := uint64 (999999 )
699+ tx := evm .GetRandomTransaction (t , "cece4f25ac74deb1468965160c7185e07dff413f23fcadb611b05ca37ab0a52e" , "0x944fDcD1c868E3cC566C78023CcB38A32cDA836E" , "1234" , 22000 , & lastNonce )
700+
701+ err := client .SendTransaction (ctx , tx )
702+ if err != nil {
703+ invalidTxErrors = append (invalidTxErrors , fmt .Sprintf ("Invalid nonce tx: %v" , err ))
704+ t .Logf ("✅ Invalid nonce transaction rejected as expected: %v" , err )
705+ } else {
706+ invalidTxHashes = append (invalidTxHashes , tx .Hash ())
707+ t .Logf ("⚠️ Invalid nonce transaction was submitted: %s" , tx .Hash ().Hex ())
708+ }
709+ }()
710+
711+ // 7d. Test invalid gas limit transaction (too low)
712+ t .Log ("7d. Testing transaction with invalid gas limit..." )
713+ func () {
714+ defer func () {
715+ if r := recover (); r != nil {
716+ invalidTxErrors = append (invalidTxErrors , fmt .Sprintf ("Invalid gas limit tx: %v" , r ))
717+ t .Logf ("✅ Invalid gas limit transaction rejected as expected: %v" , r )
718+ }
719+ }()
720+
721+ // Use an extremely low gas limit that's insufficient for basic transfer
722+ lastNonce := uint64 (0 )
723+ tx := evm .GetRandomTransaction (t , "cece4f25ac74deb1468965160c7185e07dff413f23fcadb611b05ca37ab0a52e" , "0x944fDcD1c868E3cC566C78023CcB38A32cDA836E" , "1234" , 1000 , & lastNonce ) // Very low gas
724+
725+ err := client .SendTransaction (ctx , tx )
726+ if err != nil {
727+ invalidTxErrors = append (invalidTxErrors , fmt .Sprintf ("Invalid gas limit tx: %v" , err ))
728+ t .Logf ("✅ Invalid gas limit transaction rejected as expected: %v" , err )
729+ } else {
730+ invalidTxHashes = append (invalidTxHashes , tx .Hash ())
731+ t .Logf ("⚠️ Invalid gas limit transaction was submitted: %s" , tx .Hash ().Hex ())
732+ }
733+ }()
734+
735+ // 8. Wait a bit for any transactions to be processed
736+ t .Log ("Waiting for transaction processing..." )
737+ time .Sleep (5 * time .Second )
738+
739+ // 9. Check that none of the invalid transactions were included in blocks
740+ invalidTxsIncluded := 0
741+ for i , txHash := range invalidTxHashes {
742+ receipt , err := client .TransactionReceipt (ctx , txHash )
743+ if err == nil && receipt != nil {
744+ invalidTxsIncluded ++
745+ t .Errorf ("❌ Invalid transaction %d was included in block %d: %s" , i + 1 , receipt .BlockNumber .Uint64 (), txHash .Hex ())
746+ }
747+ }
748+
749+ if invalidTxsIncluded > 0 {
750+ require .Fail (t , fmt .Sprintf ("❌ %d invalid transactions were incorrectly included in blocks" , invalidTxsIncluded ))
751+ } else {
752+ t .Logf ("✅ All invalid transactions were properly rejected: %d errors recorded" , len (invalidTxErrors ))
753+ for i , errMsg := range invalidTxErrors {
754+ t .Logf (" %d. %s" , i + 1 , errMsg )
755+ }
756+ }
757+
758+ // 10. Submit a valid transaction to verify system stability
759+ t .Log ("Testing system stability with valid transaction..." )
760+ lastNonce := uint64 (0 )
761+ validTx := evm .GetRandomTransaction (t , "cece4f25ac74deb1468965160c7185e07dff413f23fcadb611b05ca37ab0a52e" , "0x944fDcD1c868E3cC566C78023CcB38A32cDA836E" , "1234" , 22000 , & lastNonce )
762+
763+ evm .SubmitTransaction (t , validTx )
764+ t .Logf ("Submitted valid transaction: %s" , validTx .Hash ().Hex ())
765+
766+ // 11. Wait for valid transaction to be included
767+ require .Eventually (t , func () bool {
768+ receipt , err := client .TransactionReceipt (ctx , validTx .Hash ())
769+ return err == nil && receipt != nil && receipt .Status == 1
770+ }, 20 * time .Second , 1 * time .Second , "Valid transaction should be included after invalid ones were rejected" )
771+
772+ t .Log ("✅ Valid transaction included successfully - system stability confirmed" )
773+
774+ // 12. Final verification
775+ validReceipt , err := client .TransactionReceipt (ctx , validTx .Hash ())
776+ require .NoError (t , err , "Should get receipt for valid transaction" )
777+ require .Equal (t , uint64 (1 ), validReceipt .Status , "Valid transaction should be successful" )
778+
779+ t .Logf ("✅ Test PASSED: Invalid transaction rejection working correctly" )
780+ t .Logf (" - %d invalid transactions properly rejected" , len (invalidTxErrors ))
781+ t .Logf (" - No invalid transactions included in any blocks" )
782+ t .Logf (" - Valid transactions continue to work normally" )
783+ t .Logf (" - System maintains stability after rejecting invalid transactions" )
784+ t .Logf (" - Transaction validation mechanisms functioning properly" )
785+ }
0 commit comments