Skip to content

Commit 80469be

Browse files
rjl493456442karalabe
authored andcommitted
all: integrate the freezer with fast sync
* all: freezer style syncing core, eth, les, light: clean up freezer relative APIs core, eth, les, trie, ethdb, light: clean a bit core, eth, les, light: add unit tests core, light: rewrite setHead function core, eth: fix downloader unit tests core: add receipt chain insertion test core: use constant instead of hardcoding table name core: fix rollback core: fix setHead core/rawdb: remove canonical block first and then iterate side chain core/rawdb, ethdb: add hasAncient interface eth/downloader: calculate ancient limit via cht first core, eth, ethdb: lots of fixes * eth/downloader: print ancient disable log only for fast sync
1 parent b6cac42 commit 80469be

26 files changed

+1068
-318
lines changed

core/blockchain.go

+299-84
Large diffs are not rendered by default.

core/blockchain_test.go

+190-21
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ package core
1818

1919
import (
2020
"fmt"
21+
"io/ioutil"
2122
"math/big"
2223
"math/rand"
24+
"os"
2325
"sync"
2426
"testing"
2527
"time"
@@ -33,7 +35,6 @@ import (
3335
"github.com/ethereum/go-ethereum/core/vm"
3436
"github.com/ethereum/go-ethereum/crypto"
3537
"github.com/ethereum/go-ethereum/ethdb"
36-
"github.com/ethereum/go-ethereum/ethdb/memorydb"
3738
"github.com/ethereum/go-ethereum/params"
3839
)
3940

@@ -639,34 +640,63 @@ func TestFastVsFullChains(t *testing.T) {
639640
if n, err := fast.InsertHeaderChain(headers, 1); err != nil {
640641
t.Fatalf("failed to insert header %d: %v", n, err)
641642
}
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 {
643664
t.Fatalf("failed to insert receipt %d: %v", n, err)
644665
}
645666
// Iterate over all chain data components, and cross reference
646667
for i := 0; i < len(blocks); i++ {
647668
num, hash := blocks[i].NumberU64(), blocks[i].Hash()
648669

649670
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)
651675
}
652676
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)
654681
}
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())
661688
}
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)
664691
}
665692
}
666693
// Check that the canonical chains are the same between the databases
667694
for i := 0; i < len(blocks)+1; i++ {
668695
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)
670700
}
671701
}
672702
}
@@ -730,13 +760,40 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
730760
if n, err := fast.InsertHeaderChain(headers, 1); err != nil {
731761
t.Fatalf("failed to insert header %d: %v", n, err)
732762
}
733-
if n, err := fast.InsertReceiptChain(blocks, receipts); err != nil {
763+
if n, err := fast.InsertReceiptChain(blocks, receipts, 0); err != nil {
734764
t.Fatalf("failed to insert receipt %d: %v", n, err)
735765
}
736766
assert(t, "fast", fast, height, height, 0)
737767
fast.Rollback(remove)
738768
assert(t, "fast", fast, height/2, height/2, 0)
739769

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+
740797
// Import the chain as a light node and ensure all pointers are updated
741798
lightDb := rawdb.NewMemoryDatabase()
742799
gspec.MustCommit(lightDb)
@@ -918,7 +975,7 @@ func TestLogRebirth(t *testing.T) {
918975
var (
919976
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
920977
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
921-
db = memorydb.New()
978+
db = rawdb.NewMemoryDatabase()
922979

923980
// this code generates a log
924981
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
@@ -1040,7 +1097,7 @@ func TestSideLogRebirth(t *testing.T) {
10401097
var (
10411098
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
10421099
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
1043-
db = memorydb.New()
1100+
db = rawdb.NewMemoryDatabase()
10441101

10451102
// this code generates a log
10461103
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
@@ -1564,6 +1621,122 @@ func TestLargeReorgTrieGC(t *testing.T) {
15641621
}
15651622
}
15661623

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+
15671740
// Tests that importing a very large side fork, which is larger than the canon chain,
15681741
// but where the difficulty per block is kept low: this means that it will not
15691742
// 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) {
17641937
if err != nil {
17651938
return err
17661939
}
1767-
_, err = chain.InsertReceiptChain(blocks, receipts)
1940+
_, err = chain.InsertReceiptChain(blocks, receipts, 0)
17681941
return err
17691942
}
17701943
asserter = func(t *testing.T, block *types.Block) {
@@ -2019,14 +2192,12 @@ func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) {
20192192
numTxs = 1000
20202193
numBlocks = 1
20212194
)
2022-
20232195
recipientFn := func(nonce uint64) common.Address {
20242196
return common.BigToAddress(big.NewInt(0).SetUint64(1337 + nonce))
20252197
}
20262198
dataFn := func(nonce uint64) []byte {
20272199
return nil
20282200
}
2029-
20302201
benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
20312202
}
20322203

@@ -2044,7 +2215,6 @@ func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) {
20442215
dataFn := func(nonce uint64) []byte {
20452216
return nil
20462217
}
2047-
20482218
benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
20492219
}
20502220

@@ -2062,6 +2232,5 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
20622232
dataFn := func(nonce uint64) []byte {
20632233
return nil
20642234
}
2065-
20662235
benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
20672236
}

0 commit comments

Comments
 (0)