cmd, contracts, les, light, params: minor checkpoint sync cleanups

This commit is contained in:
Péter Szilágyi 2019-06-14 11:09:29 +03:00
parent d6266a5562
commit 2f66fee3b7
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
8 changed files with 126 additions and 60 deletions

View file

@ -51,12 +51,13 @@ func (w *wizard) makeGenesis() {
Difficulty: big.NewInt(524288),
Alloc: make(core.GenesisAlloc),
Config: &params.ChainConfig{
HomesteadBlock: big.NewInt(1),
EIP150Block: big.NewInt(2),
EIP155Block: big.NewInt(3),
EIP158Block: big.NewInt(3),
ByzantiumBlock: big.NewInt(4),
ConstantinopleBlock: big.NewInt(5),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
},
}
// Figure out which consensus engine to choose
@ -141,13 +142,13 @@ func (w *wizard) makeGenesis() {
// Query the user for checkpoint contract config
fmt.Println()
fmt.Println("Should checkpoint contract be deployed (default = no)")
fmt.Println("Should a checkpoint contract be deployed (y/n)? (default = no)")
if w.readDefaultYesNo(false) {
// Read the address of the trusted signers
fmt.Println("Which accounts should be the trusted signer? (advisable at least one)")
// Read the addresses of the trusted signers
fmt.Println("Which accounts should be trusted signers? (mandatory at least one)")
var (
signers []common.Address
threshold *big.Int
threshold uint64
)
// Get trusted signer addresses
for {
@ -155,14 +156,18 @@ func (w *wizard) makeGenesis() {
signers = append(signers, *address)
continue
}
if len(signers) == 0 {
continue
}
break
}
// Get stable checkpoint signature minFraction
// Read the checkpoint signature threshold
for {
fmt.Printf("What is the minimal approval threshold? (maximum %d)\n", len(signers))
threshold = w.readDefaultBigInt(big.NewInt(0))
if threshold.Int64() <= 0 || threshold.Int64() > int64(len(signers)) {
fmt.Printf("Invalid approval threshold, please enter in range [1, %d]\n", len(signers))
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
}
@ -170,7 +175,7 @@ func (w *wizard) makeGenesis() {
if err != nil {
log.Crit("Parse contract ABI failed", "err", err)
}
input, err := parsed.Pack("", signers, big.NewInt(params.CheckpointFrequency), big.NewInt(params.CheckpointProcessConfirmations), threshold)
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)
}
@ -182,21 +187,18 @@ func (w *wizard) makeGenesis() {
}
config.State.Commit(true)
genesis.Alloc[address] = core.GenesisAccount{Code: code, Storage: make(map[common.Hash]common.Hash), Balance: big.NewInt(1)}
err = config.State.ForEachStorage(address, func(key, value common.Hash) bool {
if err = config.State.ForEachStorage(address, func(key, value common.Hash) bool {
genesis.Alloc[address].Storage[key] = value
return true
})
if err != nil {
}); err != nil {
log.Crit("Failed to iterate contract storage", "err", err)
}
genesis.Config.CheckpointConfig = &params.CheckpointContractConfig{
Name: w.network,
Address: address,
Signers: signers,
Threshold: threshold.Uint64(),
Threshold: threshold,
}
}
// All done, store the genesis and flush to disk
log.Info("Configured new genesis block")
@ -256,7 +258,7 @@ func (w *wizard) importGenesis() {
func (w *wizard) manageGenesis() {
// Figure out whether to modify or export the genesis
fmt.Println()
fmt.Println(" 1. Modify existing fork rules")
fmt.Println(" 1. Modify existing configurations")
fmt.Println(" 2. Export genesis configurations")
fmt.Println(" 3. Remove genesis configuration")
@ -291,9 +293,80 @@ func (w *wizard) manageGenesis() {
w.conf.Genesis.Config.PetersburgBlock = w.conf.Genesis.Config.ConstantinopleBlock
}
fmt.Println()
fmt.Printf("Which block should Constantinople-Fix (remove EIP-1283) come into effect? (default = %v)\n", w.conf.Genesis.Config.PetersburgBlock)
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

@ -14,6 +14,7 @@
// 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/>.
// Package registrar is a an on-chain light client checkpoint oracle.
package registrar
//go:generate abigen --sol contract/registrar.sol --pkg contract --out contract/registrar.go
@ -29,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
)
// Registrar is a Go wrapper around an on-chain light client checkpoint oracle.
type Registrar struct {
contract *contract.Contract
}
@ -47,9 +49,9 @@ func (registrar *Registrar) Contract() *contract.Contract {
return registrar.contract
}
// LookupCheckpointEvent searches checkpoint event for specific section in the
// LookupCheckpointEvents searches checkpoint event for specific section in the
// given log batches.
func (registrar *Registrar) LookupCheckpointEvent(blockLogs [][]*types.Log, section uint64, hash common.Hash) []*contract.ContractNewCheckpointVote {
func (registrar *Registrar) LookupCheckpointEvents(blockLogs [][]*types.Log, section uint64, hash common.Hash) []*contract.ContractNewCheckpointVote {
var votes []*contract.ContractNewCheckpointVote
for _, logs := range blockLogs {

View file

@ -83,7 +83,7 @@ type peer struct {
// Checkpoint relative fields
advertisedCheckpoint params.TrustedCheckpoint
registeredHeight uint64
isHardcode bool // Indicator whether the checkpoint is hardcoded
hardcodedCheckpoint bool // Indicator whether the checkpoint is hardcoded
id string
@ -702,7 +702,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
if err := recv.get("checkpoint/value", &p.advertisedCheckpoint); hardcoded != nil &&
(err != nil || p.advertisedCheckpoint.SectionIndex < hardcoded.SectionIndex) {
p.advertisedCheckpoint = *hardcoded
p.isHardcode = true
p.hardcodedCheckpoint = true
}
recv.get("checkpoint/registerHeight", &p.registeredHeight)

View file

@ -30,9 +30,8 @@ import (
)
// checkpointRegistrar is responsible for offering the latest stable checkpoint
// which generated by local and announced by contract admins in the server
// side and verifying advertised checkpoint during the checkpoint syncing
// in the client side.
// generated and announced by the contract admins on-chain. The checkpoint is
// verified by clients locally during the checkpoint syncing.
type checkpointRegistrar struct {
config *params.CheckpointContractConfig
contract *registrar.Registrar
@ -51,11 +50,11 @@ func newCheckpointRegistrar(config *params.CheckpointContractConfig, getLocal fu
return nil
}
if config.Address == (common.Address{}) || uint64(len(config.Signers)) < config.Threshold {
log.Warn("Invalid checkpoint contract config")
log.Warn("Invalid checkpoint registrar config")
return nil
}
log.Info("Setup checkpoint registrar", "contract", config.Address, "numsigner", len(config.Signers),
"threshold", config.Threshold)
log.Info("Configured checkpoint registrar", "address", config.Address, "signers", len(config.Signers), "threshold", config.Threshold)
return &checkpointRegistrar{
config: config,
getLocal: getLocal,
@ -67,11 +66,11 @@ func newCheckpointRegistrar(config *params.CheckpointContractConfig, getLocal fu
func (reg *checkpointRegistrar) start(backend bind.ContractBackend) {
contract, err := registrar.NewRegistrar(reg.config.Address, backend)
if err != nil {
log.Info("Registrar contract binding failed", "err", err)
log.Error("Registrar contract binding failed", "err", err)
return
}
if !atomic.CompareAndSwapInt32(&reg.running, 0, 1) {
log.Info("Already bound and listening to registrar contract")
log.Error("Already bound and listening to registrar")
return
}
reg.contract = contract
@ -82,13 +81,12 @@ func (reg *checkpointRegistrar) isRunning() bool {
return atomic.LoadInt32(&reg.running) == 1
}
// stableCheckpoint returns the stable checkpoint which generated by local indexers
// and announced by trusted signers.
// stableCheckpoint returns the stable checkpoint which was generated by local
// indexers and announced by trusted signers.
func (reg *checkpointRegistrar) stableCheckpoint() (*params.TrustedCheckpoint, uint64) {
// Retrieve the latest checkpoint from the contract, abort if empty
latest, hash, height, err := reg.contract.Contract().GetLatestCheckpoint(nil)
// Short circuit if the checkpoint contract is empty.
if err != nil || latest == 0 && hash == [32]byte{} {
if err != nil || (latest == 0 && hash == [32]byte{}) {
return nil, 0
}
local := reg.getLocal(latest)
@ -107,9 +105,9 @@ func (reg *checkpointRegistrar) stableCheckpoint() (*params.TrustedCheckpoint, u
return nil, 0
}
// VerifySigner recovers the signer address according to the signature and
// checks whether there are enough approves to finalize the checkpoint.
func (reg *checkpointRegistrar) verifySigner(index uint64, hash [32]byte, signatures [][]byte) (bool, []common.Address) {
// verifySigners recovers the signer addresses according to the signature and
// checks whether there are enough approvals to finalize the checkpoint.
func (reg *checkpointRegistrar) verifySigners(index uint64, hash [32]byte, signatures [][]byte) (bool, []common.Address) {
// Short circuit if the given signatures doesn't reach the threshold.
if len(signatures) < int(reg.config.Threshold) {
return false, nil
@ -118,7 +116,7 @@ func (reg *checkpointRegistrar) verifySigner(index uint64, hash [32]byte, signat
signers []common.Address
checked = make(map[common.Address]struct{})
)
for i := 0; i < len(signatures); i += 1 {
for i := 0; i < len(signatures); i++ {
if len(signatures[i]) != 65 {
continue
}
@ -154,7 +152,7 @@ func (reg *checkpointRegistrar) verifySigner(index uint64, hash [32]byte, signat
}
threshold := reg.config.Threshold
if uint64(len(signers)) < threshold {
log.Warn("Not enough signatures to approve checkpoint", "given", len(signers), "want", threshold)
log.Warn("Not enough signers to approve checkpoint", "signers", len(signers), "threshold", threshold)
return false, nil
}
return true, signers

View file

@ -96,7 +96,7 @@ func (pm *ProtocolManager) validateCheckpoint(peer *peer) error {
if err != nil {
return err
}
events := pm.reg.contract.LookupCheckpointEvent(logs, cp.SectionIndex, cp.Hash())
events := pm.reg.contract.LookupCheckpointEvents(logs, cp.SectionIndex, cp.Hash())
if len(events) == 0 {
return errInvalidCheckpoint
}
@ -108,11 +108,11 @@ func (pm *ProtocolManager) validateCheckpoint(peer *peer) error {
for _, event := range events {
signatures = append(signatures, append(event.R[:], append(event.S[:], event.V)...))
}
valid, signers := pm.reg.verifySigner(index, hash, signatures)
valid, signers := pm.reg.verifySigners(index, hash, signatures)
if !valid {
return errInvalidCheckpoint
}
log.Debug("Verify advertised checkpoint successfully", "peer", peer.id, "signernum", len(signers))
log.Warn("Verifed advertised checkpoint", "peer", peer.id, "signers", len(signers))
return nil
}
@ -144,8 +144,8 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
log.Debug("Disable checkpoint syncing", "reason", "empty checkpoint")
case latest.Number.Uint64() >= (cp.SectionIndex+1)*pm.iConfig.ChtSize-1:
mode = lightSync
log.Debug("Disable checkpoint syncing", "reason", "local chain beyonds the checkpoint")
case peer.isHardcode:
log.Debug("Disable checkpoint syncing", "reason", "local chain beyond the checkpoint")
case peer.hardcodedCheckpoint:
mode = legacyCheckpointSync
log.Debug("Disable checkpoint syncing", "reason", "checkpoint is hardcoded")
case pm.reg == nil || !pm.reg.isRunning():

View file

View file

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

View file

@ -61,7 +61,6 @@ var (
// MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network.
MainnetTrustedCheckpoint = &TrustedCheckpoint{
Name: "mainnet",
SectionIndex: 227,
SectionHead: common.HexToHash("0xa2e0b25d72c2fc6e35a7f853cdacb193b4b4f95c606accf7f8fa8415283582c7"),
CHTRoot: common.HexToHash("0xf69bdd4053b95b61a27b106a0e86103d791edd8574950dc96aa351ab9b9f1aa0"),
@ -86,7 +85,6 @@ var (
// TestnetTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network.
TestnetTrustedCheckpoint = &TrustedCheckpoint{
Name: "testnet",
SectionIndex: 161,
SectionHead: common.HexToHash("0x5378afa734e1feafb34bcca1534c4d96952b754579b96a4afb23d5301ecececc"),
CHTRoot: common.HexToHash("0x1cf2b071e7443a62914362486b613ff30f60cea0d9c268ed8c545f876a3ee60c"),
@ -111,7 +109,6 @@ var (
Epoch: 30000,
},
CheckpointConfig: &CheckpointContractConfig{
Name: "rinkeby",
Address: common.HexToAddress("0x62652ed8e969ce7bd5e3dd13590efa1e569215f1"),
Signers: []common.Address{
common.HexToAddress("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3"), // Peter
@ -125,7 +122,6 @@ var (
// RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network.
RinkebyTrustedCheckpoint = &TrustedCheckpoint{
Name: "rinkeby",
SectionIndex: 125,
SectionHead: common.HexToHash("0x8a738386f6bb34add15846f8f49c4c519a2f32519096e792b9f43bcb407c831c"),
CHTRoot: common.HexToHash("0xa1e5720a9bad4dce794f129e4ac6744398197b652868011486a6f89c8ec84a75"),
@ -152,7 +148,6 @@ var (
// GoerliTrustedCheckpoint contains the light client trusted checkpoint for the Görli test network.
GoerliTrustedCheckpoint = &TrustedCheckpoint{
Name: "goerli",
SectionIndex: 9,
SectionHead: common.HexToHash("0x8e223d827391eee53b07cb8ee057dbfa11c93e0b45352188c783affd7840a921"),
CHTRoot: common.HexToHash("0xe0a817ac69b36c1e437c5b0cff9e764853f5115702b5f66d451b665d6afb7e78"),
@ -182,7 +177,6 @@ var (
// used to start light syncing from this checkpoint and avoid downloading the
// entire header chain while still being able to securely access old headers/logs.
type TrustedCheckpoint struct {
Name string `json:"-"`
SectionIndex uint64 `json:"sectionIndex"`
SectionHead common.Hash `json:"sectionHead"`
CHTRoot common.Hash `json:"chtRoot"`
@ -215,8 +209,7 @@ func (c *TrustedCheckpoint) Empty() bool {
// CheckpointContractConfig represents a set of checkpoint contract config
// which used for light client checkpoint syncing.
type CheckpointContractConfig struct {
Name string `json:"-"`
Address common.Address `json:"contractAddr"`
Address common.Address `json:"address"`
Signers []common.Address `json:"signers"`
Threshold uint64 `json:"threshold"`
}