From 2f66fee3b713d2a4c5f4cc1983fdc9a7477912e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 14 Jun 2019 11:09:29 +0300 Subject: [PATCH] cmd, contracts, les, light, params: minor checkpoint sync cleanups --- cmd/puppeth/wizard_genesis.go | 121 +++++++++++++++++++++++++------ contracts/registrar/registrar.go | 6 +- les/peer.go | 4 +- les/registrar.go | 34 ++++----- les/sync.go | 10 +-- les/transactions.rlp | 0 light/lightchain.go | 2 +- params/config.go | 9 +-- 8 files changed, 126 insertions(+), 60 deletions(-) delete mode 100755 les/transactions.rlp diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index fa89e4ee79..15122f2982 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -51,12 +51,13 @@ func (w *wizard) makeGenesis() { Difficulty: big.NewInt(524288), Alloc: make(core.GenesisAlloc), Config: ¶ms.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 = ¶ms.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) diff --git a/contracts/registrar/registrar.go b/contracts/registrar/registrar.go index 45d5b80b5c..960227bc4a 100644 --- a/contracts/registrar/registrar.go +++ b/contracts/registrar/registrar.go @@ -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 . +// 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 { diff --git a/les/peer.go b/les/peer.go index 2b89c01da8..cc0547bf71 100644 --- a/les/peer.go +++ b/les/peer.go @@ -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) diff --git a/les/registrar.go b/les/registrar.go index 1e61e43fa5..41934882a7 100644 --- a/les/registrar.go +++ b/les/registrar.go @@ -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(®.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(®.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 diff --git a/les/sync.go b/les/sync.go index 53fb2d6567..54160b585e 100644 --- a/les/sync.go +++ b/les/sync.go @@ -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(): diff --git a/les/transactions.rlp b/les/transactions.rlp deleted file mode 100755 index e69de29bb2..0000000000 diff --git a/light/lightchain.go b/light/lightchain.go index daaa4e1ad9..8b787dc7e4 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -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 { diff --git a/params/config.go b/params/config.go index ba40cc5941..a472a5c43a 100644 --- a/params/config.go +++ b/params/config.go @@ -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"` }