@@ -40,46 +40,6 @@ import (
4040 "github.com/rollkit/rollkit/execution/evm"
4141)
4242
43- // TestEvmSequencerE2E tests the basic end-to-end functionality of a single EVM sequencer node.
44- //
45- // Test Flow:
46- // 1. Sets up Local DA layer for data availability
47- // 2. Starts EVM (Reth) engine via Docker Compose
48- // 3. Initializes and starts the sequencer node with proper configuration
49- // 4. Submits a single test transaction to the EVM
50- // 5. Verifies the transaction is successfully included in a block
51- //
52- // Validation:
53- // - Sequencer node starts successfully and becomes responsive
54- // - Transaction submission works correctly
55- // - Transaction is included in EVM block with success status
56- // - Block production occurs within expected timeframe
57- //
58- // This test validates the core functionality of Rollkit's EVM integration
59- // and ensures basic transaction processing works correctly.
60- func TestEvmSequencerE2E (t * testing.T ) {
61- flag .Parse ()
62- workDir := t .TempDir ()
63- nodeHome := filepath .Join (workDir , "evm-agg" )
64- sut := NewSystemUnderTest (t )
65-
66- // Setup sequencer
67- genesisHash := setupSequencerOnlyTest (t , sut , nodeHome )
68- t .Logf ("Genesis hash: %s" , genesisHash )
69-
70- // Submit a transaction to EVM
71- lastNonce := uint64 (0 )
72- tx := evm .GetRandomTransaction (t , TestPrivateKey , TestToAddress , DefaultChainID , DefaultGasLimit , & lastNonce )
73- evm .SubmitTransaction (t , tx )
74- t .Log ("Submitted test transaction to EVM" )
75-
76- // Wait for block production and verify transaction inclusion
77- require .Eventually (t , func () bool {
78- return evm .CheckTxIncluded (t , tx .Hash ())
79- }, 15 * time .Second , 500 * time .Millisecond )
80- t .Log ("Transaction included in EVM block" )
81- }
82-
8343// TestEvmMultipleTransactionInclusionE2E tests high-throughput transaction processing
8444// to ensure multiple transactions submitted in quick succession are all included
8545// and maintain correct ordering without any loss or corruption.
@@ -256,189 +216,6 @@ func TestEvmMultipleTransactionInclusionE2E(t *testing.T) {
256216 t .Logf ("✅ Test PASSED: All %d transactions included in correct nonce order" , numTxs )
257217}
258218
259- // TestEvmDoubleSpendNonceHandlingE2E tests the system's ability to handle transactions with
260- // duplicate nonces correctly, ensuring that double-spending is prevented.
261- //
262- // Test Purpose:
263- // - Ensure the system correctly handles transactions with duplicate or out-of-order nonces
264- // - Prevent double-spending scenarios by rejecting duplicate nonce transactions
265- // - Validate that only one transaction per nonce is included in the blockchain
266- //
267- // Test Flow:
268- // 1. Sets up Local DA layer and EVM sequencer
269- // 2. Submits two transactions with the same nonce from the same account
270- // 3. Waits for transaction processing and block inclusion
271- // 4. Verifies that only one transaction is included in the blockchain
272- // 5. Confirms the rejected transaction is not included in any block
273- // 6. Validates account nonce is incremented correctly (only once)
274- //
275- // Expected Behavior:
276- // - First transaction submitted should be included successfully
277- // - Second transaction with same nonce should be rejected/not included
278- // - Account nonce should only increment once
279- // - No double-spending should occur
280- // - System should remain stable and continue processing subsequent transactions
281- //
282- // This test validates Rollkit's nonce handling and double-spend prevention mechanisms.
283- func TestEvmDoubleSpendNonceHandlingE2E (t * testing.T ) {
284- flag .Parse ()
285- workDir := t .TempDir ()
286- nodeHome := filepath .Join (workDir , "evm-agg" )
287- sut := NewSystemUnderTest (t )
288-
289- // Setup sequencer
290- genesisHash := setupSequencerOnlyTest (t , sut , nodeHome )
291- t .Logf ("Genesis hash: %s" , genesisHash )
292-
293- // Connect to EVM
294- client , err := ethclient .Dial (SequencerEthURL )
295- require .NoError (t , err , "Should be able to connect to EVM" )
296- defer client .Close ()
297-
298- // Create two transactions with the same nonce (double-spend attempt)
299- const duplicateNonce = uint64 (0 )
300- lastNonce := duplicateNonce
301-
302- // Create first transaction with nonce 0
303- tx1 := evm .GetRandomTransaction (t , TestPrivateKey , TestToAddress , DefaultChainID , DefaultGasLimit , & lastNonce )
304-
305- // Reset nonce to create second transaction with same nonce
306- lastNonce = duplicateNonce
307- tx2 := evm .GetRandomTransaction (t , TestPrivateKey , TestToAddress , DefaultChainID , DefaultGasLimit , & lastNonce )
308-
309- // Verify both transactions have the same nonce
310- require .Equal (t , tx1 .Nonce (), tx2 .Nonce (), "Both transactions should have the same nonce" )
311- require .Equal (t , duplicateNonce , tx1 .Nonce (), "Transaction 1 should have nonce %d" , duplicateNonce )
312- require .Equal (t , duplicateNonce , tx2 .Nonce (), "Transaction 2 should have nonce %d" , duplicateNonce )
313-
314- t .Logf ("Created two transactions with same nonce %d:" , duplicateNonce )
315- t .Logf (" TX1 Hash: %s" , tx1 .Hash ().Hex ())
316- t .Logf (" TX2 Hash: %s" , tx2 .Hash ().Hex ())
317-
318- // Submit both transactions in quick succession
319- evm .SubmitTransaction (t , tx1 )
320- t .Logf ("Submitted first transaction (TX1): %s" , tx1 .Hash ().Hex ())
321-
322- // Small delay between submissions to simulate realistic scenario
323- time .Sleep (20 * time .Millisecond )
324-
325- // Try to submit the second transaction - this should fail with "replacement transaction underpriced" or similar
326- // We expect this to fail, so we'll handle the error gracefully
327- func () {
328- defer func () {
329- if r := recover (); r != nil {
330- t .Logf ("Second transaction submission failed as expected: %v" , r )
331- }
332- }()
333- // This should fail, but we'll try anyway to test the system's response
334- err := func () (err error ) {
335- defer func () {
336- if r := recover (); r != nil {
337- err = fmt .Errorf ("transaction submission failed: %v" , r )
338- }
339- }()
340- // Use a lower-level approach to avoid panics
341- client , clientErr := ethclient .Dial (SequencerEthURL )
342- if clientErr != nil {
343- return clientErr
344- }
345- defer client .Close ()
346-
347- return client .SendTransaction (context .Background (), tx2 )
348- }()
349-
350- if err != nil {
351- t .Logf ("Second transaction (TX2) rejected as expected: %v" , err )
352- } else {
353- t .Logf ("Second transaction (TX2) submitted: %s" , tx2 .Hash ().Hex ())
354- }
355- }()
356-
357- // Wait for block production and check transaction inclusion
358- ctx := context .Background ()
359-
360- t .Log ("Waiting for transactions to be processed..." )
361- time .Sleep (2 * time .Second )
362-
363- // Check current block height to see if blocks are being produced
364- blockNumber , err := client .BlockNumber (ctx )
365- if err != nil {
366- t .Logf ("Warning: Could not get block number: %v" , err )
367- } else {
368- t .Logf ("Current block number: %d" , blockNumber )
369- }
370-
371- // Check which transaction was included
372- var includedTxHash common.Hash
373- var rejectedTxHash common.Hash
374-
375- // Get hash values for easier reference
376- tx1Hash := tx1 .Hash ()
377- tx2Hash := tx2 .Hash ()
378-
379- // Check TX1
380- receipt1 , err1 := client .TransactionReceipt (ctx , tx1Hash )
381- tx1Included := err1 == nil && receipt1 != nil && receipt1 .Status == 1
382-
383- // Check TX2
384- receipt2 , err2 := client .TransactionReceipt (ctx , tx2Hash )
385- tx2Included := err2 == nil && receipt2 != nil && receipt2 .Status == 1
386-
387- // Determine which transaction was included and which was rejected
388- if tx1Included && ! tx2Included {
389- includedTxHash = tx1Hash
390- rejectedTxHash = tx2Hash
391- t .Logf ("✅ TX1 included, TX2 rejected (as expected)" )
392- } else if tx2Included && ! tx1Included {
393- includedTxHash = tx2Hash
394- rejectedTxHash = tx1Hash
395- t .Logf ("✅ TX2 included, TX1 rejected (as expected)" )
396- } else if tx1Included && tx2Included {
397- t .Errorf ("❌ BOTH transactions were included - double-spend not prevented!" )
398- t .Errorf (" TX1: %s (block: %d)" , tx1Hash .Hex (), receipt1 .BlockNumber .Uint64 ())
399- t .Errorf (" TX2: %s (block: %d)" , tx2Hash .Hex (), receipt2 .BlockNumber .Uint64 ())
400- require .Fail (t , "Double-spend prevention failed - both transactions with same nonce were included" )
401- } else {
402- t .Errorf ("❌ NEITHER transaction was included" )
403- t .Errorf (" TX1 error: %v" , err1 )
404- t .Errorf (" TX2 error: %v" , err2 )
405- require .Fail (t , "Neither transaction was included - system may have failed" )
406- }
407-
408- // Verify exactly one transaction was included
409- require .True (t , (tx1Included && ! tx2Included ) || (tx2Included && ! tx1Included ),
410- "Exactly one transaction should be included, the other should be rejected" )
411-
412- t .Logf ("Double-spend prevention working correctly:" )
413- t .Logf (" ✅ Included transaction: %s" , includedTxHash .Hex ())
414- t .Logf (" ❌ Rejected transaction: %s" , rejectedTxHash .Hex ())
415-
416- // Verify the account nonce (note: in test environment, nonce behavior may vary)
417- fromAddress := common .HexToAddress (TestToAddress )
418-
419- // Wait for the transaction to be fully processed and nonce updated
420- time .Sleep (500 * time .Millisecond )
421-
422- currentNonce , err := client .NonceAt (ctx , fromAddress , nil )
423- require .NoError (t , err , "Should be able to get current nonce" )
424-
425- expectedNonce := duplicateNonce + 1
426- if currentNonce == expectedNonce {
427- t .Logf ("✅ Account nonce correctly incremented: %d -> %d" , duplicateNonce , currentNonce )
428- } else {
429- // In test environments, nonce behavior might be different
430- // The important thing is that double-spend was prevented
431- t .Logf ("⚠️ Account nonce: expected %d, got %d (this is acceptable in test environment)" , expectedNonce , currentNonce )
432- t .Logf ("✅ Main test objective achieved: double-spend prevention working correctly" )
433- }
434-
435- t .Logf ("✅ Test PASSED: Double-spend prevention working correctly" )
436- t .Logf (" - Only 1 of 2 transactions with same nonce was included" )
437- t .Logf (" - Double-spend prevention mechanism functioning properly" )
438- t .Logf (" - EVM correctly rejected duplicate nonce transaction" )
439- t .Logf (" - System maintains transaction integrity and prevents double-spending" )
440- }
441-
442219// TestEvmInvalidTransactionRejectionE2E tests the system's ability to properly reject
443220// various types of invalid transactions and ensure they are not included in any blocks.
444221//
0 commit comments