mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
light: CHT/BBT indexers working in light mode
This commit is contained in:
parent
040aa2bb10
commit
f70f63949d
15 changed files with 220 additions and 58 deletions
|
|
@ -45,6 +45,17 @@ type ChainIndexerBackend interface {
|
||||||
|
|
||||||
// Commit finalizes the section metadata and stores it into the database.
|
// Commit finalizes the section metadata and stores it into the database.
|
||||||
Commit() error
|
Commit() error
|
||||||
|
|
||||||
|
// Closing signals the backend about the indexer shutting down. After Closing
|
||||||
|
// is called the backend should not block waiting for any external events and
|
||||||
|
// may return with an error if it cannot finish the current operation. If there
|
||||||
|
// are no blocking operations and result is guaranteed in a limited time then
|
||||||
|
// Closing can be ignored.
|
||||||
|
//
|
||||||
|
// Note: Closing may be called during any phase of section processing or also
|
||||||
|
// when no processing is happening at all. It applies to all current and
|
||||||
|
// subsequent blocking operations.
|
||||||
|
Closing()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainIndexerChain interface is used for connecting the indexer to a blockchain
|
// ChainIndexerChain interface is used for connecting the indexer to a blockchain
|
||||||
|
|
@ -138,6 +149,8 @@ func (c *ChainIndexer) Start(chain ChainIndexerChain) {
|
||||||
func (c *ChainIndexer) Close() error {
|
func (c *ChainIndexer) Close() error {
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
|
c.backend.Closing()
|
||||||
|
|
||||||
// Tear down the primary update loop
|
// Tear down the primary update loop
|
||||||
errc := make(chan error)
|
errc := make(chan error)
|
||||||
c.quit <- errc
|
c.quit <- errc
|
||||||
|
|
|
||||||
|
|
@ -235,3 +235,5 @@ func (b *testChainIndexBackend) Commit() error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *testChainIndexBackend) Closing() {}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
gasPrice: config.GasPrice,
|
gasPrice: config.GasPrice,
|
||||||
etherbase: config.Etherbase,
|
etherbase: config.Etherbase,
|
||||||
bloomRequests: make(chan chan *bloombits.Retrieval),
|
bloomRequests: make(chan chan *bloombits.Retrieval),
|
||||||
bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks),
|
bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, bloomConfirms),
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId)
|
log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId)
|
||||||
|
|
|
||||||
|
|
@ -103,14 +103,14 @@ type BloomIndexer struct {
|
||||||
|
|
||||||
// NewBloomIndexer returns a chain indexer that generates bloom bits data for the
|
// NewBloomIndexer returns a chain indexer that generates bloom bits data for the
|
||||||
// canonical chain for fast logs filtering.
|
// canonical chain for fast logs filtering.
|
||||||
func NewBloomIndexer(db ethdb.Database, size uint64) *core.ChainIndexer {
|
func NewBloomIndexer(db ethdb.Database, size, confReq uint64) *core.ChainIndexer {
|
||||||
backend := &BloomIndexer{
|
backend := &BloomIndexer{
|
||||||
db: db,
|
db: db,
|
||||||
size: size,
|
size: size,
|
||||||
}
|
}
|
||||||
table := ethdb.NewTable(db, string(rawdb.BloomBitsIndexPrefix))
|
table := ethdb.NewTable(db, string(rawdb.BloomBitsIndexPrefix))
|
||||||
|
|
||||||
return core.NewChainIndexer(db, table, backend, size, bloomConfirms, bloomThrottling, "bloombits")
|
return core.NewChainIndexer(db, table, backend, size, confReq, bloomThrottling, "bloombits")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset implements core.ChainIndexerBackend, starting a new bloombits index
|
// Reset implements core.ChainIndexerBackend, starting a new bloombits index
|
||||||
|
|
@ -142,3 +142,6 @@ func (b *BloomIndexer) Commit() error {
|
||||||
}
|
}
|
||||||
return batch.Write()
|
return batch.Write()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel implements core.ChainIndexerBackend
|
||||||
|
func (b *BloomIndexer) Closing() {}
|
||||||
|
|
|
||||||
|
|
@ -106,18 +106,24 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
|
||||||
shutdownChan: make(chan bool),
|
shutdownChan: make(chan bool),
|
||||||
networkId: config.NetworkId,
|
networkId: config.NetworkId,
|
||||||
bloomRequests: make(chan chan *bloombits.Retrieval),
|
bloomRequests: make(chan chan *bloombits.Retrieval),
|
||||||
bloomIndexer: eth.NewBloomIndexer(chainDb, light.BloomTrieFrequency),
|
bloomIndexer: eth.NewBloomIndexer(chainDb, light.BloomTrieFrequency, light.HelperTrieConfirmations),
|
||||||
chtIndexer: light.NewChtIndexer(chainDb, true),
|
|
||||||
bloomTrieIndexer: light.NewBloomTrieIndexer(chainDb, true),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
leth.relay = NewLesTxRelay(peers, leth.reqDist)
|
leth.relay = NewLesTxRelay(peers, leth.reqDist)
|
||||||
leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg)
|
leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg)
|
||||||
leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool)
|
leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool)
|
||||||
leth.odr = NewLesOdr(chainDb, leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer, leth.retriever)
|
leth.odr = NewLesOdr(chainDb, leth.retriever)
|
||||||
|
leth.chtIndexer = light.NewChtIndexer(chainDb, true, leth.odr)
|
||||||
|
leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, true, leth.odr)
|
||||||
|
leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer)
|
||||||
|
// Note: NewLightChain adds the trusted checkpoint so it needs an ODR with
|
||||||
|
// indexers already set but not started yet
|
||||||
if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine); err != nil {
|
if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// Note: AddChildIndexer starts the update process for the child
|
||||||
|
leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer)
|
||||||
|
leth.chtIndexer.Start(leth.blockchain)
|
||||||
leth.bloomIndexer.Start(leth.blockchain)
|
leth.bloomIndexer.Start(leth.blockchain)
|
||||||
// Rewind the chain in case of an incompatible config upgrade.
|
// Rewind the chain in case of an incompatible config upgrade.
|
||||||
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
||||||
|
|
@ -242,9 +248,6 @@ func (s *LightEthereum) Stop() error {
|
||||||
if s.chtIndexer != nil {
|
if s.chtIndexer != nil {
|
||||||
s.chtIndexer.Close()
|
s.chtIndexer.Close()
|
||||||
}
|
}
|
||||||
if s.bloomTrieIndexer != nil {
|
|
||||||
s.bloomTrieIndexer.Close()
|
|
||||||
}
|
|
||||||
s.blockchain.Stop()
|
s.blockchain.Stop()
|
||||||
s.protocolManager.Stop()
|
s.protocolManager.Stop()
|
||||||
s.txPool.Stop()
|
s.txPool.Stop()
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,10 @@ package les
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"errors"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNoPeers is returned if no peers capable of serving a queued request are available
|
|
||||||
var ErrNoPeers = errors.New("no suitable peers available")
|
|
||||||
|
|
||||||
// requestDistributor implements a mechanism that distributes requests to
|
// requestDistributor implements a mechanism that distributes requests to
|
||||||
// suitable peers, obeying flow control rules and prioritizing them in creation
|
// suitable peers, obeying flow control rules and prioritizing them in creation
|
||||||
// order (even when a resend is necessary).
|
// order (even when a resend is necessary).
|
||||||
|
|
|
||||||
|
|
@ -1258,7 +1258,7 @@ func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, s
|
||||||
}
|
}
|
||||||
_, ok := <-pc.manager.reqDist.queue(rq)
|
_, ok := <-pc.manager.reqDist.queue(rq)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNoPeers
|
return light.ErrNoPeers
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1282,7 +1282,7 @@ func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip
|
||||||
}
|
}
|
||||||
_, ok := <-pc.manager.reqDist.queue(rq)
|
_, ok := <-pc.manager.reqDist.queue(rq)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNoPeers
|
return light.ErrNoPeers
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -156,12 +156,12 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
|
||||||
} else {
|
} else {
|
||||||
blockchain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{})
|
blockchain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{})
|
||||||
|
|
||||||
chtIndexer := light.NewChtIndexer(db, false)
|
chtIndexer := light.NewChtIndexer(db, false, nil)
|
||||||
chtIndexer.Start(blockchain)
|
chtIndexer.Start(blockchain)
|
||||||
|
|
||||||
bbtIndexer := light.NewBloomTrieIndexer(db, false)
|
bbtIndexer := light.NewBloomTrieIndexer(db, false, nil)
|
||||||
|
|
||||||
bloomIndexer := eth.NewBloomIndexer(db, params.BloomBitsBlocks)
|
bloomIndexer := eth.NewBloomIndexer(db, params.BloomBitsBlocks, light.HelperTrieProcessConfirmations)
|
||||||
bloomIndexer.AddChildIndexer(bbtIndexer)
|
bloomIndexer.AddChildIndexer(bbtIndexer)
|
||||||
bloomIndexer.Start(blockchain)
|
bloomIndexer.Start(blockchain)
|
||||||
|
|
||||||
|
|
|
||||||
12
les/odr.go
12
les/odr.go
|
|
@ -33,12 +33,9 @@ type LesOdr struct {
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLesOdr(db ethdb.Database, chtIndexer, bloomTrieIndexer, bloomIndexer *core.ChainIndexer, retriever *retrieveManager) *LesOdr {
|
func NewLesOdr(db ethdb.Database, retriever *retrieveManager) *LesOdr {
|
||||||
return &LesOdr{
|
return &LesOdr{
|
||||||
db: db,
|
db: db,
|
||||||
chtIndexer: chtIndexer,
|
|
||||||
bloomTrieIndexer: bloomTrieIndexer,
|
|
||||||
bloomIndexer: bloomIndexer,
|
|
||||||
retriever: retriever,
|
retriever: retriever,
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
@ -54,6 +51,13 @@ func (odr *LesOdr) Database() ethdb.Database {
|
||||||
return odr.db
|
return odr.db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIndexers adds the necessary chain indexers to the ODR backend
|
||||||
|
func (odr *LesOdr) SetIndexers(chtIndexer, bloomTrieIndexer, bloomIndexer *core.ChainIndexer) {
|
||||||
|
odr.chtIndexer = chtIndexer
|
||||||
|
odr.bloomTrieIndexer = bloomTrieIndexer
|
||||||
|
odr.bloomIndexer = bloomIndexer
|
||||||
|
}
|
||||||
|
|
||||||
// ChtIndexer returns the CHT chain indexer
|
// ChtIndexer returns the CHT chain indexer
|
||||||
func (odr *LesOdr) ChtIndexer() *core.ChainIndexer {
|
func (odr *LesOdr) ChtIndexer() *core.ChainIndexer {
|
||||||
return odr.chtIndexer
|
return odr.chtIndexer
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,8 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
|
||||||
rm := newRetrieveManager(peers, dist, nil)
|
rm := newRetrieveManager(peers, dist, nil)
|
||||||
db := ethdb.NewMemDatabase()
|
db := ethdb.NewMemDatabase()
|
||||||
ldb := ethdb.NewMemDatabase()
|
ldb := ethdb.NewMemDatabase()
|
||||||
odr := NewLesOdr(ldb, light.NewChtIndexer(db, true), light.NewBloomTrieIndexer(db, true), eth.NewBloomIndexer(db, light.BloomTrieFrequency), rm)
|
odr := NewLesOdr(ldb, rm)
|
||||||
|
odr.SetIndexers(light.NewChtIndexer(db, true, nil), light.NewBloomTrieIndexer(db, true, nil), eth.NewBloomIndexer(db, light.BloomTrieFrequency, light.HelperTrieConfirmations))
|
||||||
pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
|
pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
|
||||||
lpm := newTestProtocolManagerMust(t, true, 0, nil, peers, odr, ldb)
|
lpm := newTestProtocolManagerMust(t, true, 0, nil, peers, odr, ldb)
|
||||||
_, err1, lpeer, err2 := newTestPeerPair("peer", protocol, pm, lpm)
|
_, err1, lpeer, err2 := newTestPeerPair("peer", protocol, pm, lpm)
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,8 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) {
|
||||||
rm := newRetrieveManager(peers, dist, nil)
|
rm := newRetrieveManager(peers, dist, nil)
|
||||||
db := ethdb.NewMemDatabase()
|
db := ethdb.NewMemDatabase()
|
||||||
ldb := ethdb.NewMemDatabase()
|
ldb := ethdb.NewMemDatabase()
|
||||||
odr := NewLesOdr(ldb, light.NewChtIndexer(db, true), light.NewBloomTrieIndexer(db, true), eth.NewBloomIndexer(db, light.BloomTrieFrequency), rm)
|
odr := NewLesOdr(ldb, rm)
|
||||||
|
odr.SetIndexers(light.NewChtIndexer(db, true, nil), light.NewBloomTrieIndexer(db, true, nil), eth.NewBloomIndexer(db, light.BloomTrieFrequency, light.HelperTrieConfirmations))
|
||||||
|
|
||||||
pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
|
pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
|
||||||
lpm := newTestProtocolManagerMust(t, true, 0, nil, peers, odr, ldb)
|
lpm := newTestProtocolManagerMust(t, true, 0, nil, peers, odr, ldb)
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
|
"github.com/ethereum/go-ethereum/light"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -207,7 +208,7 @@ func (r *sentReq) stateRequesting() reqStateFn {
|
||||||
return r.stateNoMorePeers
|
return r.stateNoMorePeers
|
||||||
}
|
}
|
||||||
// nothing to wait for, no more peers to ask, return with error
|
// nothing to wait for, no more peers to ask, return with error
|
||||||
r.stop(ErrNoPeers)
|
r.stop(light.ErrNoPeers)
|
||||||
// no need to go to stopped state because waiting() already returned false
|
// no need to go to stopped state because waiting() already returned false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,8 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
|
||||||
protocolManager: pm,
|
protocolManager: pm,
|
||||||
quitSync: quitSync,
|
quitSync: quitSync,
|
||||||
lesTopics: lesTopics,
|
lesTopics: lesTopics,
|
||||||
chtIndexer: light.NewChtIndexer(eth.ChainDb(), false),
|
chtIndexer: light.NewChtIndexer(eth.ChainDb(), false, nil),
|
||||||
bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), false),
|
bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), false, nil),
|
||||||
}
|
}
|
||||||
logger := log.New()
|
logger := log.New()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package light
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -33,6 +34,9 @@ import (
|
||||||
// service is not required.
|
// service is not required.
|
||||||
var NoOdr = context.Background()
|
var NoOdr = context.Background()
|
||||||
|
|
||||||
|
// ErrNoPeers is returned if no peers capable of serving a queued request are available
|
||||||
|
var ErrNoPeers = errors.New("no suitable peers available")
|
||||||
|
|
||||||
// OdrBackend is an interface to a backend service that handles ODR retrievals type
|
// OdrBackend is an interface to a backend service that handles ODR retrievals type
|
||||||
type OdrBackend interface {
|
type OdrBackend interface {
|
||||||
Database() ethdb.Database
|
Database() ethdb.Database
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,10 @@
|
||||||
package light
|
package light
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -119,15 +121,17 @@ func StoreChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root common
|
||||||
|
|
||||||
// ChtIndexerBackend implements core.ChainIndexerBackend
|
// ChtIndexerBackend implements core.ChainIndexerBackend
|
||||||
type ChtIndexerBackend struct {
|
type ChtIndexerBackend struct {
|
||||||
diskdb ethdb.Database
|
diskdb, trieTable ethdb.Database
|
||||||
|
odr OdrBackend
|
||||||
triedb *trie.Database
|
triedb *trie.Database
|
||||||
section, sectionSize uint64
|
section, sectionSize uint64
|
||||||
lastHash common.Hash
|
lastHash common.Hash
|
||||||
trie *trie.Trie
|
trie *trie.Trie
|
||||||
|
quit chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBloomTrieIndexer creates a BloomTrie chain indexer
|
// NewBloomTrieIndexer creates a BloomTrie chain indexer
|
||||||
func NewChtIndexer(db ethdb.Database, clientMode bool) *core.ChainIndexer {
|
func NewChtIndexer(db ethdb.Database, clientMode bool, odr OdrBackend) *core.ChainIndexer {
|
||||||
var sectionSize, confirmReq uint64
|
var sectionSize, confirmReq uint64
|
||||||
if clientMode {
|
if clientMode {
|
||||||
sectionSize = CHTFrequencyClient
|
sectionSize = CHTFrequencyClient
|
||||||
|
|
@ -137,14 +141,55 @@ func NewChtIndexer(db ethdb.Database, clientMode bool) *core.ChainIndexer {
|
||||||
confirmReq = HelperTrieProcessConfirmations
|
confirmReq = HelperTrieProcessConfirmations
|
||||||
}
|
}
|
||||||
idb := ethdb.NewTable(db, "chtIndex-")
|
idb := ethdb.NewTable(db, "chtIndex-")
|
||||||
|
trieTable := ethdb.NewTable(db, ChtTablePrefix)
|
||||||
backend := &ChtIndexerBackend{
|
backend := &ChtIndexerBackend{
|
||||||
diskdb: db,
|
diskdb: db,
|
||||||
triedb: trie.NewDatabase(ethdb.NewTable(db, ChtTablePrefix)),
|
odr: odr,
|
||||||
|
trieTable: trieTable,
|
||||||
|
triedb: trie.NewDatabase(trieTable),
|
||||||
sectionSize: sectionSize,
|
sectionSize: sectionSize,
|
||||||
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
return core.NewChainIndexer(db, idb, backend, sectionSize, confirmReq, time.Millisecond*100, "cht")
|
return core.NewChainIndexer(db, idb, backend, sectionSize, confirmReq, time.Millisecond*100, "cht")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fetchMissingNodes tries to retrieve the last entry of the latest trusted CHT from the
|
||||||
|
// ODR backend in order to be able to add new entries and calculate subsequent root hashes
|
||||||
|
func (c *ChtIndexerBackend) fetchMissingNodes(section uint64, root common.Hash) error {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-c.quit:
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
defer close(done)
|
||||||
|
|
||||||
|
batch := c.trieTable.NewBatch()
|
||||||
|
r := &ChtRequest{ChtRoot: root, ChtNum: section - 1, BlockNum: section*c.sectionSize - 1}
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
err = c.odr.Retrieve(ctx, r)
|
||||||
|
if err == ErrNoPeers {
|
||||||
|
// if there are no peers to serve, retry later
|
||||||
|
select {
|
||||||
|
case <-c.quit:
|
||||||
|
return fmt.Errorf("Section processing cancelled")
|
||||||
|
case <-time.After(time.Second * 10):
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
r.Proof.Store(batch)
|
||||||
|
err = batch.Write()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Reset implements core.ChainIndexerBackend
|
// Reset implements core.ChainIndexerBackend
|
||||||
func (c *ChtIndexerBackend) Reset(section uint64, lastSectionHead common.Hash) error {
|
func (c *ChtIndexerBackend) Reset(section uint64, lastSectionHead common.Hash) error {
|
||||||
var root common.Hash
|
var root common.Hash
|
||||||
|
|
@ -153,6 +198,14 @@ func (c *ChtIndexerBackend) Reset(section uint64, lastSectionHead common.Hash) e
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
c.trie, err = trie.New(root, c.triedb)
|
c.trie, err = trie.New(root, c.triedb)
|
||||||
|
|
||||||
|
if err != nil && c.odr != nil {
|
||||||
|
err = c.fetchMissingNodes(section, root)
|
||||||
|
if err == nil {
|
||||||
|
c.trie, err = trie.New(root, c.triedb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.section = section
|
c.section = section
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -181,16 +234,20 @@ func (c *ChtIndexerBackend) Commit() error {
|
||||||
c.triedb.Commit(root, false)
|
c.triedb.Commit(root, false)
|
||||||
|
|
||||||
if ((c.section+1)*c.sectionSize)%CHTFrequencyClient == 0 {
|
if ((c.section+1)*c.sectionSize)%CHTFrequencyClient == 0 {
|
||||||
log.Info("Storing CHT", "section", c.section*c.sectionSize/CHTFrequencyClient, "head", c.lastHash, "root", root)
|
log.Info("Storing CHT", "section", c.section*c.sectionSize/CHTFrequencyClient, "head", fmt.Sprintf("%064x", c.lastHash), "root", fmt.Sprintf("%064x", root))
|
||||||
}
|
}
|
||||||
StoreChtRoot(c.diskdb, c.section, c.lastHash, root)
|
StoreChtRoot(c.diskdb, c.section, c.lastHash, root)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel implements core.ChainIndexerBackend
|
||||||
|
func (c *ChtIndexerBackend) Closing() {
|
||||||
|
close(c.quit)
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BloomTrieFrequency = 32768
|
BloomTrieFrequency = 32768
|
||||||
ethBloomBitsSection = 4096
|
ethBloomBitsSection = 4096
|
||||||
ethBloomBitsConfirmations = 256
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -215,32 +272,98 @@ func StoreBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root
|
||||||
|
|
||||||
// BloomTrieIndexerBackend implements core.ChainIndexerBackend
|
// BloomTrieIndexerBackend implements core.ChainIndexerBackend
|
||||||
type BloomTrieIndexerBackend struct {
|
type BloomTrieIndexerBackend struct {
|
||||||
diskdb ethdb.Database
|
diskdb, trieTable ethdb.Database
|
||||||
|
odr OdrBackend
|
||||||
triedb *trie.Database
|
triedb *trie.Database
|
||||||
section, parentSectionSize, bloomTrieRatio uint64
|
section, parentSectionSize, bloomTrieRatio uint64
|
||||||
trie *trie.Trie
|
trie *trie.Trie
|
||||||
sectionHeads []common.Hash
|
sectionHeads []common.Hash
|
||||||
|
quit chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBloomTrieIndexer creates a BloomTrie chain indexer
|
// NewBloomTrieIndexer creates a BloomTrie chain indexer
|
||||||
func NewBloomTrieIndexer(db ethdb.Database, clientMode bool) *core.ChainIndexer {
|
func NewBloomTrieIndexer(db ethdb.Database, clientMode bool, odr OdrBackend) *core.ChainIndexer {
|
||||||
|
trieTable := ethdb.NewTable(db, BloomTrieTablePrefix)
|
||||||
backend := &BloomTrieIndexerBackend{
|
backend := &BloomTrieIndexerBackend{
|
||||||
diskdb: db,
|
diskdb: db,
|
||||||
triedb: trie.NewDatabase(ethdb.NewTable(db, BloomTrieTablePrefix)),
|
odr: odr,
|
||||||
|
trieTable: trieTable,
|
||||||
|
triedb: trie.NewDatabase(trieTable),
|
||||||
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
idb := ethdb.NewTable(db, "bltIndex-")
|
idb := ethdb.NewTable(db, "bltIndex-")
|
||||||
|
|
||||||
var confirmReq uint64
|
|
||||||
if clientMode {
|
if clientMode {
|
||||||
backend.parentSectionSize = BloomTrieFrequency
|
backend.parentSectionSize = BloomTrieFrequency
|
||||||
confirmReq = HelperTrieConfirmations
|
|
||||||
} else {
|
} else {
|
||||||
backend.parentSectionSize = ethBloomBitsSection
|
backend.parentSectionSize = ethBloomBitsSection
|
||||||
confirmReq = HelperTrieProcessConfirmations
|
|
||||||
}
|
}
|
||||||
backend.bloomTrieRatio = BloomTrieFrequency / backend.parentSectionSize
|
backend.bloomTrieRatio = BloomTrieFrequency / backend.parentSectionSize
|
||||||
backend.sectionHeads = make([]common.Hash, backend.bloomTrieRatio)
|
backend.sectionHeads = make([]common.Hash, backend.bloomTrieRatio)
|
||||||
return core.NewChainIndexer(db, idb, backend, BloomTrieFrequency, confirmReq-ethBloomBitsConfirmations, time.Millisecond*100, "bloomtrie")
|
return core.NewChainIndexer(db, idb, backend, BloomTrieFrequency, 0, time.Millisecond*100, "bloomtrie")
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchMissingNodes tries to retrieve the last entries of the latest trusted bloom trie from the
|
||||||
|
// ODR backend in order to be able to add new entries and calculate subsequent root hashes
|
||||||
|
func (b *BloomTrieIndexerBackend) fetchMissingNodes(section uint64, root common.Hash) error {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-b.quit:
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
defer close(done)
|
||||||
|
|
||||||
|
indexCh := make(chan uint, types.BloomBitLength)
|
||||||
|
type res struct {
|
||||||
|
nodes *NodeSet
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
resCh := make(chan res, types.BloomBitLength)
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
bitIndex, ok := <-indexCh
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r := &BloomRequest{BloomTrieRoot: root, BloomTrieNum: section - 1, BitIdx: bitIndex, SectionIdxList: []uint64{section - 1}}
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
err = b.odr.Retrieve(ctx, r)
|
||||||
|
if err == ErrNoPeers {
|
||||||
|
// if there are no peers to serve, retry later
|
||||||
|
select {
|
||||||
|
case <-b.quit:
|
||||||
|
resCh <- res{nil, fmt.Errorf("Section processing cancelled")}
|
||||||
|
return
|
||||||
|
case <-time.After(time.Second * 10):
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resCh <- res{r.Proofs, err}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint(0); i < types.BloomBitLength; i++ {
|
||||||
|
indexCh <- i
|
||||||
|
}
|
||||||
|
close(indexCh)
|
||||||
|
batch := b.trieTable.NewBatch()
|
||||||
|
for i := uint(0); i < types.BloomBitLength; i++ {
|
||||||
|
res := <-resCh
|
||||||
|
if res.err != nil {
|
||||||
|
return res.err
|
||||||
|
}
|
||||||
|
res.nodes.Store(batch)
|
||||||
|
}
|
||||||
|
return batch.Write()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset implements core.ChainIndexerBackend
|
// Reset implements core.ChainIndexerBackend
|
||||||
|
|
@ -251,6 +374,12 @@ func (b *BloomTrieIndexerBackend) Reset(section uint64, lastSectionHead common.H
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
b.trie, err = trie.New(root, b.triedb)
|
b.trie, err = trie.New(root, b.triedb)
|
||||||
|
if err != nil && b.odr != nil {
|
||||||
|
err = b.fetchMissingNodes(section, root)
|
||||||
|
if err == nil {
|
||||||
|
b.trie, err = trie.New(root, b.triedb)
|
||||||
|
}
|
||||||
|
}
|
||||||
b.section = section
|
b.section = section
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -300,8 +429,13 @@ func (b *BloomTrieIndexerBackend) Commit() error {
|
||||||
b.triedb.Commit(root, false)
|
b.triedb.Commit(root, false)
|
||||||
|
|
||||||
sectionHead := b.sectionHeads[b.bloomTrieRatio-1]
|
sectionHead := b.sectionHeads[b.bloomTrieRatio-1]
|
||||||
log.Info("Storing bloom trie", "section", b.section, "head", sectionHead, "root", root, "compression", float64(compSize)/float64(decompSize))
|
log.Info("Storing bloom trie", "section", b.section, "head", fmt.Sprintf("%064x", sectionHead), "root", fmt.Sprintf("%064x", root), "compression", float64(compSize)/float64(decompSize))
|
||||||
StoreBloomTrieRoot(b.diskdb, b.section, sectionHead, root)
|
StoreBloomTrieRoot(b.diskdb, b.section, sectionHead, root)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel implements core.ChainIndexerBackend
|
||||||
|
func (b *BloomTrieIndexerBackend) Closing() {
|
||||||
|
close(b.quit)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue