2016-11-08 19:01:56 -06:00
// Copyright 2016 The go-ethereum Authors
2016-10-13 22:47:09 -05:00
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
2016-11-08 19:01:56 -06:00
2019-02-26 05:32:48 -06:00
// Package light implements on-demand retrieval capable state and chain objects
// for the Ethereum Light Client.
2016-10-13 22:47:09 -05:00
package light
import (
2017-03-22 12:20:33 -05:00
"context"
2018-02-05 10:40:32 -06:00
"errors"
2016-10-13 22:47:09 -05:00
"math/big"
"sync"
"sync/atomic"
2017-03-22 14:44:22 -05:00
"time"
2016-10-13 22:47:09 -05:00
"github.com/ethereum/go-ethereum/common"
2017-04-04 17:16:29 -05:00
"github.com/ethereum/go-ethereum/consensus"
2016-10-13 22:47:09 -05:00
"github.com/ethereum/go-ethereum/core"
2018-05-07 06:35:06 -05:00
"github.com/ethereum/go-ethereum/core/rawdb"
2018-02-05 10:40:32 -06:00
"github.com/ethereum/go-ethereum/core/state"
2016-10-13 22:47:09 -05:00
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
2017-02-22 06:10:07 -06:00
"github.com/ethereum/go-ethereum/log"
2016-10-20 06:36:29 -05:00
"github.com/ethereum/go-ethereum/params"
2016-10-13 22:47:09 -05:00
"github.com/ethereum/go-ethereum/rlp"
2019-01-24 06:40:37 -06:00
lru "github.com/hashicorp/golang-lru"
2016-10-13 22:47:09 -05:00
)
var (
bodyCacheLimit = 256
blockCacheLimit = 256
)
// LightChain represents a canonical chain that by default only handles block
// headers, downloading block bodies and receipts on demand through an ODR
// interface. It only does header validation during chain insertion.
type LightChain struct {
2017-08-18 05:58:36 -05:00
hc * core . HeaderChain
2018-08-28 02:08:16 -05:00
indexerConfig * IndexerConfig
2017-08-18 05:58:36 -05:00
chainDb ethdb . Database
2019-01-24 06:40:37 -06:00
engine consensus . Engine
2017-08-18 05:58:36 -05:00
odr OdrBackend
chainFeed event . Feed
chainSideFeed event . Feed
chainHeadFeed event . Feed
scope event . SubscriptionScope
genesisBlock * types . Block
2016-10-13 22:47:09 -05:00
bodyCache * lru . Cache // Cache for the most recent block bodies
bodyRLPCache * lru . Cache // Cache for the most recent block bodies in RLP encoded format
blockCache * lru . Cache // Cache for the most recent entire blocks
2019-01-24 06:40:37 -06:00
chainmu sync . RWMutex // protects header inserts
2016-10-13 22:47:09 -05:00
quit chan struct { }
2019-01-24 06:40:37 -06:00
wg sync . WaitGroup
2019-01-24 05:18:26 -06:00
2019-01-24 06:40:37 -06:00
// Atomic boolean switches:
running int32 // whether LightChain is running or stopped
procInterrupt int32 // interrupts chain insert
disableCheckFreq int32 // disables header verification
2016-10-13 22:47:09 -05:00
}
// NewLightChain returns a fully initialised light chain using information
// available in the database. It initialises the default Ethereum header
// validator.
all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
2019-06-28 02:34:02 -05:00
func NewLightChain ( odr OdrBackend , config * params . ChainConfig , engine consensus . Engine , checkpoint * params . TrustedCheckpoint ) ( * LightChain , error ) {
2016-10-13 22:47:09 -05:00
bodyCache , _ := lru . New ( bodyCacheLimit )
bodyRLPCache , _ := lru . New ( bodyCacheLimit )
blockCache , _ := lru . New ( blockCacheLimit )
bc := & LightChain {
2018-08-28 02:08:16 -05:00
chainDb : odr . Database ( ) ,
indexerConfig : odr . IndexerConfig ( ) ,
odr : odr ,
quit : make ( chan struct { } ) ,
bodyCache : bodyCache ,
bodyRLPCache : bodyRLPCache ,
blockCache : blockCache ,
engine : engine ,
2016-10-13 22:47:09 -05:00
}
var err error
2017-04-04 17:16:29 -05:00
bc . hc , err = core . NewHeaderChain ( odr . Database ( ) , config , bc . engine , bc . getProcInterrupt )
2016-10-13 22:47:09 -05:00
if err != nil {
return nil , err
}
bc . genesisBlock , _ = bc . GetBlockByNumber ( NoOdr , 0 )
if bc . genesisBlock == nil {
2017-03-02 07:03:33 -06:00
return nil , core . ErrNoGenesis
2016-10-13 22:47:09 -05:00
}
all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
2019-06-28 02:34:02 -05:00
if checkpoint != nil {
bc . AddTrustedCheckpoint ( checkpoint )
2017-09-11 16:36:16 -05:00
}
2016-10-13 22:47:09 -05:00
if err := bc . loadLastState ( ) ; err != nil {
return nil , err
}
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
2017-01-06 08:52:03 -06:00
for hash := range core . BadHashes {
2016-10-13 22:47:09 -05:00
if header := bc . GetHeaderByHash ( hash ) ; header != nil {
2017-03-03 03:41:52 -06:00
log . Error ( "Found bad hash, rewinding chain" , "number" , header . Number , "hash" , header . ParentHash )
2016-10-13 22:47:09 -05:00
bc . SetHead ( header . Number . Uint64 ( ) - 1 )
2020-07-13 04:02:54 -05:00
log . Info ( "Chain rewind was successful, resuming normal operation" )
2016-10-13 22:47:09 -05:00
}
}
return bc , nil
}
all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
2019-06-28 02:34:02 -05:00
// AddTrustedCheckpoint adds a trusted checkpoint to the blockchain
func ( lc * LightChain ) AddTrustedCheckpoint ( cp * params . TrustedCheckpoint ) {
2019-02-07 04:53:45 -06:00
if lc . odr . ChtIndexer ( ) != nil {
StoreChtRoot ( lc . chainDb , cp . SectionIndex , cp . SectionHead , cp . CHTRoot )
lc . odr . ChtIndexer ( ) . AddCheckpoint ( cp . SectionIndex , cp . SectionHead )
2017-10-24 08:19:09 -05:00
}
2019-02-07 04:53:45 -06:00
if lc . odr . BloomTrieIndexer ( ) != nil {
StoreBloomTrieRoot ( lc . chainDb , cp . SectionIndex , cp . SectionHead , cp . BloomRoot )
lc . odr . BloomTrieIndexer ( ) . AddCheckpoint ( cp . SectionIndex , cp . SectionHead )
2017-10-24 08:19:09 -05:00
}
2019-02-07 04:53:45 -06:00
if lc . odr . BloomIndexer ( ) != nil {
lc . odr . BloomIndexer ( ) . AddCheckpoint ( cp . SectionIndex , cp . SectionHead )
2017-10-24 08:19:09 -05:00
}
all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
2019-06-28 02:34:02 -05:00
log . Info ( "Added trusted checkpoint" , "block" , ( cp . SectionIndex + 1 ) * lc . indexerConfig . ChtSize - 1 , "hash" , cp . SectionHead )
2017-10-24 08:19:09 -05:00
}
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) getProcInterrupt ( ) bool {
return atomic . LoadInt32 ( & lc . procInterrupt ) == 1
2016-10-13 22:47:09 -05:00
}
// Odr returns the ODR backend of the chain
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) Odr ( ) OdrBackend {
return lc . odr
2016-10-13 22:47:09 -05:00
}
2019-11-19 11:22:04 -06:00
// HeaderChain returns the underlying header chain.
func ( lc * LightChain ) HeaderChain ( ) * core . HeaderChain {
return lc . hc
}
2016-10-13 22:47:09 -05:00
// loadLastState loads the last known chain state from the database. This method
// assumes that the chain manager mutex is held.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) loadLastState ( ) error {
if head := rawdb . ReadHeadHeaderHash ( lc . chainDb ) ; head == ( common . Hash { } ) {
2016-10-13 22:47:09 -05:00
// Corrupt or empty database, init from scratch
2019-02-07 04:53:45 -06:00
lc . Reset ( )
2016-10-13 22:47:09 -05:00
} else {
2020-07-13 04:02:54 -05:00
header := lc . GetHeaderByHash ( head )
if header == nil {
// Corrupt or empty database, init from scratch
lc . Reset ( )
} else {
2019-02-07 04:53:45 -06:00
lc . hc . SetCurrentHeader ( header )
2016-10-13 22:47:09 -05:00
}
}
// Issue a status log and return
2019-02-07 04:53:45 -06:00
header := lc . hc . CurrentHeader ( )
headerTd := lc . GetTd ( header . Hash ( ) , header . Number . Uint64 ( ) )
2019-04-02 15:28:48 -05:00
log . Info ( "Loaded most recent local header" , "number" , header . Number , "hash" , header . Hash ( ) , "td" , headerTd , "age" , common . PrettyAge ( time . Unix ( int64 ( header . Time ) , 0 ) ) )
2016-10-13 22:47:09 -05:00
return nil
}
// SetHead rewinds the local chain to a new head. Everything above the new
// head will be deleted and the new one set.
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
2019-04-25 09:59:48 -05:00
func ( lc * LightChain ) SetHead ( head uint64 ) error {
2019-02-07 04:53:45 -06:00
lc . chainmu . Lock ( )
defer lc . chainmu . Unlock ( )
2016-10-13 22:47:09 -05:00
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
2019-04-25 09:59:48 -05:00
lc . hc . SetHead ( head , nil , nil )
return lc . loadLastState ( )
2016-10-13 22:47:09 -05:00
}
// GasLimit returns the gas limit of the current HEAD block.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GasLimit ( ) uint64 {
return lc . hc . CurrentHeader ( ) . GasLimit
2016-10-13 22:47:09 -05:00
}
// Reset purges the entire blockchain, restoring it to its genesis state.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) Reset ( ) {
lc . ResetWithGenesisBlock ( lc . genesisBlock )
2016-10-13 22:47:09 -05:00
}
// ResetWithGenesisBlock purges the entire blockchain, restoring it to the
// specified genesis state.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) ResetWithGenesisBlock ( genesis * types . Block ) {
2016-10-13 22:47:09 -05:00
// Dump the entire block chain and purge the caches
2019-02-07 04:53:45 -06:00
lc . SetHead ( 0 )
2016-10-13 22:47:09 -05:00
2019-02-07 04:53:45 -06:00
lc . chainmu . Lock ( )
defer lc . chainmu . Unlock ( )
2016-10-13 22:47:09 -05:00
// Prepare the genesis block and reinitialise the chain
2020-01-17 04:49:32 -06:00
batch := lc . chainDb . NewBatch ( )
rawdb . WriteTd ( batch , genesis . Hash ( ) , genesis . NumberU64 ( ) , genesis . Difficulty ( ) )
rawdb . WriteBlock ( batch , genesis )
rawdb . WriteHeadHeaderHash ( batch , genesis . Hash ( ) )
if err := batch . Write ( ) ; err != nil {
log . Crit ( "Failed to reset genesis block" , "err" , err )
}
2019-02-07 04:53:45 -06:00
lc . genesisBlock = genesis
lc . hc . SetGenesis ( lc . genesisBlock . Header ( ) )
lc . hc . SetCurrentHeader ( lc . genesisBlock . Header ( ) )
2016-10-13 22:47:09 -05:00
}
// Accessors
2017-04-12 08:38:31 -05:00
// Engine retrieves the light chain's consensus engine.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) Engine ( ) consensus . Engine { return lc . engine }
2017-04-12 08:38:31 -05:00
2016-10-13 22:47:09 -05:00
// Genesis returns the genesis block
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) Genesis ( ) * types . Block {
return lc . genesisBlock
2016-10-13 22:47:09 -05:00
}
2019-03-18 06:19:40 -05:00
func ( lc * LightChain ) StateCache ( ) state . Database {
panic ( "not implemented" )
2018-02-05 10:40:32 -06:00
}
2016-10-13 22:47:09 -05:00
// GetBody retrieves a block body (transactions and uncles) from the database
// or ODR service by hash, caching it if found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetBody ( ctx context . Context , hash common . Hash ) ( * types . Body , error ) {
2016-10-13 22:47:09 -05:00
// Short circuit if the body's already in the cache, retrieve otherwise
2019-02-07 04:53:45 -06:00
if cached , ok := lc . bodyCache . Get ( hash ) ; ok {
2016-10-13 22:47:09 -05:00
body := cached . ( * types . Body )
return body , nil
}
2019-02-07 04:53:45 -06:00
number := lc . hc . GetBlockNumber ( hash )
2018-05-07 06:35:06 -05:00
if number == nil {
return nil , errors . New ( "unknown block" )
}
2019-02-07 04:53:45 -06:00
body , err := GetBody ( ctx , lc . odr , hash , * number )
2016-10-13 22:47:09 -05:00
if err != nil {
return nil , err
}
// Cache the found body for next time and return
2019-02-07 04:53:45 -06:00
lc . bodyCache . Add ( hash , body )
2016-10-13 22:47:09 -05:00
return body , nil
}
// GetBodyRLP retrieves a block body in RLP encoding from the database or
// ODR service by hash, caching it if found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetBodyRLP ( ctx context . Context , hash common . Hash ) ( rlp . RawValue , error ) {
2016-10-13 22:47:09 -05:00
// Short circuit if the body's already in the cache, retrieve otherwise
2019-02-07 04:53:45 -06:00
if cached , ok := lc . bodyRLPCache . Get ( hash ) ; ok {
2016-10-13 22:47:09 -05:00
return cached . ( rlp . RawValue ) , nil
}
2019-02-07 04:53:45 -06:00
number := lc . hc . GetBlockNumber ( hash )
2018-05-07 06:35:06 -05:00
if number == nil {
return nil , errors . New ( "unknown block" )
}
2019-02-07 04:53:45 -06:00
body , err := GetBodyRLP ( ctx , lc . odr , hash , * number )
2016-10-13 22:47:09 -05:00
if err != nil {
return nil , err
}
// Cache the found body for next time and return
2019-02-07 04:53:45 -06:00
lc . bodyRLPCache . Add ( hash , body )
2016-10-13 22:47:09 -05:00
return body , nil
}
// HasBlock checks if a block is fully present in the database or not, caching
// it if present.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) HasBlock ( hash common . Hash , number uint64 ) bool {
blk , _ := lc . GetBlock ( NoOdr , hash , number )
2016-10-13 22:47:09 -05:00
return blk != nil
}
// GetBlock retrieves a block from the database or ODR service by hash and number,
// caching it if found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetBlock ( ctx context . Context , hash common . Hash , number uint64 ) ( * types . Block , error ) {
2016-10-13 22:47:09 -05:00
// Short circuit if the block's already in the cache, retrieve otherwise
2019-02-07 04:53:45 -06:00
if block , ok := lc . blockCache . Get ( hash ) ; ok {
2016-10-13 22:47:09 -05:00
return block . ( * types . Block ) , nil
}
2019-02-07 04:53:45 -06:00
block , err := GetBlock ( ctx , lc . odr , hash , number )
2016-10-13 22:47:09 -05:00
if err != nil {
return nil , err
}
// Cache the found block for next time and return
2019-02-07 04:53:45 -06:00
lc . blockCache . Add ( block . Hash ( ) , block )
2016-10-13 22:47:09 -05:00
return block , nil
}
// GetBlockByHash retrieves a block from the database or ODR service by hash,
// caching it if found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetBlockByHash ( ctx context . Context , hash common . Hash ) ( * types . Block , error ) {
number := lc . hc . GetBlockNumber ( hash )
2018-05-07 06:35:06 -05:00
if number == nil {
return nil , errors . New ( "unknown block" )
}
2019-02-07 04:53:45 -06:00
return lc . GetBlock ( ctx , hash , * number )
2016-10-13 22:47:09 -05:00
}
// GetBlockByNumber retrieves a block from the database or ODR service by
// number, caching it (associated with its hash) if found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetBlockByNumber ( ctx context . Context , number uint64 ) ( * types . Block , error ) {
hash , err := GetCanonicalHash ( ctx , lc . odr , number )
2016-10-13 22:47:09 -05:00
if hash == ( common . Hash { } ) || err != nil {
return nil , err
}
2019-02-07 04:53:45 -06:00
return lc . GetBlock ( ctx , hash , number )
2016-10-13 22:47:09 -05:00
}
// Stop stops the blockchain service. If any imports are currently in progress
// it will abort them using the procInterrupt.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) Stop ( ) {
if ! atomic . CompareAndSwapInt32 ( & lc . running , 0 , 1 ) {
2016-10-13 22:47:09 -05:00
return
}
2019-02-07 04:53:45 -06:00
close ( lc . quit )
2020-05-26 14:37:37 -05:00
lc . StopInsert ( )
2019-02-07 04:53:45 -06:00
lc . wg . Wait ( )
2020-05-26 14:37:37 -05:00
log . Info ( "Blockchain stopped" )
}
// StopInsert interrupts all insertion methods, causing them to return
// errInsertionInterrupted as soon as possible. Insertion is permanently disabled after
// calling this method.
func ( lc * LightChain ) StopInsert ( ) {
atomic . StoreInt32 ( & lc . procInterrupt , 1 )
2016-10-13 22:47:09 -05:00
}
// Rollback is designed to remove a chain of links from the database that aren't
// certain enough to be valid.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) Rollback ( chain [ ] common . Hash ) {
lc . chainmu . Lock ( )
defer lc . chainmu . Unlock ( )
2016-10-13 22:47:09 -05:00
2020-01-17 04:49:32 -06:00
batch := lc . chainDb . NewBatch ( )
2016-10-13 22:47:09 -05:00
for i := len ( chain ) - 1 ; i >= 0 ; i -- {
hash := chain [ i ]
2020-01-17 04:49:32 -06:00
// Degrade the chain markers if they are explicitly reverted.
// In theory we should update all in-memory markers in the
// last step, however the direction of rollback is from high
// to low, so it's safe the update in-memory markers directly.
2019-02-07 04:53:45 -06:00
if head := lc . hc . CurrentHeader ( ) ; head . Hash ( ) == hash {
2020-01-17 04:49:32 -06:00
rawdb . WriteHeadHeaderHash ( batch , head . ParentHash )
2019-02-07 04:53:45 -06:00
lc . hc . SetCurrentHeader ( lc . GetHeader ( head . ParentHash , head . Number . Uint64 ( ) - 1 ) )
2016-10-13 22:47:09 -05:00
}
}
2020-01-17 04:49:32 -06:00
if err := batch . Write ( ) ; err != nil {
log . Crit ( "Failed to rollback light chain" , "error" , err )
}
2016-10-13 22:47:09 -05:00
}
// postChainEvents iterates over the events generated by a chain insertion and
2017-08-18 05:58:36 -05:00
// posts them into the event feed.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) postChainEvents ( events [ ] interface { } ) {
2016-10-13 22:47:09 -05:00
for _ , event := range events {
2017-08-18 05:58:36 -05:00
switch ev := event . ( type ) {
case core . ChainEvent :
2019-02-07 04:53:45 -06:00
if lc . CurrentHeader ( ) . Hash ( ) == ev . Hash {
lc . chainHeadFeed . Send ( core . ChainHeadEvent { Block : ev . Block } )
2016-10-13 22:47:09 -05:00
}
2019-02-07 04:53:45 -06:00
lc . chainFeed . Send ( ev )
2017-08-18 05:58:36 -05:00
case core . ChainSideEvent :
2019-02-07 04:53:45 -06:00
lc . chainSideFeed . Send ( ev )
2016-10-13 22:47:09 -05:00
}
}
}
// InsertHeaderChain attempts to insert the given header chain in to the local
// chain, possibly creating a reorg. If an error is returned, it will return the
// index number of the failing header as well an error describing what went wrong.
//
// The verify parameter can be used to fine tune whether nonce verification
// should be done or not. The reason behind the optional check is because some
// of the header retrieval mechanisms already need to verfy nonces, as well as
// because nonces can be verified sparsely, not needing to check each.
//
// In the case of a light chain, InsertHeaderChain also creates and posts light
// chain events when necessary.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) InsertHeaderChain ( chain [ ] * types . Header , checkFreq int ) ( int , error ) {
if atomic . LoadInt32 ( & lc . disableCheckFreq ) == 1 {
2019-01-24 05:18:26 -06:00
checkFreq = 0
}
2017-03-22 14:44:22 -05:00
start := time . Now ( )
2019-02-07 04:53:45 -06:00
if i , err := lc . hc . ValidateHeaderChain ( chain , checkFreq ) ; err != nil {
2017-03-22 14:44:22 -05:00
return i , err
}
2016-10-13 22:47:09 -05:00
// Make sure only one thread manipulates the chain at once
2019-02-07 04:53:45 -06:00
lc . chainmu . Lock ( )
defer lc . chainmu . Unlock ( )
2016-10-13 22:47:09 -05:00
2019-02-07 04:53:45 -06:00
lc . wg . Add ( 1 )
defer lc . wg . Done ( )
2016-10-13 22:47:09 -05:00
2020-12-09 04:13:02 -06:00
status , err := lc . hc . InsertHeaderChain ( chain , start )
if err != nil || len ( chain ) == 0 {
return 0 , err
}
// Create chain event for the new head block of this insertion.
var (
events = make ( [ ] interface { } , 0 , 1 )
lastHeader = chain [ len ( chain ) - 1 ]
block = types . NewBlockWithHeader ( lastHeader )
)
switch status {
case core . CanonStatTy :
events = append ( events , core . ChainEvent { Block : block , Hash : block . Hash ( ) } )
case core . SideStatTy :
events = append ( events , core . ChainSideEvent { Block : block } )
2016-10-13 22:47:09 -05:00
}
2019-02-07 04:53:45 -06:00
lc . postChainEvents ( events )
2020-12-09 04:13:02 -06:00
return 0 , err
2016-10-13 22:47:09 -05:00
}
// CurrentHeader retrieves the current head header of the canonical chain. The
// header is retrieved from the HeaderChain's internal cache.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) CurrentHeader ( ) * types . Header {
return lc . hc . CurrentHeader ( )
2016-10-13 22:47:09 -05:00
}
// GetTd retrieves a block's total difficulty in the canonical chain from the
// database by hash and number, caching it if found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetTd ( hash common . Hash , number uint64 ) * big . Int {
return lc . hc . GetTd ( hash , number )
2016-10-13 22:47:09 -05:00
}
2020-07-13 04:02:54 -05:00
// GetHeaderByNumberOdr retrieves the total difficult from the database or
// network by hash and number, caching it (associated with its hash) if found.
func ( lc * LightChain ) GetTdOdr ( ctx context . Context , hash common . Hash , number uint64 ) * big . Int {
td := lc . GetTd ( hash , number )
if td != nil {
return td
}
td , _ = GetTd ( ctx , lc . odr , hash , number )
return td
}
2016-10-13 22:47:09 -05:00
// GetHeader retrieves a block header from the database by hash and number,
// caching it if found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetHeader ( hash common . Hash , number uint64 ) * types . Header {
return lc . hc . GetHeader ( hash , number )
2016-10-13 22:47:09 -05:00
}
// GetHeaderByHash retrieves a block header from the database by hash, caching it if
// found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetHeaderByHash ( hash common . Hash ) * types . Header {
return lc . hc . GetHeaderByHash ( hash )
2016-10-13 22:47:09 -05:00
}
// HasHeader checks if a block header is present in the database or not, caching
// it if present.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) HasHeader ( hash common . Hash , number uint64 ) bool {
return lc . hc . HasHeader ( hash , number )
2016-10-13 22:47:09 -05:00
}
2019-09-26 03:47:31 -05:00
// GetCanonicalHash returns the canonical hash for a given block number
func ( bc * LightChain ) GetCanonicalHash ( number uint64 ) common . Hash {
return bc . hc . GetCanonicalHash ( number )
}
2018-06-12 08:52:54 -05:00
// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or
// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the
// number of blocks to be individually checked before we reach the canonical chain.
//
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetAncestor ( hash common . Hash , number , ancestor uint64 , maxNonCanonical * uint64 ) ( common . Hash , uint64 ) {
return lc . hc . GetAncestor ( hash , number , ancestor , maxNonCanonical )
2018-06-12 08:52:54 -05:00
}
2016-10-13 22:47:09 -05:00
// GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetHeaderByNumber ( number uint64 ) * types . Header {
return lc . hc . GetHeaderByNumber ( number )
2016-10-13 22:47:09 -05:00
}
// GetHeaderByNumberOdr retrieves a block header from the database or network
// by number, caching it (associated with its hash) if found.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) GetHeaderByNumberOdr ( ctx context . Context , number uint64 ) ( * types . Header , error ) {
if header := lc . hc . GetHeaderByNumber ( number ) ; header != nil {
2016-10-13 22:47:09 -05:00
return header , nil
}
2019-02-07 04:53:45 -06:00
return GetHeaderByNumber ( ctx , lc . odr , number )
2016-10-13 22:47:09 -05:00
}
2017-12-28 07:18:34 -06:00
// Config retrieves the header chain's chain configuration.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) Config ( ) * params . ChainConfig { return lc . hc . Config ( ) }
2017-12-28 07:18:34 -06:00
all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
2019-06-28 02:34:02 -05:00
// 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
2019-02-07 04:53:45 -06:00
head := lc . CurrentHeader ( ) . Number . Uint64 ( )
2018-08-21 06:39:28 -05:00
all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
2019-06-28 02:34:02 -05:00
latest := ( checkpoint . SectionIndex + 1 ) * lc . indexerConfig . ChtSize - 1
2019-02-07 04:53:45 -06:00
if clique := lc . hc . Config ( ) . Clique ; clique != nil {
2018-08-21 06:39:28 -05:00
latest -= latest % clique . Epoch // epoch snapshot for clique
}
if head >= latest {
all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
2019-06-28 02:34:02 -05:00
return true
2018-08-21 06:39:28 -05:00
}
// Retrieve the latest useful header and update to it
2019-02-07 04:53:45 -06:00
if header , err := GetHeaderByNumber ( ctx , lc . odr , latest ) ; header != nil && err == nil {
lc . chainmu . Lock ( )
defer lc . chainmu . Unlock ( )
2018-08-21 06:39:28 -05:00
// Ensure the chain didn't move past the latest block while retrieving it
2019-02-07 04:53:45 -06:00
if lc . hc . CurrentHeader ( ) . Number . Uint64 ( ) < header . Number . Uint64 ( ) {
2019-04-02 15:28:48 -05:00
log . Info ( "Updated latest header based on CHT" , "number" , header . Number , "hash" , header . Hash ( ) , "age" , common . PrettyAge ( time . Unix ( int64 ( header . Time ) , 0 ) ) )
2020-01-17 04:49:32 -06:00
rawdb . WriteHeadHeaderHash ( lc . chainDb , header . Hash ( ) )
2019-02-07 04:53:45 -06:00
lc . hc . SetCurrentHeader ( header )
2016-10-13 22:47:09 -05:00
}
2018-08-21 06:39:28 -05:00
return true
2016-10-13 22:47:09 -05:00
}
return false
}
2016-11-29 23:02:08 -06:00
// LockChain locks the chain mutex for reading so that multiple canonical hashes can be
// retrieved while it is guaranteed that they belong to the same version of the chain
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) LockChain ( ) {
lc . chainmu . RLock ( )
2016-11-29 23:02:08 -06:00
}
// UnlockChain unlocks the chain mutex
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) UnlockChain ( ) {
lc . chainmu . RUnlock ( )
2016-11-29 23:02:08 -06:00
}
2017-08-18 05:58:36 -05:00
// SubscribeChainEvent registers a subscription of ChainEvent.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) SubscribeChainEvent ( ch chan <- core . ChainEvent ) event . Subscription {
return lc . scope . Track ( lc . chainFeed . Subscribe ( ch ) )
2017-08-18 05:58:36 -05:00
}
// SubscribeChainHeadEvent registers a subscription of ChainHeadEvent.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) SubscribeChainHeadEvent ( ch chan <- core . ChainHeadEvent ) event . Subscription {
return lc . scope . Track ( lc . chainHeadFeed . Subscribe ( ch ) )
2017-08-18 05:58:36 -05:00
}
// SubscribeChainSideEvent registers a subscription of ChainSideEvent.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) SubscribeChainSideEvent ( ch chan <- core . ChainSideEvent ) event . Subscription {
return lc . scope . Track ( lc . chainSideFeed . Subscribe ( ch ) )
2017-08-18 05:58:36 -05:00
}
// SubscribeLogsEvent implements the interface of filters.Backend
// LightChain does not send logs events, so return an empty subscription.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) SubscribeLogsEvent ( ch chan <- [ ] * types . Log ) event . Subscription {
return lc . scope . Track ( new ( event . Feed ) . Subscribe ( ch ) )
2017-08-18 05:58:36 -05:00
}
// SubscribeRemovedLogsEvent implements the interface of filters.Backend
// LightChain does not send core.RemovedLogsEvent, so return an empty subscription.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) SubscribeRemovedLogsEvent ( ch chan <- core . RemovedLogsEvent ) event . Subscription {
return lc . scope . Track ( new ( event . Feed ) . Subscribe ( ch ) )
2017-08-18 05:58:36 -05:00
}
2019-01-24 05:18:26 -06:00
2019-01-24 06:40:37 -06:00
// DisableCheckFreq disables header validation. This is used for ultralight mode.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) DisableCheckFreq ( ) {
atomic . StoreInt32 ( & lc . disableCheckFreq , 1 )
2019-01-24 05:18:26 -06:00
}
2019-01-24 06:40:37 -06:00
// EnableCheckFreq enables header validation.
2019-02-07 04:53:45 -06:00
func ( lc * LightChain ) EnableCheckFreq ( ) {
atomic . StoreInt32 ( & lc . disableCheckFreq , 0 )
2019-01-24 05:18:26 -06:00
}