@@ -484,3 +484,163 @@ func TestGetDiffAccounts(t *testing.T) {
484
484
}
485
485
}
486
486
}
487
+
488
+ // newTwoForkedBlockchains returns two blockchains, these two chains are generated by different
489
+ // generators, they have some same parent blocks, the number of same blocks are determined by
490
+ // testBlocks, once chain1 inserted a non-default block, chain1 and chain2 get forked.
491
+ func newTwoForkedBlockchains (len1 , len2 int ) (chain1 * BlockChain , chain2 * BlockChain ) {
492
+ signer := types.HomesteadSigner {}
493
+ // Create a database pre-initialize with a genesis block
494
+ db1 := rawdb .NewMemoryDatabase ()
495
+ db1 .SetDiffStore (memorydb .New ())
496
+ (& Genesis {
497
+ Config : params .TestChainConfig ,
498
+ Alloc : GenesisAlloc {testAddr : {Balance : big .NewInt (100000000000000000 )}},
499
+ }).MustCommit (db1 )
500
+
501
+ chain1 , _ = NewBlockChain (db1 , nil , params .TestChainConfig , ethash .NewFaker (), vm.Config {}, nil , nil , EnablePersistDiff (860000 ))
502
+ generator1 := func (i int , block * BlockGen ) {
503
+ // The chain maker doesn't have access to a chain, so the difficulty will be
504
+ // lets unset (nil). Set it here to the correct value.
505
+ block .SetCoinbase (testAddr )
506
+
507
+ for idx , testBlock := range testBlocks {
508
+ // Specific block setting, the index in this generator has 1 diff from specified blockNr.
509
+ if i + 1 == testBlock .blockNr {
510
+ for _ , testTransaction := range testBlock .txs {
511
+ var transaction * types.Transaction
512
+ if testTransaction .to == nil {
513
+ transaction = types .NewContractCreation (block .TxNonce (testAddr ),
514
+ testTransaction .value , uint64 (commonGas ), testTransaction .gasPrice , testTransaction .data )
515
+ } else {
516
+ transaction = types .NewTransaction (block .TxNonce (testAddr ), * testTransaction .to ,
517
+ testTransaction .value , uint64 (commonGas ), testTransaction .gasPrice , testTransaction .data )
518
+ }
519
+ tx , err := types .SignTx (transaction , signer , testKey )
520
+ if err != nil {
521
+ panic (err )
522
+ }
523
+ block .AddTxWithChain (chain1 , tx )
524
+ }
525
+ break
526
+ }
527
+
528
+ // Default block setting.
529
+ if idx == len (testBlocks )- 1 {
530
+ // We want to simulate an empty middle block, having the same state as the
531
+ // first one. The last is needs a state change again to force a reorg.
532
+ for _ , testTransaction := range testBlocks [0 ].txs {
533
+ tx , err := types .SignTx (types .NewTransaction (block .TxNonce (testAddr ), * testTransaction .to ,
534
+ testTransaction .value , uint64 (commonGas ), testTransaction .gasPrice , testTransaction .data ), signer , testKey )
535
+ if err != nil {
536
+ panic (err )
537
+ }
538
+ block .AddTxWithChain (chain1 , tx )
539
+ }
540
+ }
541
+ }
542
+
543
+ }
544
+ bs1 , _ := GenerateChain (params .TestChainConfig , chain1 .Genesis (), ethash .NewFaker (), db1 , len1 , generator1 )
545
+ if _ , err := chain1 .InsertChain (bs1 ); err != nil {
546
+ panic (err )
547
+ }
548
+
549
+ // Create a database pre-initialize with a genesis block
550
+ db2 := rawdb .NewMemoryDatabase ()
551
+ db2 .SetDiffStore (memorydb .New ())
552
+ (& Genesis {
553
+ Config : params .TestChainConfig ,
554
+ Alloc : GenesisAlloc {testAddr : {Balance : big .NewInt (100000000000000000 )}},
555
+ }).MustCommit (db2 )
556
+ chain2 , _ = NewBlockChain (db2 , nil , params .TestChainConfig , ethash .NewFaker (), vm.Config {}, nil , nil , EnablePersistDiff (860000 ))
557
+ generator2 := func (i int , block * BlockGen ) {
558
+ // The chain maker doesn't have access to a chain, so the difficulty will be
559
+ // lets unset (nil). Set it here to the correct value.
560
+ block .SetCoinbase (testAddr )
561
+ // We want to simulate an empty middle block, having the same state as the
562
+ // first one. The last is needs a state change again to force a reorg.
563
+ for _ , testTransaction := range testBlocks [0 ].txs {
564
+ tx , err := types .SignTx (types .NewTransaction (block .TxNonce (testAddr ), * testTransaction .to ,
565
+ testTransaction .value , uint64 (commonGas ), testTransaction .gasPrice , testTransaction .data ), signer , testKey )
566
+ if err != nil {
567
+ panic (err )
568
+ }
569
+ block .AddTxWithChain (chain1 , tx )
570
+ }
571
+ }
572
+ bs2 , _ := GenerateChain (params .TestChainConfig , chain2 .Genesis (), ethash .NewFaker (), db2 , len2 , generator2 )
573
+ if _ , err := chain2 .InsertChain (bs2 ); err != nil {
574
+ panic (err )
575
+ }
576
+
577
+ return chain1 , chain2
578
+ }
579
+
580
+ func testGetRootByDiffHash (t * testing.T , chain1 , chain2 * BlockChain , blockNumber uint64 , status types.VerifyStatus ) {
581
+ block2 := chain2 .GetBlockByNumber (blockNumber )
582
+ if block2 == nil {
583
+ t .Fatalf ("failed to find block, number: %v" , blockNumber )
584
+ }
585
+ expect := types.VerifyResult {
586
+ Status : status ,
587
+ BlockNumber : blockNumber ,
588
+ BlockHash : block2 .Hash (),
589
+ }
590
+ if status .Code & 0xff00 == types .StatusVerified .Code {
591
+ expect .Root = block2 .Root ()
592
+ }
593
+
594
+ diffLayer2 := chain2 .GetTrustedDiffLayer (block2 .Hash ())
595
+ if diffLayer2 == nil {
596
+ t .Fatal ("failed to find diff layer" )
597
+ }
598
+ diffHash2 := types .EmptyRootHash
599
+ if status != types .StatusDiffHashMismatch {
600
+ var err error
601
+ diffHash2 , err = GetTrustedDiffHash (diffLayer2 )
602
+ if err != nil {
603
+ t .Fatalf ("failed to compute diff hash: %v" , err )
604
+ }
605
+ }
606
+
607
+ if status == types .StatusUntrustedVerified {
608
+ block1 := chain1 .GetBlockByNumber (blockNumber )
609
+ if block1 == nil {
610
+ t .Fatalf ("failed to find block, number: %v" , blockNumber )
611
+ }
612
+ chain1 .diffLayerCache .Remove (block1 .Hash ())
613
+ }
614
+
615
+ result , _ := chain1 .GetRootByDiffHash (blockNumber , block2 .Hash (), diffHash2 )
616
+ if result .Status != expect .Status {
617
+ t .Fatalf ("failed to verify block, number: %v, expect status: %v, real status: %v" , blockNumber , expect .Status , result .Status )
618
+ }
619
+ if result .Root != expect .Root {
620
+ t .Fatalf ("failed to verify block, number: %v, expect root: %v, real root: %v" , blockNumber , expect .Root , result .Root )
621
+ }
622
+ }
623
+
624
+ func TestGetRootByDiffHash (t * testing.T ) {
625
+ len1 := 23 // length of blockchain1
626
+ len2 := 35 // length of blockchain2
627
+ plen := 11 // length of same parent blocks, which determined by testBlocks.
628
+
629
+ chain1 , chain2 := newTwoForkedBlockchains (len1 , len2 )
630
+ defer chain1 .Stop ()
631
+ defer chain2 .Stop ()
632
+
633
+ hash1 := chain1 .GetBlockByNumber (uint64 (plen )).Hash ()
634
+ hash2 := chain2 .GetBlockByNumber (uint64 (plen )).Hash ()
635
+ if hash1 != hash2 {
636
+ t .Errorf ("chain content mismatch at %d: have hash %v, want hash %v" , plen , hash2 , hash1 )
637
+ }
638
+
639
+ testGetRootByDiffHash (t , chain1 , chain2 , 10 , types .StatusFullVerified )
640
+ testGetRootByDiffHash (t , chain1 , chain2 , 2 , types .StatusUntrustedVerified )
641
+ testGetRootByDiffHash (t , chain1 , chain2 , 10 , types .StatusDiffHashMismatch )
642
+ testGetRootByDiffHash (t , chain1 , chain2 , 12 , types .StatusImpossibleFork )
643
+ testGetRootByDiffHash (t , chain1 , chain2 , 20 , types .StatusPossibleFork )
644
+ testGetRootByDiffHash (t , chain1 , chain2 , 24 , types .StatusBlockNewer )
645
+ testGetRootByDiffHash (t , chain1 , chain2 , 35 , types .StatusBlockTooNew )
646
+ }
0 commit comments