Skip to content

Commit

Permalink
cmd, contracts, les, light, params: minor checkpoint sync cleanups
Browse files Browse the repository at this point in the history
  • Loading branch information
karalabe committed Jun 14, 2019
1 parent 9e4835a commit 40e7199
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 60 deletions.
121 changes: 97 additions & 24 deletions cmd/puppeth/wizard_genesis.go
Expand Up @@ -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
Expand Down Expand Up @@ -141,36 +142,40 @@ 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 {
if address := w.readAddress(); address != nil {
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
}
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), 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)
}
Expand All @@ -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")

Expand Down Expand Up @@ -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")

Expand Down Expand Up @@ -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)

Expand Down
6 changes: 4 additions & 2 deletions contracts/registrar/registrar.go
Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions les/peer.go
Expand Up @@ -81,7 +81,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

Expand Down Expand Up @@ -699,7 +699,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)

Expand Down
34 changes: 16 additions & 18 deletions les/registrar.go
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions les/sync.go
Expand Up @@ -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
}
Expand All @@ -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
}

Expand Down Expand Up @@ -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():
Expand Down
Empty file removed les/transactions.rlp
Empty file.
2 changes: 1 addition & 1 deletion light/lightchain.go
Expand Up @@ -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 {
Expand Down

0 comments on commit 40e7199

Please sign in to comment.