@@ -18,8 +18,10 @@ package core
18
18
19
19
import (
20
20
"fmt"
21
+ "io/ioutil"
21
22
"math/big"
22
23
"math/rand"
24
+ "os"
23
25
"sync"
24
26
"testing"
25
27
"time"
@@ -33,7 +35,6 @@ import (
33
35
"github.com/ethereum/go-ethereum/core/vm"
34
36
"github.com/ethereum/go-ethereum/crypto"
35
37
"github.com/ethereum/go-ethereum/ethdb"
36
- "github.com/ethereum/go-ethereum/ethdb/memorydb"
37
38
"github.com/ethereum/go-ethereum/params"
38
39
)
39
40
@@ -639,34 +640,63 @@ func TestFastVsFullChains(t *testing.T) {
639
640
if n , err := fast .InsertHeaderChain (headers , 1 ); err != nil {
640
641
t .Fatalf ("failed to insert header %d: %v" , n , err )
641
642
}
642
- if n , err := fast .InsertReceiptChain (blocks , receipts ); err != nil {
643
+ if n , err := fast .InsertReceiptChain (blocks , receipts , 0 ); err != nil {
644
+ t .Fatalf ("failed to insert receipt %d: %v" , n , err )
645
+ }
646
+ // Freezer style fast import the chain.
647
+ frdir , err := ioutil .TempDir ("" , "" )
648
+ if err != nil {
649
+ t .Fatalf ("failed to create temp freezer dir: %v" , err )
650
+ }
651
+ defer os .Remove (frdir )
652
+ ancientDb , err := rawdb .NewDatabaseWithFreezer (rawdb .NewMemoryDatabase (), frdir , "" )
653
+ if err != nil {
654
+ t .Fatalf ("failed to create temp freezer db: %v" , err )
655
+ }
656
+ gspec .MustCommit (ancientDb )
657
+ ancient , _ := NewBlockChain (ancientDb , nil , gspec .Config , ethash .NewFaker (), vm.Config {}, nil )
658
+ defer ancient .Stop ()
659
+
660
+ if n , err := ancient .InsertHeaderChain (headers , 1 ); err != nil {
661
+ t .Fatalf ("failed to insert header %d: %v" , n , err )
662
+ }
663
+ if n , err := ancient .InsertReceiptChain (blocks , receipts , uint64 (len (blocks )/ 2 )); err != nil {
643
664
t .Fatalf ("failed to insert receipt %d: %v" , n , err )
644
665
}
645
666
// Iterate over all chain data components, and cross reference
646
667
for i := 0 ; i < len (blocks ); i ++ {
647
668
num , hash := blocks [i ].NumberU64 (), blocks [i ].Hash ()
648
669
649
670
if ftd , atd := fast .GetTdByHash (hash ), archive .GetTdByHash (hash ); ftd .Cmp (atd ) != 0 {
650
- t .Errorf ("block #%d [%x]: td mismatch: have %v, want %v" , num , hash , ftd , atd )
671
+ t .Errorf ("block #%d [%x]: td mismatch: fastdb %v, archivedb %v" , num , hash , ftd , atd )
672
+ }
673
+ if antd , artd := ancient .GetTdByHash (hash ), archive .GetTdByHash (hash ); antd .Cmp (artd ) != 0 {
674
+ t .Errorf ("block #%d [%x]: td mismatch: ancientdb %v, archivedb %v" , num , hash , antd , artd )
651
675
}
652
676
if fheader , aheader := fast .GetHeaderByHash (hash ), archive .GetHeaderByHash (hash ); fheader .Hash () != aheader .Hash () {
653
- t .Errorf ("block #%d [%x]: header mismatch: have %v, want %v" , num , hash , fheader , aheader )
677
+ t .Errorf ("block #%d [%x]: header mismatch: fastdb %v, archivedb %v" , num , hash , fheader , aheader )
678
+ }
679
+ if anheader , arheader := ancient .GetHeaderByHash (hash ), archive .GetHeaderByHash (hash ); anheader .Hash () != arheader .Hash () {
680
+ t .Errorf ("block #%d [%x]: header mismatch: ancientdb %v, archivedb %v" , num , hash , anheader , arheader )
654
681
}
655
- if fblock , ablock := fast .GetBlockByHash (hash ), archive .GetBlockByHash (hash ); fblock .Hash () != ablock .Hash () {
656
- t .Errorf ("block #%d [%x]: block mismatch: have %v, want %v" , num , hash , fblock , ablock )
657
- } else if types .DeriveSha (fblock .Transactions ()) != types .DeriveSha (ablock .Transactions ()) {
658
- t .Errorf ("block #%d [%x]: transactions mismatch: have %v, want %v" , num , hash , fblock .Transactions (), ablock .Transactions ())
659
- } else if types .CalcUncleHash (fblock .Uncles ()) != types .CalcUncleHash (ablock .Uncles ()) {
660
- t .Errorf ("block #%d [%x]: uncles mismatch: have %v, want %v" , num , hash , fblock .Uncles (), ablock .Uncles ())
682
+ if fblock , arblock , anblock := fast .GetBlockByHash (hash ), archive .GetBlockByHash (hash ), ancient . GetBlockByHash ( hash ) ; fblock .Hash () != arblock . Hash () || anblock . Hash () != arblock .Hash () {
683
+ t .Errorf ("block #%d [%x]: block mismatch: fastdb %v, ancientdb %v, archivedb %v " , num , hash , fblock , anblock , arblock )
684
+ } else if types .DeriveSha (fblock .Transactions ()) != types .DeriveSha (arblock . Transactions ()) || types . DeriveSha ( anblock . Transactions ()) != types . DeriveSha ( arblock .Transactions ()) {
685
+ t .Errorf ("block #%d [%x]: transactions mismatch: fastdb %v, ancientdb %v, archivedb %v " , num , hash , fblock .Transactions (), anblock . Transactions (), arblock .Transactions ())
686
+ } else if types .CalcUncleHash (fblock .Uncles ()) != types .CalcUncleHash (arblock . Uncles ()) || types . CalcUncleHash ( anblock . Uncles ()) != types . CalcUncleHash ( arblock .Uncles ()) {
687
+ t .Errorf ("block #%d [%x]: uncles mismatch: fastdb %v, ancientdb %v, archivedb %v " , num , hash , fblock .Uncles (), anblock , arblock .Uncles ())
661
688
}
662
- if freceipts , areceipts := rawdb .ReadReceipts (fastDb , hash , * rawdb .ReadHeaderNumber (fastDb , hash ), fast .Config ()), rawdb .ReadReceipts (archiveDb , hash , * rawdb .ReadHeaderNumber (archiveDb , hash ), archive .Config ()); types .DeriveSha (freceipts ) != types .DeriveSha (areceipts ) {
663
- t .Errorf ("block #%d [%x]: receipts mismatch: have %v, want %v" , num , hash , freceipts , areceipts )
689
+ if freceipts , anreceipts , areceipts := rawdb .ReadReceipts (fastDb , hash , * rawdb .ReadHeaderNumber (fastDb , hash ), fast .Config ()), rawdb .ReadReceipts (ancientDb , hash , * rawdb . ReadHeaderNumber ( ancientDb , hash ), fast . Config ()), rawdb . ReadReceipts ( archiveDb , hash , * rawdb .ReadHeaderNumber (archiveDb , hash ), fast .Config ()); types .DeriveSha (freceipts ) != types .DeriveSha (areceipts ) {
690
+ t .Errorf ("block #%d [%x]: receipts mismatch: fastdb %v, ancientdb %v, archivedb %v " , num , hash , freceipts , anreceipts , areceipts )
664
691
}
665
692
}
666
693
// Check that the canonical chains are the same between the databases
667
694
for i := 0 ; i < len (blocks )+ 1 ; i ++ {
668
695
if fhash , ahash := rawdb .ReadCanonicalHash (fastDb , uint64 (i )), rawdb .ReadCanonicalHash (archiveDb , uint64 (i )); fhash != ahash {
669
- t .Errorf ("block #%d: canonical hash mismatch: have %v, want %v" , i , fhash , ahash )
696
+ t .Errorf ("block #%d: canonical hash mismatch: fastdb %v, archivedb %v" , i , fhash , ahash )
697
+ }
698
+ if anhash , arhash := rawdb .ReadCanonicalHash (ancientDb , uint64 (i )), rawdb .ReadCanonicalHash (archiveDb , uint64 (i )); anhash != arhash {
699
+ t .Errorf ("block #%d: canonical hash mismatch: ancientdb %v, archivedb %v" , i , anhash , arhash )
670
700
}
671
701
}
672
702
}
@@ -730,13 +760,40 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
730
760
if n , err := fast .InsertHeaderChain (headers , 1 ); err != nil {
731
761
t .Fatalf ("failed to insert header %d: %v" , n , err )
732
762
}
733
- if n , err := fast .InsertReceiptChain (blocks , receipts ); err != nil {
763
+ if n , err := fast .InsertReceiptChain (blocks , receipts , 0 ); err != nil {
734
764
t .Fatalf ("failed to insert receipt %d: %v" , n , err )
735
765
}
736
766
assert (t , "fast" , fast , height , height , 0 )
737
767
fast .Rollback (remove )
738
768
assert (t , "fast" , fast , height / 2 , height / 2 , 0 )
739
769
770
+ // Import the chain as a ancient-first node and ensure all pointers are updated
771
+ frdir , err := ioutil .TempDir ("" , "" )
772
+ if err != nil {
773
+ t .Fatalf ("failed to create temp freezer dir: %v" , err )
774
+ }
775
+ defer os .Remove (frdir )
776
+ ancientDb , err := rawdb .NewDatabaseWithFreezer (rawdb .NewMemoryDatabase (), frdir , "" )
777
+ if err != nil {
778
+ t .Fatalf ("failed to create temp freezer db: %v" , err )
779
+ }
780
+ gspec .MustCommit (ancientDb )
781
+ ancient , _ := NewBlockChain (ancientDb , nil , gspec .Config , ethash .NewFaker (), vm.Config {}, nil )
782
+ defer ancient .Stop ()
783
+
784
+ if n , err := ancient .InsertHeaderChain (headers , 1 ); err != nil {
785
+ t .Fatalf ("failed to insert header %d: %v" , n , err )
786
+ }
787
+ if n , err := ancient .InsertReceiptChain (blocks , receipts , uint64 (3 * len (blocks )/ 4 )); err != nil {
788
+ t .Fatalf ("failed to insert receipt %d: %v" , n , err )
789
+ }
790
+ assert (t , "ancient" , ancient , height , height , 0 )
791
+ ancient .Rollback (remove )
792
+ assert (t , "ancient" , ancient , height / 2 , height / 2 , 0 )
793
+ if frozen , err := ancientDb .Ancients (); err != nil || frozen != height / 2 + 1 {
794
+ t .Fatalf ("failed to truncate ancient store, want %v, have %v" , height / 2 + 1 , frozen )
795
+ }
796
+
740
797
// Import the chain as a light node and ensure all pointers are updated
741
798
lightDb := rawdb .NewMemoryDatabase ()
742
799
gspec .MustCommit (lightDb )
@@ -918,7 +975,7 @@ func TestLogRebirth(t *testing.T) {
918
975
var (
919
976
key1 , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
920
977
addr1 = crypto .PubkeyToAddress (key1 .PublicKey )
921
- db = memorydb . New ()
978
+ db = rawdb . NewMemoryDatabase ()
922
979
923
980
// this code generates a log
924
981
code = common .Hex2Bytes ("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00" )
@@ -1040,7 +1097,7 @@ func TestSideLogRebirth(t *testing.T) {
1040
1097
var (
1041
1098
key1 , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
1042
1099
addr1 = crypto .PubkeyToAddress (key1 .PublicKey )
1043
- db = memorydb . New ()
1100
+ db = rawdb . NewMemoryDatabase ()
1044
1101
1045
1102
// this code generates a log
1046
1103
code = common .Hex2Bytes ("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00" )
@@ -1564,6 +1621,122 @@ func TestLargeReorgTrieGC(t *testing.T) {
1564
1621
}
1565
1622
}
1566
1623
1624
+ func TestBlockchainRecovery (t * testing.T ) {
1625
+ // Configure and generate a sample block chain
1626
+ var (
1627
+ gendb = rawdb .NewMemoryDatabase ()
1628
+ key , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
1629
+ address = crypto .PubkeyToAddress (key .PublicKey )
1630
+ funds = big .NewInt (1000000000 )
1631
+ gspec = & Genesis {Config : params .TestChainConfig , Alloc : GenesisAlloc {address : {Balance : funds }}}
1632
+ genesis = gspec .MustCommit (gendb )
1633
+ )
1634
+ height := uint64 (1024 )
1635
+ blocks , receipts := GenerateChain (gspec .Config , genesis , ethash .NewFaker (), gendb , int (height ), nil )
1636
+
1637
+ // Import the chain as a ancient-first node and ensure all pointers are updated
1638
+ frdir , err := ioutil .TempDir ("" , "" )
1639
+ if err != nil {
1640
+ t .Fatalf ("failed to create temp freezer dir: %v" , err )
1641
+ }
1642
+ defer os .Remove (frdir )
1643
+ ancientDb , err := rawdb .NewDatabaseWithFreezer (rawdb .NewMemoryDatabase (), frdir , "" )
1644
+ if err != nil {
1645
+ t .Fatalf ("failed to create temp freezer db: %v" , err )
1646
+ }
1647
+ gspec .MustCommit (ancientDb )
1648
+ ancient , _ := NewBlockChain (ancientDb , nil , gspec .Config , ethash .NewFaker (), vm.Config {}, nil )
1649
+
1650
+ headers := make ([]* types.Header , len (blocks ))
1651
+ for i , block := range blocks {
1652
+ headers [i ] = block .Header ()
1653
+ }
1654
+ if n , err := ancient .InsertHeaderChain (headers , 1 ); err != nil {
1655
+ t .Fatalf ("failed to insert header %d: %v" , n , err )
1656
+ }
1657
+ if n , err := ancient .InsertReceiptChain (blocks , receipts , uint64 (3 * len (blocks )/ 4 )); err != nil {
1658
+ t .Fatalf ("failed to insert receipt %d: %v" , n , err )
1659
+ }
1660
+ ancient .Stop ()
1661
+
1662
+ // Destroy head fast block manually
1663
+ midBlock := blocks [len (blocks )/ 2 ]
1664
+ rawdb .WriteHeadFastBlockHash (ancientDb , midBlock .Hash ())
1665
+
1666
+ // Reopen broken blockchain again
1667
+ ancient , _ = NewBlockChain (ancientDb , nil , gspec .Config , ethash .NewFaker (), vm.Config {}, nil )
1668
+ defer ancient .Stop ()
1669
+ if num := ancient .CurrentBlock ().NumberU64 (); num != 0 {
1670
+ t .Errorf ("head block mismatch: have #%v, want #%v" , num , 0 )
1671
+ }
1672
+ if num := ancient .CurrentFastBlock ().NumberU64 (); num != midBlock .NumberU64 () {
1673
+ t .Errorf ("head fast-block mismatch: have #%v, want #%v" , num , midBlock .NumberU64 ())
1674
+ }
1675
+ if num := ancient .CurrentHeader ().Number .Uint64 (); num != midBlock .NumberU64 () {
1676
+ t .Errorf ("head header mismatch: have #%v, want #%v" , num , midBlock .NumberU64 ())
1677
+ }
1678
+ }
1679
+
1680
+ func TestIncompleteAncientReceiptChainInsertion (t * testing.T ) {
1681
+ // Configure and generate a sample block chain
1682
+ var (
1683
+ gendb = rawdb .NewMemoryDatabase ()
1684
+ key , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
1685
+ address = crypto .PubkeyToAddress (key .PublicKey )
1686
+ funds = big .NewInt (1000000000 )
1687
+ gspec = & Genesis {Config : params .TestChainConfig , Alloc : GenesisAlloc {address : {Balance : funds }}}
1688
+ genesis = gspec .MustCommit (gendb )
1689
+ )
1690
+ height := uint64 (1024 )
1691
+ blocks , receipts := GenerateChain (gspec .Config , genesis , ethash .NewFaker (), gendb , int (height ), nil )
1692
+
1693
+ // Import the chain as a ancient-first node and ensure all pointers are updated
1694
+ frdir , err := ioutil .TempDir ("" , "" )
1695
+ if err != nil {
1696
+ t .Fatalf ("failed to create temp freezer dir: %v" , err )
1697
+ }
1698
+ defer os .Remove (frdir )
1699
+ ancientDb , err := rawdb .NewDatabaseWithFreezer (rawdb .NewMemoryDatabase (), frdir , "" )
1700
+ if err != nil {
1701
+ t .Fatalf ("failed to create temp freezer db: %v" , err )
1702
+ }
1703
+ gspec .MustCommit (ancientDb )
1704
+ ancient , _ := NewBlockChain (ancientDb , nil , gspec .Config , ethash .NewFaker (), vm.Config {}, nil )
1705
+ defer ancient .Stop ()
1706
+
1707
+ headers := make ([]* types.Header , len (blocks ))
1708
+ for i , block := range blocks {
1709
+ headers [i ] = block .Header ()
1710
+ }
1711
+ if n , err := ancient .InsertHeaderChain (headers , 1 ); err != nil {
1712
+ t .Fatalf ("failed to insert header %d: %v" , n , err )
1713
+ }
1714
+ // Abort ancient receipt chain insertion deliberately
1715
+ ancient .terminateInsert = func (hash common.Hash , number uint64 ) bool {
1716
+ if number == blocks [len (blocks )/ 2 ].NumberU64 () {
1717
+ return true
1718
+ }
1719
+ return false
1720
+ }
1721
+ previousFastBlock := ancient .CurrentFastBlock ()
1722
+ if n , err := ancient .InsertReceiptChain (blocks , receipts , uint64 (3 * len (blocks )/ 4 )); err == nil {
1723
+ t .Fatalf ("failed to insert receipt %d: %v" , n , err )
1724
+ }
1725
+ if ancient .CurrentFastBlock ().NumberU64 () != previousFastBlock .NumberU64 () {
1726
+ t .Fatalf ("failed to rollback ancient data, want %d, have %d" , previousFastBlock .NumberU64 (), ancient .CurrentFastBlock ().NumberU64 ())
1727
+ }
1728
+ if frozen , err := ancient .db .Ancients (); err != nil || frozen != 1 {
1729
+ t .Fatalf ("failed to truncate ancient data" )
1730
+ }
1731
+ ancient .terminateInsert = nil
1732
+ if n , err := ancient .InsertReceiptChain (blocks , receipts , uint64 (3 * len (blocks )/ 4 )); err != nil {
1733
+ t .Fatalf ("failed to insert receipt %d: %v" , n , err )
1734
+ }
1735
+ if ancient .CurrentFastBlock ().NumberU64 () != blocks [len (blocks )- 1 ].NumberU64 () {
1736
+ t .Fatalf ("failed to insert ancient recept chain after rollback" )
1737
+ }
1738
+ }
1739
+
1567
1740
// Tests that importing a very large side fork, which is larger than the canon chain,
1568
1741
// but where the difficulty per block is kept low: this means that it will not
1569
1742
// overtake the 'canon' chain until after it's passed canon by about 200 blocks.
@@ -1764,7 +1937,7 @@ func testInsertKnownChainData(t *testing.T, typ string) {
1764
1937
if err != nil {
1765
1938
return err
1766
1939
}
1767
- _ , err = chain .InsertReceiptChain (blocks , receipts )
1940
+ _ , err = chain .InsertReceiptChain (blocks , receipts , 0 )
1768
1941
return err
1769
1942
}
1770
1943
asserter = func (t * testing.T , block * types.Block ) {
@@ -2019,14 +2192,12 @@ func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) {
2019
2192
numTxs = 1000
2020
2193
numBlocks = 1
2021
2194
)
2022
-
2023
2195
recipientFn := func (nonce uint64 ) common.Address {
2024
2196
return common .BigToAddress (big .NewInt (0 ).SetUint64 (1337 + nonce ))
2025
2197
}
2026
2198
dataFn := func (nonce uint64 ) []byte {
2027
2199
return nil
2028
2200
}
2029
-
2030
2201
benchmarkLargeNumberOfValueToNonexisting (b , numTxs , numBlocks , recipientFn , dataFn )
2031
2202
}
2032
2203
@@ -2044,7 +2215,6 @@ func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) {
2044
2215
dataFn := func (nonce uint64 ) []byte {
2045
2216
return nil
2046
2217
}
2047
-
2048
2218
benchmarkLargeNumberOfValueToNonexisting (b , numTxs , numBlocks , recipientFn , dataFn )
2049
2219
}
2050
2220
@@ -2062,6 +2232,5 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
2062
2232
dataFn := func (nonce uint64 ) []byte {
2063
2233
return nil
2064
2234
}
2065
-
2066
2235
benchmarkLargeNumberOfValueToNonexisting (b , numTxs , numBlocks , recipientFn , dataFn )
2067
2236
}
0 commit comments