cmd, contracts, les: discard stale checkpoint

This commit is contained in:
rjl493456442 2019-04-25 19:21:21 +08:00
parent 8d1972d793
commit ad66858ac1
4 changed files with 39 additions and 94 deletions

View file

@ -19,7 +19,6 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"math/big"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -46,7 +45,6 @@ var commandQueryCheckpoint = cli.Command{
Fetch the registered checkpoint with the specified index. Fetch the registered checkpoint with the specified index.
`, `,
Flags: []cli.Flag{ Flags: []cli.Flag{
checkpointIndexFlag,
clientURLFlag, clientURLFlag,
}, },
Action: utils.MigrateFlags(queryCheckpoint), Action: utils.MigrateFlags(queryCheckpoint),
@ -84,20 +82,11 @@ func queryAdmin(ctx *cli.Context) error {
// registrar contract. // registrar contract.
func queryCheckpoint(ctx *cli.Context) error { func queryCheckpoint(ctx *cli.Context) error {
contract := setupContract(setupDialContext(ctx)) contract := setupContract(setupDialContext(ctx))
if ctx.GlobalIsSet(checkpointIndexFlag.Name) { index, checkpoint, height, err := contract.Contract().GetLatestCheckpoint(nil)
index := ctx.GlobalInt64(checkpointIndexFlag.Name) if err != nil {
checkpoint, height, err := contract.Contract().GetCheckpoint(nil, big.NewInt(index)) return err
if err != nil {
return err
}
fmt.Printf("Checkpoint(registered at height #%d) %d => %s\n", height, index, common.Hash(checkpoint).Hex())
} else {
index, checkpoint, height, err := contract.Contract().GetLatestCheckpoint(nil)
if err != nil {
return err
}
fmt.Printf("Latest checkpoint(registered at height #%d) %d => %s\n", height, index, common.Hash(checkpoint).Hex())
} }
fmt.Printf("Latest checkpoint(registered at height #%d) %d => %s\n", height, index, common.Hash(checkpoint).Hex())
return nil return nil
} }

File diff suppressed because one or more lines are too long

View file

@ -68,22 +68,7 @@ contract Registrar {
view view
public public
returns(uint, bytes32, uint) { returns(uint, bytes32, uint) {
(bytes32 hash, uint height) = GetCheckpoint(latest); return (sectionIndex, hash, height);
return (latest, hash, height);
}
/**
* @dev Get a stable checkpoint information with specified section index.
* @param _sectionIndex section index
* @return checkpoint hash
* @return the associated register block height
*/
function GetCheckpoint(uint _sectionIndex)
view
public
returns(bytes32, uint)
{
return (checkpoints[_sectionIndex], register_height[_sectionIndex]);
} }
/** /**
@ -115,7 +100,7 @@ contract Registrar {
return false; return false;
} }
// Filter out stale announcement // Filter out stale announcement
if (_sectionIndex == latest && (latest != 0 || register_height[0] != 0)) { if (_sectionIndex == sectionIndex && (sectionIndex != 0 || height != 0)) {
return false; return false;
} }
// Filter out invalid announcement // Filter out invalid announcement
@ -134,7 +119,15 @@ contract Registrar {
bool isNew = (old == ""); bool isNew = (old == "");
pending_proposal.usermap[msg.sender] = _hash; pending_proposal.usermap[msg.sender] = _hash;
if (!isNew) { if (isNew) {
// New checkpoint announcement
pending_proposal.count += 1;
pending_proposal.index = _sectionIndex;
pending_proposal.votemap[_hash].push(Vote({
addr: msg.sender,
sig: _sig
}));
} else {
// Checkpoint modification // Checkpoint modification
Vote[] storage votes = pending_proposal.votemap[old]; Vote[] storage votes = pending_proposal.votemap[old];
for (uint i = 0; i < votes.length - 1; i++) { for (uint i = 0; i < votes.length - 1; i++) {
@ -149,21 +142,14 @@ contract Registrar {
addr: msg.sender, addr: msg.sender,
sig: _sig sig: _sig
})); }));
} else {
// New checkpoint announcement
pending_proposal.count += 1;
pending_proposal.index = _sectionIndex;
pending_proposal.votemap[_hash].push(Vote({
addr: msg.sender,
sig: _sig
}));
} }
if (pending_proposal.votemap[_hash].length < threshold) { if (pending_proposal.votemap[_hash].length < threshold) {
return true; return true;
} }
checkpoints[_sectionIndex] = _hash; // Update latest checkpoint
register_height[_sectionIndex] = block.number; hash = _hash;
latest = _sectionIndex; height = block.number;
sectionIndex = _sectionIndex;
bytes memory sigs; bytes memory sigs;
for (uint idx = 0; idx < threshold; idx++) { for (uint idx = 0; idx < threshold; idx++) {
@ -243,15 +229,15 @@ contract Registrar {
// A list of admin users so that we can obtain all admin users. // A list of admin users so that we can obtain all admin users.
address[] adminList; address[] adminList;
// Registered checkpoint information
mapping(uint => bytes32) checkpoints;
// Latest stored section id // Latest stored section id
// Note all registered checkpoint information should continuous with previous one. // Note all registered checkpoint information should continuous with previous one.
uint latest; uint sectionIndex;
// The block height associated with latest registered checkpoint. // The block height associated with latest registered checkpoint.
mapping(uint => uint) register_height; uint height;
// The hash of latest registered checkpoint.
bytes32 hash;
// The frequency for creating a checkpoint // The frequency for creating a checkpoint
// //

View file

@ -18,7 +18,6 @@
package les package les
import ( import (
"math/big"
"sync/atomic" "sync/atomic"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
@ -87,21 +86,22 @@ func (reg *checkpointRegistrar) isRunning() bool {
// stableCheckpoint returns the stable checkpoint which generated by local indexers // stableCheckpoint returns the stable checkpoint which generated by local indexers
// and announced by trusted signers. // and announced by trusted signers.
func (reg *checkpointRegistrar) stableCheckpoint() (*params.TrustedCheckpoint, uint64) { func (reg *checkpointRegistrar) stableCheckpoint() (*params.TrustedCheckpoint, uint64) {
latest, hash, _, err := reg.contract.Contract().GetLatestCheckpoint(nil) latest, hash, height, err := reg.contract.Contract().GetLatestCheckpoint(nil)
// Short circuit if the checkpoint contract is empty.
if err != nil || latest.Uint64() == 0 && hash == [32]byte{} { if err != nil || latest.Uint64() == 0 && hash == [32]byte{} {
return nil, 0 return nil, 0
} }
index := latest.Uint64() local := reg.getLocal(latest.Uint64())
for { // The following scenarios may occur:
local := reg.getLocal(index) //
hash, height, err := reg.contract.Contract().GetCheckpoint(nil, big.NewInt(int64(index))) // * local node is out of sync so that it doesn't have the
if err == nil && local.HashEqual(common.Hash(hash)) { // checkpoint which registered in the contract.
return &local, height.Uint64() // * local checkpoint doesn't match with the registered one.
} //
if index == 0 { // In both cases, server won't send the **stable** checkpoint
break // to the client(no worry, client can use hardcoded one instead).
} if local.HashEqual(common.Hash(hash)) {
index -= 1 return &local, height.Uint64()
} }
return nil, 0 return nil, 0
} }