@@ -48,6 +48,7 @@ import (
48
48
"github.com/ethereum/go-ethereum/internal/ethapi/override"
49
49
"github.com/ethereum/go-ethereum/params"
50
50
"github.com/ethereum/go-ethereum/rpc"
51
+ "github.com/ethereum/go-ethereum/trie"
51
52
)
52
53
53
54
var (
@@ -1334,3 +1335,250 @@ func TestStandardTraceBlockToFile(t *testing.T) {
1334
1335
}
1335
1336
}
1336
1337
}
1338
+
1339
+ // createTestTransactions creates test transactions for bad block testing
1340
+ func createTestTransactions (t * testing.T , count int ) []* types.Transaction {
1341
+ t .Helper ()
1342
+
1343
+ var (
1344
+ key , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
1345
+ testAddr = common .HexToAddress ("0x7217d81b76bdd8707601e959454e3d776aee5f43" )
1346
+ )
1347
+
1348
+ var transactions []* types.Transaction
1349
+ for i := 0 ; i < count ; i ++ {
1350
+ tx , _ := types .SignTx (types .NewTx (& types.LegacyTx {
1351
+ Nonce : uint64 (i ),
1352
+ To : & testAddr ,
1353
+ Value : big .NewInt (int64 (100 * (i + 1 ))), // Different values for each tx
1354
+ Gas : 21000 ,
1355
+ GasPrice : big .NewInt (1000000000 ),
1356
+ Data : []byte {},
1357
+ }), types.HomesteadSigner {}, key )
1358
+ transactions = append (transactions , tx )
1359
+ }
1360
+
1361
+ return transactions
1362
+ }
1363
+
1364
+ // createSingleTransaction creates a single transaction for testing
1365
+ func createSingleTransaction (t * testing.T , nonce uint64 , value * big.Int , gasLimit uint64 , data []byte ) * types.Transaction {
1366
+ t .Helper ()
1367
+
1368
+ var (
1369
+ key , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
1370
+ testAddr = common .HexToAddress ("0x7217d81b76bdd8707601e959454e3d776aee5f43" )
1371
+ )
1372
+
1373
+ tx , _ := types .SignTx (types .NewTx (& types.LegacyTx {
1374
+ Nonce : nonce ,
1375
+ To : & testAddr ,
1376
+ Value : value ,
1377
+ Gas : gasLimit ,
1378
+ GasPrice : big .NewInt (1000000000 ),
1379
+ Data : data ,
1380
+ }), types.HomesteadSigner {}, key )
1381
+
1382
+ return tx
1383
+ }
1384
+
1385
+ // setupBadBlock creates a bad block and stores it in the database for testing
1386
+ func setupBadBlock (t * testing.T , backend * testBackend , transactions []* types.Transaction ) (* types.Block , []common.Hash ) {
1387
+ t .Helper ()
1388
+
1389
+ var txHashes []common.Hash
1390
+ for _ , tx := range transactions {
1391
+ txHashes = append (txHashes , tx .Hash ())
1392
+ }
1393
+
1394
+ // Get the latest block from the test chain as the parent
1395
+ latestBlock := backend .chain .CurrentBlock ()
1396
+ parentHash := latestBlock .Hash ()
1397
+ parentNumber := latestBlock .Number .Uint64 ()
1398
+
1399
+ // Create a bad block header that references the existing parent
1400
+ badHeader := & types.Header {
1401
+ Number : big .NewInt (int64 (parentNumber + 1 )),
1402
+ Time : latestBlock .Time + 1 ,
1403
+ Extra : []byte ("bad block for testing" ),
1404
+ GasLimit : latestBlock .GasLimit ,
1405
+ GasUsed : uint64 (len (transactions ) * 21000 ),
1406
+ Difficulty : big .NewInt (1000 ),
1407
+ UncleHash : types .EmptyUncleHash ,
1408
+ TxHash : types .DeriveSha (types .Transactions (transactions ), trie .NewStackTrie (nil )),
1409
+ ReceiptHash : types .EmptyReceiptsHash ,
1410
+ ParentHash : parentHash ,
1411
+ BaseFee : latestBlock .BaseFee , // Copy base fee to avoid nil pointer
1412
+ }
1413
+
1414
+ // Create the bad block
1415
+ body := & types.Body {
1416
+ Transactions : transactions ,
1417
+ Uncles : []* types.Header {},
1418
+ }
1419
+ badBlock := types .NewBlock (badHeader , body , nil , trie .NewStackTrie (nil ))
1420
+
1421
+ // Store the bad block in the database
1422
+ rawdb .WriteBadBlock (backend .chaindb , badBlock )
1423
+
1424
+ // Verify the bad block was stored
1425
+ storedBlock := rawdb .ReadBadBlock (backend .chaindb , badBlock .Hash ())
1426
+ if storedBlock == nil {
1427
+ t .Fatalf ("Failed to store bad block in database" )
1428
+ }
1429
+
1430
+ return badBlock , txHashes
1431
+ }
1432
+
1433
+ func TestStandardTraceBadBlockToFile (t * testing.T ) {
1434
+ // Set up accounts for testing
1435
+ key , _ := crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
1436
+ address := crypto .PubkeyToAddress (key .PublicKey )
1437
+ funds := big .NewInt (1000000000000000 )
1438
+ testAddr := common .HexToAddress ("0x7217d81b76bdd8707601e959454e3d776aee5f43" )
1439
+ testCode := []byte {byte (vm .PUSH1 ), 0x42 , byte (vm .POP ), byte (vm .STOP )}
1440
+
1441
+ // Create test backend with proper accounts
1442
+ genesis := & core.Genesis {
1443
+ Config : params .TestChainConfig ,
1444
+ Alloc : types.GenesisAlloc {
1445
+ address : {Balance : funds },
1446
+ testAddr : {
1447
+ Code : testCode ,
1448
+ Balance : big .NewInt (0 ),
1449
+ },
1450
+ },
1451
+ }
1452
+ backend := newTestBackend (t , 1 , genesis , func (i int , b * core.BlockGen ) {
1453
+ // Empty block generator
1454
+ })
1455
+ defer backend .chain .Stop ()
1456
+
1457
+ api := NewAPI (backend )
1458
+
1459
+ // Create test transactions
1460
+ testTxs := createTestTransactions (t , 2 )
1461
+ emptyTxs := []* types.Transaction {}
1462
+
1463
+ // Create bad blocks for testing
1464
+ badBlockWithTxs , txHashes := setupBadBlock (t , backend , testTxs )
1465
+ badBlockWithoutTxs , _ := setupBadBlock (t , backend , emptyTxs )
1466
+ nonExistentHash := common .HexToHash ("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" )
1467
+
1468
+ var testSuite = []struct {
1469
+ name string
1470
+ badBlockHash common.Hash
1471
+ config * StdTraceConfig
1472
+ expectError bool
1473
+ expectedError string
1474
+ expectedTraces []string
1475
+ }{
1476
+ {
1477
+ name : "BasicBadBlockTrace" ,
1478
+ badBlockHash : badBlockWithTxs .Hash (),
1479
+ config : nil ,
1480
+ expectError : false ,
1481
+ expectedTraces : []string {
1482
+ `{"pc":0,"op":96,"gas":"0x0","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1","error":"out of gas"}
1483
+ {"output":"","gasUsed":"0x0","error":"out of gas"}
1484
+ ` ,
1485
+ `{"pc":0,"op":96,"gas":"0x0","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1","error":"out of gas"}
1486
+ {"output":"","gasUsed":"0x0","error":"out of gas"}
1487
+ ` ,
1488
+ },
1489
+ },
1490
+ {
1491
+ name : "BadBlockNotFound" ,
1492
+ badBlockHash : nonExistentHash ,
1493
+ config : nil ,
1494
+ expectError : true ,
1495
+ expectedError : "bad block 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef not found" ,
1496
+ },
1497
+ {
1498
+ name : "BadBlockWithSpecificTransaction" ,
1499
+ badBlockHash : badBlockWithTxs .Hash (),
1500
+ config : & StdTraceConfig {
1501
+ TxHash : txHashes [0 ], // Trace only first transaction
1502
+ },
1503
+ expectError : false ,
1504
+ expectedTraces : []string {
1505
+ `{"pc":0,"op":96,"gas":"0x0","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1","error":"out of gas"}
1506
+ {"output":"","gasUsed":"0x0","error":"out of gas"}
1507
+ ` ,
1508
+ },
1509
+ },
1510
+ {
1511
+ name : "BadBlockWithoutTransactions" ,
1512
+ badBlockHash : badBlockWithoutTxs .Hash (),
1513
+ config : nil ,
1514
+ expectError : false ,
1515
+ },
1516
+ {
1517
+ name : "BadBlockWithConfiguration" ,
1518
+ badBlockHash : badBlockWithTxs .Hash (),
1519
+ config : & StdTraceConfig {
1520
+ Config : logger.Config {
1521
+ DisableStack : true ,
1522
+ },
1523
+ },
1524
+ expectError : false ,
1525
+ expectedTraces : []string {
1526
+ `{"pc":0,"op":96,"gas":"0x0","gasCost":"0x3","memSize":0,"stack":null,"depth":1,"refund":0,"opName":"PUSH1","error":"out of gas"}
1527
+ {"output":"","gasUsed":"0x0","error":"out of gas"}
1528
+ ` ,
1529
+ `{"pc":0,"op":96,"gas":"0x0","gasCost":"0x3","memSize":0,"stack":null,"depth":1,"refund":0,"opName":"PUSH1","error":"out of gas"}
1530
+ {"output":"","gasUsed":"0x0","error":"out of gas"}
1531
+ ` ,
1532
+ },
1533
+ },
1534
+ }
1535
+
1536
+ for _ , tc := range testSuite {
1537
+ t .Run (tc .name , func (t * testing.T ) {
1538
+ t .Parallel ()
1539
+
1540
+ files , err := api .StandardTraceBadBlockToFile (context .Background (), tc .badBlockHash , tc .config )
1541
+
1542
+ // Check error expectations
1543
+ if tc .expectError {
1544
+ if err == nil {
1545
+ t .Fatalf ("Expected error, got nil" )
1546
+ }
1547
+ if err .Error () != tc .expectedError {
1548
+ t .Fatalf ("Expected error '%s', got '%s'" , tc .expectedError , err .Error ())
1549
+ }
1550
+ if files != nil {
1551
+ t .Fatalf ("Expected nil files for error case, got %v" , files )
1552
+ }
1553
+ return
1554
+ }
1555
+
1556
+ // Check success case
1557
+ if err != nil {
1558
+ t .Fatalf ("Unexpected error: %v" , err )
1559
+ }
1560
+
1561
+ if len (files ) != len (tc .expectedTraces ) {
1562
+ t .Fatalf ("Expected %d trace files, got %d" , len (tc .expectedTraces ), len (files ))
1563
+ }
1564
+
1565
+ // Verify trace content if files are expected
1566
+ for i , fileName := range files {
1567
+ data , err := os .ReadFile (fileName )
1568
+ if err != nil {
1569
+ t .Fatalf ("Failed to read trace file %s: %v" , fileName , err )
1570
+ }
1571
+
1572
+ if i < len (tc .expectedTraces ) {
1573
+ traceContent := string (data )
1574
+ if traceContent != tc .expectedTraces [i ] {
1575
+ t .Fatalf ("Trace file %d content mismatch.\n Expected:\n %s\n Got:\n %s" , i , tc .expectedTraces [i ], traceContent )
1576
+ }
1577
+ }
1578
+
1579
+ // Clean up
1580
+ os .Remove (fileName )
1581
+ }
1582
+ })
1583
+ }
1584
+ }
0 commit comments