cmd, eth, les, light: move checkpoint config to config file

This commit is contained in:
rjl493456442 2019-06-24 21:32:53 +08:00 committed by Péter Szilágyi
parent 2f66fee3b7
commit 1e51c9a14f
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
19 changed files with 123 additions and 228 deletions

View file

@ -27,17 +27,10 @@ import (
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/contracts/registrar/contract"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm/runtime"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
@ -140,65 +133,6 @@ func (w *wizard) makeGenesis() {
fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)")
genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536))))
// Query the user for checkpoint contract config
fmt.Println()
fmt.Println("Should a checkpoint contract be deployed (y/n)? (default = no)")
if w.readDefaultYesNo(false) {
// Read the addresses of the trusted signers
fmt.Println("Which accounts should be trusted signers? (mandatory at least one)")
var (
signers []common.Address
threshold uint64
)
// Get trusted signer addresses
for {
if address := w.readAddress(); address != nil {
signers = append(signers, *address)
continue
}
if len(signers) == 0 {
continue
}
break
}
// Read the checkpoint signature threshold
for {
fmt.Printf("What is the minimal approval threshold (maximum %d)?\n", len(signers))
threshold = uint64(w.readInt())
if threshold <= 0 || threshold > uint64(len(signers)) {
log.Error(fmt.Sprintf("Invalid approval threshold, please enter in range [1, %d]\n", len(signers)))
continue
}
break
}
parsed, err := abi.JSON(strings.NewReader(contract.ContractABI))
if err != nil {
log.Crit("Parse contract ABI failed", "err", err)
}
input, err := parsed.Pack("", signers, big.NewInt(params.CheckpointFrequency), big.NewInt(params.CheckpointProcessConfirmations), new(big.Int).SetUint64(threshold))
if err != nil {
log.Crit("Pack contract constructor arguments failed", "err", err)
}
config := &runtime.Config{GasLimit: math.MaxInt64}
config.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
code, address, _, err := runtime.Create(append(common.FromHex(contract.ContractBin), input...), config)
if err != nil {
log.Crit("Execute contract constructor failed", "err", err)
}
config.State.Commit(true)
genesis.Alloc[address] = core.GenesisAccount{Code: code, Storage: make(map[common.Hash]common.Hash), Balance: big.NewInt(1)}
if err = config.State.ForEachStorage(address, func(key, value common.Hash) bool {
genesis.Alloc[address].Storage[key] = value
return true
}); err != nil {
log.Crit("Failed to iterate contract storage", "err", err)
}
genesis.Config.CheckpointConfig = &params.CheckpointContractConfig{
Address: address,
Signers: signers,
Threshold: threshold,
}
}
// All done, store the genesis and flush to disk
log.Info("Configured new genesis block")
@ -296,77 +230,6 @@ func (w *wizard) manageGenesis() {
fmt.Printf("Which block should Petersburg come into effect? (default = %v)\n", w.conf.Genesis.Config.PetersburgBlock)
w.conf.Genesis.Config.PetersburgBlock = w.readDefaultBigInt(w.conf.Genesis.Config.PetersburgBlock)
// The registrar contract might have been deployed
fmt.Println()
fmt.Printf("Should a checkpoint contract be active (y/n)? (default = %v)\n", w.conf.Genesis.Config.CheckpointConfig != nil)
if !w.readDefaultYesNo(w.conf.Genesis.Config.CheckpointConfig != nil) {
w.conf.Genesis.Config.CheckpointConfig = nil
} else {
// Make sure we have a checkpoint config to fill out
checkpoint := w.conf.Genesis.Config.CheckpointConfig
if checkpoint == nil {
checkpoint = new(params.CheckpointContractConfig)
}
// Read the Ethereum address of the deployed contract
fmt.Println()
if checkpoint.Address == (common.Address{}) {
fmt.Printf("Which address does the checkpoint contract reside at?\n")
for checkpoint.Address == (common.Address{}) {
if address := w.readAddress(); address != nil {
checkpoint.Address = *address
}
}
} else {
fmt.Printf("Which address does the checkpoint contract reside at? (default = %s)\n", checkpoint.Address.Hex())
checkpoint.Address = w.readDefaultAddress(checkpoint.Address)
}
// Read the addresses of the trusted signers
if len(checkpoint.Signers) > 0 {
signers := make([]string, len(checkpoint.Signers))
for i, signer := range checkpoint.Signers {
signers[i] = signer.Hex()
}
fmt.Println()
fmt.Printf("Keep existing list of authorized signers %s? (default = yes)\n", strings.Join(signers, ","))
if !w.readDefaultYesNo(true) {
checkpoint.Signers = nil
}
}
if len(checkpoint.Signers) == 0 {
fmt.Println()
fmt.Println("Which accounts should be trusted signers? (mandatory at least one)")
for {
if address := w.readAddress(); address != nil {
checkpoint.Signers = append(checkpoint.Signers, *address)
continue
}
if len(checkpoint.Signers) == 0 {
continue
}
break
}
}
// Read the checkpoint signature threshold
fmt.Println()
if checkpoint.Threshold == 0 {
fmt.Printf("What is the minimal approval threshold (maximum %d)?\n", len(checkpoint.Signers))
} else {
fmt.Printf("What is the minimal approval threshold (maximum %d)? (default = %d)\n", len(checkpoint.Signers), checkpoint.Threshold)
}
for {
if checkpoint.Threshold == 0 {
checkpoint.Threshold = uint64(w.readInt())
} else {
checkpoint.Threshold = uint64(w.readDefaultInt(int(checkpoint.Threshold)))
}
if checkpoint.Threshold <= 0 || checkpoint.Threshold > uint64(len(checkpoint.Signers)) {
log.Error(fmt.Sprintf("Invalid approval threshold, please enter in range [1, %d]\n", len(checkpoint.Signers)))
continue
}
break
}
w.conf.Genesis.Config.CheckpointConfig = checkpoint
}
out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", " ")
fmt.Printf("Chain configuration updated:\n\n%s\n", out)

View file

@ -1468,16 +1468,34 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
cfg.NetworkId = 3
}
cfg.Genesis = core.DefaultTestnetGenesisBlock()
// Only override default checkpoint so that user can customize checkpoint
// by themselves.
if cfg.Checkpoint == eth.DefaultConfig.Checkpoint {
cfg.Checkpoint = params.TestnetTrustedCheckpoint
}
case ctx.GlobalBool(RinkebyFlag.Name):
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 4
}
cfg.Genesis = core.DefaultRinkebyGenesisBlock()
// Only override default checkpoint so that user can customize checkpoint
// by themselves.
if cfg.Checkpoint == eth.DefaultConfig.Checkpoint {
cfg.Checkpoint = params.RinkebyTrustedCheckpoint
}
if cfg.CheckpointConfig == nil {
cfg.CheckpointConfig = params.RinkebyCheckpointConfig // Enable checkpoint contract for rinkeby testnet.
}
case ctx.GlobalBool(GoerliFlag.Name):
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 5
}
cfg.Genesis = core.DefaultGoerliGenesisBlock()
// Only override default checkpoint so that user can customize checkpoint
// by themselves.
if cfg.Checkpoint == eth.DefaultConfig.Checkpoint {
cfg.Checkpoint = params.GoerliTrustedCheckpoint
}
case ctx.GlobalBool(DeveloperFlag.Name):
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 1337

View file

@ -202,7 +202,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
// Permit the downloader to use the trie cache allowance during fast sync
cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit
if eth.protocolManager, err = NewProtocolManager(chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, cacheLimit, config.Whitelist); err != nil {
if eth.protocolManager, err = NewProtocolManager(chainConfig, config.Checkpoint, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, cacheLimit, config.Whitelist); err != nil {
return nil, err
}
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)

View file

@ -60,6 +60,7 @@ var DefaultConfig = Config{
Blocks: 20,
Percentile: 60,
},
Checkpoint: params.MainnetTrustedCheckpoint,
}
func init() {
@ -149,4 +150,10 @@ type Config struct {
// RPCGasCap is the global gas cap for eth-call variants.
RPCGasCap *big.Int `toml:",omitempty"`
// Checkpoint is a hardcoded checkpoint which can be nil.
Checkpoint *params.TrustedCheckpoint
// CheckpointConfig is a set of checkpoint contract configs.
CheckpointConfig *params.CheckpointContractConfig
}

View file

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
)
// MarshalTOML marshals as TOML.
@ -32,6 +33,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
SkipBcVersionCheck bool `toml:"-"`
DatabaseHandles int `toml:"-"`
DatabaseCache int
DatabaseFreezer string
TrieCleanCache int
TrieDirtyCache int
TrieTimeout time.Duration
@ -45,6 +47,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
EVMInterpreter string
ConstantinopleOverride *big.Int
RPCGasCap *big.Int `toml:",omitempty"`
Checkpoint *params.TrustedCheckpoint
CheckpointConfig *params.CheckpointContractConfig
}
var enc Config
enc.Genesis = c.Genesis
@ -62,6 +66,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.SkipBcVersionCheck = c.SkipBcVersionCheck
enc.DatabaseHandles = c.DatabaseHandles
enc.DatabaseCache = c.DatabaseCache
enc.DatabaseFreezer = c.DatabaseFreezer
enc.TrieCleanCache = c.TrieCleanCache
enc.TrieDirtyCache = c.TrieDirtyCache
enc.TrieTimeout = c.TrieTimeout
@ -75,6 +80,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.EVMInterpreter = c.EVMInterpreter
enc.ConstantinopleOverride = c.ConstantinopleOverride
enc.RPCGasCap = c.RPCGasCap
enc.Checkpoint = c.Checkpoint
enc.CheckpointConfig = c.CheckpointConfig
return &enc, nil
}
@ -96,6 +103,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
SkipBcVersionCheck *bool `toml:"-"`
DatabaseHandles *int `toml:"-"`
DatabaseCache *int
DatabaseFreezer *string
TrieCleanCache *int
TrieDirtyCache *int
TrieTimeout *time.Duration
@ -109,6 +117,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
EVMInterpreter *string
ConstantinopleOverride *big.Int
RPCGasCap *big.Int `toml:",omitempty"`
Checkpoint *params.TrustedCheckpoint
CheckpointConfig *params.CheckpointContractConfig
}
var dec Config
if err := unmarshal(&dec); err != nil {
@ -159,6 +169,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.DatabaseCache != nil {
c.DatabaseCache = *dec.DatabaseCache
}
if dec.DatabaseFreezer != nil {
c.DatabaseFreezer = *dec.DatabaseFreezer
}
if dec.TrieCleanCache != nil {
c.TrieCleanCache = *dec.TrieCleanCache
}
@ -198,5 +211,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.RPCGasCap != nil {
c.RPCGasCap = dec.RPCGasCap
}
if dec.Checkpoint != nil {
c.Checkpoint = dec.Checkpoint
}
if dec.CheckpointConfig != nil {
c.CheckpointConfig = dec.CheckpointConfig
}
return nil
}

View file

@ -106,7 +106,7 @@ type ProtocolManager struct {
// NewProtocolManager returns a new Ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the Ethereum network.
func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database, cacheLimit int, whitelist map[uint64]common.Hash) (*ProtocolManager, error) {
func NewProtocolManager(config *params.ChainConfig, checkpoint *params.TrustedCheckpoint, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database, cacheLimit int, whitelist map[uint64]common.Hash) (*ProtocolManager, error) {
// Create the protocol manager with the base fields
manager := &ProtocolManager{
networkID: networkID,
@ -145,7 +145,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
}
}
// If we have trusted checkpoints, enforce them on the chain
if checkpoint, ok := params.TrustedCheckpoints[blockchain.Genesis().Hash()]; ok {
if checkpoint != nil {
manager.checkpointNumber = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1
manager.checkpointHash = checkpoint.SectionHead
}

View file

@ -499,31 +499,30 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo
// Initialize a chain and generate a fake CHT if checkpointing is enabled
var (
db = rawdb.NewMemoryDatabase()
config = new(params.ChainConfig)
genesis = (&core.Genesis{Config: config}).MustCommit(db)
db = rawdb.NewMemoryDatabase()
config = new(params.ChainConfig)
)
(&core.Genesis{Config: config}).MustCommit(db) // Commit genesis block
// If checkpointing is enabled, create and inject a fake CHT and the corresponding
// chllenge response.
var response *types.Header
var cht *params.TrustedCheckpoint
if checkpoint {
index := uint64(rand.Intn(500))
number := (index+1)*params.CHTFrequency - 1
response = &types.Header{Number: big.NewInt(int64(number)), Extra: []byte("valid")}
cht := &params.TrustedCheckpoint{
cht = &params.TrustedCheckpoint{
SectionIndex: index,
SectionHead: response.Hash(),
}
params.TrustedCheckpoints[genesis.Hash()] = cht
defer delete(params.TrustedCheckpoints, genesis.Hash())
}
// Create a checkpoint aware protocol manager
blockchain, err := core.NewBlockChain(db, nil, config, ethash.NewFaker(), vm.Config{}, nil)
if err != nil {
t.Fatalf("failed to create new blockchain: %v", err)
}
pm, err := NewProtocolManager(config, syncmode, DefaultConfig.NetworkId, new(event.TypeMux), new(testTxPool), ethash.NewFaker(), blockchain, db, 1, nil)
pm, err := NewProtocolManager(config, cht, syncmode, DefaultConfig.NetworkId, new(event.TypeMux), new(testTxPool), ethash.NewFaker(), blockchain, db, 1, nil)
if err != nil {
t.Fatalf("failed to start test protocol manager: %v", err)
}
@ -610,7 +609,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
if err != nil {
t.Fatalf("failed to create new blockchain: %v", err)
}
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, 1, nil)
pm, err := NewProtocolManager(config, nil, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, 1, nil)
if err != nil {
t.Fatalf("failed to start test protocol manager: %v", err)
}

View file

@ -66,7 +66,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
if _, err := blockchain.InsertChain(chain); err != nil {
panic(err)
}
pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db, 1, nil)
pm, err := NewProtocolManager(gspec.Config, nil, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db, 1, nil)
if err != nil {
return nil, nil, err
}

View file

@ -126,7 +126,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
// 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, config.Checkpoint); err != nil {
return nil, err
}
// Note: AddChildIndexer starts the update process for the child
@ -150,8 +150,8 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
}
leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams)
registrar := newCheckpointRegistrar(chainConfig.CheckpointConfig, leth.getLocalCheckpoint)
if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, light.DefaultClientIndexerConfig, config.ULC, true, config.NetworkId, leth.eventMux, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.serverPool, registrar, quitSync, &leth.wg, nil); err != nil {
registrar := newCheckpointRegistrar(config.CheckpointConfig, leth.getLocalCheckpoint)
if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, config.Checkpoint, light.DefaultClientIndexerConfig, config.ULC, true, config.NetworkId, leth.eventMux, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.serverPool, registrar, quitSync, &leth.wg, nil); err != nil {
return nil, err
}
if leth.protocolManager.isULCEnabled() {

View file

@ -114,6 +114,7 @@ type ProtocolManager struct {
fetcher *lightFetcher
ulc *ulc
peers *peerSet
checkpoint *params.TrustedCheckpoint
reg *checkpointRegistrar // If reg == nil, it means the checkpoint registrar is not activated
// channels for fetcher, syncer, txsyncLoop
@ -131,7 +132,7 @@ type ProtocolManager struct {
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network.
func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.IndexerConfig, ulcConfig *eth.ULCConfig, client bool, networkId uint64, mux *event.TypeMux, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, serverPool *serverPool, registrar *checkpointRegistrar, quitSync chan struct{}, wg *sync.WaitGroup, synced func() bool) (*ProtocolManager, error) {
func NewProtocolManager(chainConfig *params.ChainConfig, checkpoint *params.TrustedCheckpoint, indexerConfig *light.IndexerConfig, ulcConfig *eth.ULCConfig, client bool, networkId uint64, mux *event.TypeMux, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, serverPool *serverPool, registrar *checkpointRegistrar, quitSync chan struct{}, wg *sync.WaitGroup, synced func() bool) (*ProtocolManager, error) {
// Create the protocol manager with the base fields
manager := &ProtocolManager{
client: client,
@ -150,6 +151,7 @@ func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.In
quitSync: quitSync,
wg: wg,
noMorePeers: make(chan struct{}),
checkpoint: checkpoint,
synced: synced,
}
if odr != nil {
@ -166,11 +168,11 @@ func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.In
removePeer = func(id string) {}
}
if client {
var checkpoint uint64
if cht, ok := params.TrustedCheckpoints[blockchain.Genesis().Hash()]; ok {
checkpoint = (cht.SectionIndex+1)*params.CHTFrequency - 1
var checkpointNumber uint64
if checkpoint != nil {
checkpointNumber = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1
}
manager.downloader = downloader.New(checkpoint, chainDb, nil, manager.eventMux, nil, blockchain, removePeer)
manager.downloader = downloader.New(checkpointNumber, chainDb, nil, manager.eventMux, nil, blockchain, removePeer)
manager.peers.notify((*downloaderPeerNotify)(manager))
manager.fetcher = newLightFetcher(manager)
}

View file

@ -189,7 +189,7 @@ func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers []
// initialize empty chain for light client or pre-committed chain for server.
if lightSync {
chain, _ = light.NewLightChain(odr, gspec.Config, engine)
chain, _ = light.NewLightChain(odr, gspec.Config, engine, nil)
} else {
chain = simulation.Blockchain()
pool = core.NewTxPool(core.DefaultTxPoolConfig, gspec.Config, simulation.Blockchain())
@ -201,7 +201,6 @@ func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers []
indexConfig = light.TestClientIndexerConfig
}
config := &params.CheckpointContractConfig{
Name: "test",
Address: crypto.CreateAddress(bankAddr, 0),
Signers: []common.Address{signerAddr},
Threshold: 1,
@ -220,7 +219,7 @@ func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers []
}
reg = newCheckpointRegistrar(config, getLocal)
}
pm, err := NewProtocolManager(gspec.Config, indexConfig, ulcConfig, lightSync, NetworkId, evmux, peers, chain, pool, db, odr, nil, reg, exitCh, new(sync.WaitGroup), func() bool { return true })
pm, err := NewProtocolManager(gspec.Config, nil, indexConfig, ulcConfig, lightSync, NetworkId, evmux, peers, chain, pool, db, odr, nil, reg, exitCh, new(sync.WaitGroup), func() bool { return true })
if err != nil {
return nil, nil, err
}

View file

@ -81,9 +81,8 @@ type peer struct {
announceType uint64
// Checkpoint relative fields
advertisedCheckpoint params.TrustedCheckpoint
registeredHeight uint64
hardcodedCheckpoint bool // Indicator whether the checkpoint is hardcoded
checkpoint params.TrustedCheckpoint
checkpointNumber uint64
id string
@ -687,24 +686,8 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
p.fcServer = flowcontrol.NewServerNode(sParams, &mclock.System{})
p.fcCosts = MRC.decode(ProtocolLengths[uint(p.version)])
// Recap the checkpoint.
//
// The light client may be connected to several different versions of the server.
// (1) Old version server which can not provide stable checkpoint in the handshake packet.
// => Use hardcoded checkpoint or empty checkpoint
// (2) New version server but simple checkpoint syncing is not enabled(e.g. mainnet, new testnet or private network)
// => Use hardcoded checkpoint or empty checkpoint
// (3) New version server but the provided stable checkpoint is even lower than the hardcoded one.
// => Use hardcoded checkpoint
// (4) New version server with valid and higher stable checkpoint
// => Use provided checkpoint
hardcoded := params.TrustedCheckpoints[genesis]
if err := recv.get("checkpoint/value", &p.advertisedCheckpoint); hardcoded != nil &&
(err != nil || p.advertisedCheckpoint.SectionIndex < hardcoded.SectionIndex) {
p.advertisedCheckpoint = *hardcoded
p.hardcodedCheckpoint = true
}
recv.get("checkpoint/registerHeight", &p.registeredHeight)
recv.get("checkpoint/value", &p.checkpoint)
recv.get("checkpoint/registerHeight", &p.checkpointNumber)
if !p.isOnlyAnnounce {
for msgCode := range reqAvgTimeCost {

View file

@ -120,8 +120,8 @@ func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) {
srv.chtIndexer.Start(e.BlockChain())
registrar := newCheckpointRegistrar(e.BlockChain().Config().CheckpointConfig, srv.getLocalCheckpoint)
pm, err := NewProtocolManager(e.BlockChain().Config(), light.DefaultServerIndexerConfig, config.ULC, false, config.NetworkId, e.EventMux(), newPeerSet(), e.BlockChain(), e.TxPool(), e.ChainDb(), nil, nil, registrar, quitSync, new(sync.WaitGroup), e.Synced)
registrar := newCheckpointRegistrar(config.CheckpointConfig, srv.getLocalCheckpoint)
pm, err := NewProtocolManager(e.BlockChain().Config(), config.Checkpoint, light.DefaultServerIndexerConfig, config.ULC, false, config.NetworkId, e.EventMux(), newPeerSet(), e.BlockChain(), e.TxPool(), e.ChainDb(), nil, nil, registrar, quitSync, new(sync.WaitGroup), e.Synced)
if err != nil {
return nil, err
}

View file

@ -26,7 +26,6 @@ import (
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
var errInvalidCheckpoint = errors.New("invalid advertised checkpoint")
@ -86,8 +85,8 @@ func (pm *ProtocolManager) validateCheckpoint(peer *peer) error {
defer cancel()
// Fetch the block header corresponding to the checkpoint registration.
cp := peer.advertisedCheckpoint
header, err := light.GetUntrustedHeaderByNumber(ctx, pm.odr, peer.registeredHeight, peer.id)
cp := peer.checkpoint
header, err := light.GetUntrustedHeaderByNumber(ctx, pm.odr, peer.checkpointNumber, peer.id)
if err != nil {
return err
}
@ -128,6 +127,23 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
if currentTd != nil && peer.headBlockInfo().Td.Cmp(currentTd) < 0 {
return
}
// Recap the checkpoint.
//
// The light client may be connected to several different versions of the server.
// (1) Old version server which can not provide stable checkpoint in the handshake packet.
// => Use hardcoded checkpoint or empty checkpoint
// (2) New version server but simple checkpoint syncing is not enabled(e.g. mainnet, new testnet or private network)
// => Use hardcoded checkpoint or empty checkpoint
// (3) New version server but the provided stable checkpoint is even lower than the hardcoded one.
// => Use hardcoded checkpoint
// (4) New version server with valid and higher stable checkpoint
// => Use provided checkpoint
var checkpoint = &peer.checkpoint
var hardcoded bool
if pm.checkpoint != nil && pm.checkpoint.SectionIndex > peer.checkpoint.SectionIndex {
checkpoint = pm.checkpoint // Use the hardcoded one.
hardcoded = true
}
// Determine whether we should run checkpoint syncing or normal light syncing.
//
// Here has four situations that we will disable the checkpoint syncing:
@ -136,16 +152,15 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
// 2. The latest head block of the local chain is above the checkpoint.
// 3. The checkpoint is hardcoded(recap with local hardcoded checkpoint)
// 4. For some networks the checkpoint syncing is not activated.
cp := &peer.advertisedCheckpoint
mode := checkpointSync
switch {
case cp.Empty():
case checkpoint.Empty():
mode = lightSync
log.Debug("Disable checkpoint syncing", "reason", "empty checkpoint")
case latest.Number.Uint64() >= (cp.SectionIndex+1)*pm.iConfig.ChtSize-1:
case latest.Number.Uint64() >= (checkpoint.SectionIndex+1)*pm.iConfig.ChtSize-1:
mode = lightSync
log.Debug("Disable checkpoint syncing", "reason", "local chain beyond the checkpoint")
case peer.hardcodedCheckpoint:
log.Debug("Disable checkpoint syncing", "reason", "local chain beyonds the checkpoint")
case hardcoded:
mode = legacyCheckpointSync
log.Debug("Disable checkpoint syncing", "reason", "checkpoint is hardcoded")
case pm.reg == nil || !pm.reg.isRunning():
@ -162,16 +177,16 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
if mode == checkpointSync || mode == legacyCheckpointSync {
// Validate the advertised checkpoint
if mode == legacyCheckpointSync {
cp = params.TrustedCheckpoints[pm.blockchain.Genesis().Hash()]
checkpoint = pm.checkpoint
} else if mode == checkpointSync {
if err := pm.validateCheckpoint(peer); err != nil {
log.Debug("Failed to validate checkpoint", "reason", err)
pm.removePeer(peer.id)
return
}
pm.blockchain.(*light.LightChain).AddTrustedCheckpoint(cp)
pm.blockchain.(*light.LightChain).AddTrustedCheckpoint(checkpoint)
}
log.Debug("Checkpoint syncing start", "peer", peer.id, "checkpoint", cp.SectionIndex)
log.Debug("Checkpoint syncing start", "peer", peer.id, "checkpoint", checkpoint.SectionIndex)
// Fetch the start point block header.
//
@ -182,7 +197,7 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
// of the latest epoch covered by checkpoint.
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
if !cp.Empty() && !pm.blockchain.(*light.LightChain).SyncCheckpoint(ctx, cp) {
if !checkpoint.Empty() && !pm.blockchain.(*light.LightChain).SyncCheckpoint(ctx, checkpoint) {
log.Debug("Sync checkpoint failed")
pm.removePeer(peer.id)
return

View file

@ -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

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)

View file

@ -33,15 +33,6 @@ var (
GoerliGenesisHash = common.HexToHash("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a")
)
// TrustedCheckpoints associates each known checkpoint with the genesis hash of
// the chain it belongs to.
var TrustedCheckpoints = map[common.Hash]*TrustedCheckpoint{
MainnetGenesisHash: MainnetTrustedCheckpoint,
TestnetGenesisHash: TestnetTrustedCheckpoint,
RinkebyGenesisHash: RinkebyTrustedCheckpoint,
GoerliGenesisHash: GoerliTrustedCheckpoint,
}
var (
// MainnetChainConfig is the chain parameters to run a node on the main network.
MainnetChainConfig = &ChainConfig{
@ -108,16 +99,6 @@ var (
Period: 15,
Epoch: 30000,
},
CheckpointConfig: &CheckpointContractConfig{
Address: common.HexToAddress("0x62652ed8e969ce7bd5e3dd13590efa1e569215f1"),
Signers: []common.Address{
common.HexToAddress("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3"), // Peter
common.HexToAddress("0x78d1ad571a1a09d60d9bbf25894b44e4c8859595"), // Martin
common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt
common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary
},
Threshold: 2,
},
}
// RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network.
@ -128,6 +109,18 @@ var (
BloomRoot: common.HexToHash("0xa3048fe8b7e30f77f11bc755a88478363d7d3e71c2bdfe4e8ab9e269cd804ba2"),
}
// RinkebyCheckpointConfig contains a set of checkpoint contract configs for the Rinkeby test network.
RinkebyCheckpointConfig = &CheckpointContractConfig{
Address: common.HexToAddress("0x62652ed8e969ce7bd5e3dd13590efa1e569215f1"),
Signers: []common.Address{
common.HexToAddress("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3"), // Peter
common.HexToAddress("0x78d1ad571a1a09d60d9bbf25894b44e4c8859595"), // Martin
common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt
common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary
},
Threshold: 2,
}
// GoerliChainConfig contains the chain parameters to run a node on the Görli test network.
GoerliChainConfig = &ChainConfig{
ChainID: big.NewInt(5),
@ -159,16 +152,16 @@ var (
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil}
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil}
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Clique consensus.
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil}
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil}
TestRules = TestChainConfig.Rules(new(big.Int))
)
@ -242,9 +235,6 @@ type ChainConfig struct {
// Various consensus engines
Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"`
// Checkpoint contract configs
CheckpointConfig *CheckpointContractConfig `json:"checkpointContract,omitempty"`
}
// EthashConfig is the consensus engine configs for proof-of-work based sealing.