diff options
Diffstat (limited to 'light')
-rw-r--r-- | light/lightchain.go | 30 | ||||
-rw-r--r-- | light/lightchain_test.go | 6 | ||||
-rw-r--r-- | light/odr.go | 22 | ||||
-rw-r--r-- | light/odr_test.go | 2 | ||||
-rw-r--r-- | light/odr_util.go | 34 | ||||
-rw-r--r-- | light/txpool_test.go | 2 |
6 files changed, 69 insertions, 27 deletions
diff --git a/light/lightchain.go b/light/lightchain.go index f0beec47b..7f64d1c28 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -77,7 +77,7 @@ type LightChain struct { // NewLightChain returns a fully initialised light chain using information // available in the database. It initialises the default Ethereum header // validator. -func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine) (*LightChain, error) { +func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, checkpoint *params.TrustedCheckpoint) (*LightChain, error) { bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) blockCache, _ := lru.New(blockCacheLimit) @@ -101,8 +101,8 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. if bc.genesisBlock == nil { return nil, core.ErrNoGenesis } - if cp, ok := params.TrustedCheckpoints[bc.genesisBlock.Hash()]; ok { - bc.addTrustedCheckpoint(cp) + if checkpoint != nil { + bc.AddTrustedCheckpoint(checkpoint) } if err := bc.loadLastState(); err != nil { return nil, err @@ -118,8 +118,8 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. return bc, nil } -// addTrustedCheckpoint adds a trusted checkpoint to the blockchain -func (lc *LightChain) addTrustedCheckpoint(cp *params.TrustedCheckpoint) { +// AddTrustedCheckpoint adds a trusted checkpoint to the blockchain +func (lc *LightChain) AddTrustedCheckpoint(cp *params.TrustedCheckpoint) { if lc.odr.ChtIndexer() != nil { StoreChtRoot(lc.chainDb, cp.SectionIndex, cp.SectionHead, cp.CHTRoot) lc.odr.ChtIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) @@ -131,7 +131,7 @@ func (lc *LightChain) addTrustedCheckpoint(cp *params.TrustedCheckpoint) { if lc.odr.BloomIndexer() != nil { lc.odr.BloomIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) } - log.Info("Added trusted checkpoint", "chain", cp.Name, "block", (cp.SectionIndex+1)*lc.indexerConfig.ChtSize-1, "hash", cp.SectionHead) + log.Info("Added trusted checkpoint", "block", (cp.SectionIndex+1)*lc.indexerConfig.ChtSize-1, "hash", cp.SectionHead) } func (lc *LightChain) getProcInterrupt() bool { @@ -462,21 +462,21 @@ func (lc *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) ( // Config retrieves the header chain's chain configuration. func (lc *LightChain) Config() *params.ChainConfig { return lc.hc.Config() } -func (lc *LightChain) SyncCht(ctx context.Context) bool { - // If we don't have a CHT indexer, abort - if lc.odr.ChtIndexer() == nil { - return false - } - // Ensure the remote CHT head is ahead of us +// SyncCheckpoint fetches the checkpoint point block header according to +// the checkpoint provided by the remote peer. +// +// Note if we are running the clique, fetches the last epoch snapshot header +// which covered by checkpoint. +func (lc *LightChain) SyncCheckpoint(ctx context.Context, checkpoint *params.TrustedCheckpoint) bool { + // Ensure the remote checkpoint head is ahead of us head := lc.CurrentHeader().Number.Uint64() - sections, _, _ := lc.odr.ChtIndexer().Sections() - latest := sections*lc.indexerConfig.ChtSize - 1 + latest := (checkpoint.SectionIndex+1)*lc.indexerConfig.ChtSize - 1 if clique := lc.hc.Config().Clique; clique != nil { latest -= latest % clique.Epoch // epoch snapshot for clique } if head >= latest { - return false + return true } // Retrieve the latest useful header and update to it if header, err := GetHeaderByNumber(ctx, lc.odr, latest); header != nil && err == nil { diff --git a/light/lightchain_test.go b/light/lightchain_test.go index 58ea93044..70d2e70c1 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -55,7 +55,7 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) { db := rawdb.NewMemoryDatabase() gspec := core.Genesis{Config: params.TestChainConfig} genesis := gspec.MustCommit(db) - blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker()) + blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker(), nil) // Create and inject the requested chain if n == 0 { @@ -75,7 +75,7 @@ func newTestLightChain() *LightChain { Config: params.TestChainConfig, } gspec.MustCommit(db) - lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker()) + lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), nil) if err != nil { panic(err) } @@ -344,7 +344,7 @@ func TestReorgBadHeaderHashes(t *testing.T) { defer func() { delete(core.BadHashes, headers[3].Hash()) }() // Create a new LightChain and check that it rolled back the state. - ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker()) + ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } diff --git a/light/odr.go b/light/odr.go index d1185e4e0..907712ede 100644 --- a/light/odr.go +++ b/light/odr.go @@ -122,19 +122,25 @@ func (req *BlockRequest) StoreResult(db ethdb.Database) { // ReceiptsRequest is the ODR request type for retrieving block bodies type ReceiptsRequest struct { OdrRequest - Hash common.Hash - Number uint64 - Receipts types.Receipts + Untrusted bool // Indicator whether the result retrieved is trusted or not + Hash common.Hash + Number uint64 + Header *types.Header + Receipts types.Receipts } // StoreResult stores the retrieved data in local database func (req *ReceiptsRequest) StoreResult(db ethdb.Database) { - rawdb.WriteReceipts(db, req.Hash, req.Number, req.Receipts) + if !req.Untrusted { + rawdb.WriteReceipts(db, req.Hash, req.Number, req.Receipts) + } } // ChtRequest is the ODR request type for state/storage trie entries type ChtRequest struct { OdrRequest + Untrusted bool // Indicator whether the result retrieved is trusted or not + PeerId string // The specified peer id from which to retrieve data. Config *IndexerConfig ChtNum, BlockNum uint64 ChtRoot common.Hash @@ -147,9 +153,11 @@ type ChtRequest struct { func (req *ChtRequest) StoreResult(db ethdb.Database) { hash, num := req.Header.Hash(), req.Header.Number.Uint64() - rawdb.WriteHeader(db, req.Header) - rawdb.WriteTd(db, hash, num, req.Td) - rawdb.WriteCanonicalHash(db, hash, num) + if !req.Untrusted { + rawdb.WriteHeader(db, req.Header) + rawdb.WriteTd(db, hash, num, req.Td) + rawdb.WriteCanonicalHash(db, hash, num) + } } // BloomRequest is the ODR request type for retrieving bloom filters from a CHT structure diff --git a/light/odr_test.go b/light/odr_test.go index 912a0cbdd..debd5544c 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -264,7 +264,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { } odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig} - lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker()) + lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil) if err != nil { t.Fatal(err) } diff --git a/light/odr_util.go b/light/odr_util.go index 100bd5842..82e33bb78 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -69,6 +69,16 @@ func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*typ return r.Header, nil } +// GetUntrustedHeaderByNumber fetches specified block header without correctness checking. +// Note this function should only be used in light client checkpoint syncing. +func GetUntrustedHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64, peerId string) (*types.Header, error) { + r := &ChtRequest{BlockNum: number, ChtNum: number / odr.IndexerConfig().ChtSize, Untrusted: true, PeerId: peerId, Config: odr.IndexerConfig()} + if err := odr.Retrieve(ctx, r); err != nil { + return nil, err + } + return r.Header, nil +} + func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { hash := rawdb.ReadCanonicalHash(odr.Database(), number) if (hash != common.Hash{}) { @@ -169,6 +179,30 @@ func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number return logs, nil } +// GetUntrustedBlockLogs retrieves the logs generated by the transactions included in a +// block. The retrieved logs are regarded as untrusted and will not be stored in the +// database. This function should only be used in light client checkpoint syncing. +func GetUntrustedBlockLogs(ctx context.Context, odr OdrBackend, header *types.Header) ([][]*types.Log, error) { + // Retrieve the potentially incomplete receipts from disk or network + hash, number := header.Hash(), header.Number.Uint64() + receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number) + if receipts == nil { + r := &ReceiptsRequest{Hash: hash, Number: number, Header: header, Untrusted: true} + if err := odr.Retrieve(ctx, r); err != nil { + return nil, err + } + receipts = r.Receipts + // Untrusted receipts won't be stored in the database. Therefore + // derived fields computation is unnecessary. + } + // Return the logs without deriving any computed fields on the receipts + logs := make([][]*types.Log, len(receipts)) + for i, receipt := range receipts { + logs[i] = receipt.Logs + } + return logs, nil +} + // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxList []uint64) ([][]byte, error) { var ( diff --git a/light/txpool_test.go b/light/txpool_test.go index 4f446c6ca..0996bd7c9 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -100,7 +100,7 @@ func TestTxPool(t *testing.T) { discard: make(chan int, 1), mined: make(chan int, 1), } - lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker()) + lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil) txPermanent = 50 pool := NewTxPool(params.TestChainConfig, lightchain, relay) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) |