mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
Merge pull request #410 from cffls/v0.3.0-dev-lint
Lint consensus/bor and internal/cli
This commit is contained in:
commit
96228cc2dd
34 changed files with 417 additions and 99 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -6,7 +6,7 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- "**"
|
- "**"
|
||||||
types: [opened, synchronize]
|
types: [opened, synchronize, edited]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: build-${{ github.event.pull_request.number || github.ref }}
|
group: build-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ linters:
|
||||||
- exportloopref
|
- exportloopref
|
||||||
- gocognit
|
- gocognit
|
||||||
- gofmt
|
- gofmt
|
||||||
- gomnd
|
# - gomnd
|
||||||
- gomoddirectives
|
- gomoddirectives
|
||||||
- gosec
|
- gosec
|
||||||
- makezero
|
- makezero
|
||||||
|
|
@ -42,7 +42,7 @@ linters:
|
||||||
- predeclared
|
- predeclared
|
||||||
#- promlinter
|
#- promlinter
|
||||||
#- revive
|
#- revive
|
||||||
- tagliatelle
|
# - tagliatelle
|
||||||
- tenv
|
- tenv
|
||||||
- thelper
|
- thelper
|
||||||
- tparallel
|
- tparallel
|
||||||
|
|
@ -65,7 +65,7 @@ linters-settings:
|
||||||
local-prefixes: github.com/ethereum/go-ethereum
|
local-prefixes: github.com/ethereum/go-ethereum
|
||||||
|
|
||||||
nestif:
|
nestif:
|
||||||
min-complexity: 3
|
min-complexity: 5
|
||||||
|
|
||||||
prealloc:
|
prealloc:
|
||||||
for-loops: true
|
for-loops: true
|
||||||
|
|
@ -183,4 +183,4 @@ issues:
|
||||||
max-issues-per-linter: 0
|
max-issues-per-linter: 0
|
||||||
max-same-issues: 0
|
max-same-issues: 0
|
||||||
#new: true
|
#new: true
|
||||||
new-from-rev: origin/master
|
# new-from-rev: origin/master
|
||||||
4
Makefile
4
Makefile
|
|
@ -65,7 +65,9 @@ escape:
|
||||||
cd $(path) && go test -gcflags "-m -m" -run none -bench=BenchmarkJumpdest* -benchmem -memprofile mem.out
|
cd $(path) && go test -gcflags "-m -m" -run none -bench=BenchmarkJumpdest* -benchmem -memprofile mem.out
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
@./build/bin/golangci-lint run --config ./.golangci.yml
|
@./build/bin/golangci-lint run --config ./.golangci.yml \
|
||||||
|
internal/cli \
|
||||||
|
consensus/bor
|
||||||
|
|
||||||
lintci-deps:
|
lintci-deps:
|
||||||
rm -f ./build/bin/golangci-lint
|
rm -f ./build/bin/golangci-lint
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
"github.com/xsleonard/go-merkle"
|
"github.com/xsleonard/go-merkle"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
@ -44,6 +45,7 @@ func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,11 +61,11 @@ type difficultiesKV struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func rankMapDifficulties(values map[common.Address]uint64) []difficultiesKV {
|
func rankMapDifficulties(values map[common.Address]uint64) []difficultiesKV {
|
||||||
|
ss := make([]difficultiesKV, 0, len(values))
|
||||||
var ss []difficultiesKV
|
|
||||||
for k, v := range values {
|
for k, v := range values {
|
||||||
ss = append(ss, difficultiesKV{k, v})
|
ss = append(ss, difficultiesKV{k, v})
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(ss, func(i, j int) bool {
|
sort.Slice(ss, func(i, j int) bool {
|
||||||
return ss[i].Difficulty > ss[j].Difficulty
|
return ss[i].Difficulty > ss[j].Difficulty
|
||||||
})
|
})
|
||||||
|
|
@ -74,11 +76,15 @@ func rankMapDifficulties(values map[common.Address]uint64) []difficultiesKV {
|
||||||
// GetSnapshotProposerSequence retrieves the in-turn signers of all sprints in a span
|
// GetSnapshotProposerSequence retrieves the in-turn signers of all sprints in a span
|
||||||
func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigners, error) {
|
func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigners, error) {
|
||||||
snapNumber := *number - 1
|
snapNumber := *number - 1
|
||||||
|
|
||||||
var difficulties = make(map[common.Address]uint64)
|
var difficulties = make(map[common.Address]uint64)
|
||||||
|
|
||||||
snap, err := api.GetSnapshot(&snapNumber)
|
snap, err := api.GetSnapshot(&snapNumber)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return BlockSigners{}, err
|
return BlockSigners{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
proposer := snap.ValidatorSet.GetProposer().Address
|
proposer := snap.ValidatorSet.GetProposer().Address
|
||||||
proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
|
proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
|
||||||
|
|
||||||
|
|
@ -88,6 +94,7 @@ func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigne
|
||||||
if tempIndex < proposerIndex {
|
if tempIndex < proposerIndex {
|
||||||
tempIndex = tempIndex + len(signers)
|
tempIndex = tempIndex + len(signers)
|
||||||
}
|
}
|
||||||
|
|
||||||
difficulties[signers[i]] = uint64(len(signers) - (tempIndex - proposerIndex))
|
difficulties[signers[i]] = uint64(len(signers) - (tempIndex - proposerIndex))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,6 +104,7 @@ func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigne
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return BlockSigners{}, err
|
return BlockSigners{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
diff := int(difficulties[*author])
|
diff := int(difficulties[*author])
|
||||||
blockSigners := &BlockSigners{
|
blockSigners := &BlockSigners{
|
||||||
Signers: rankedDifficulties,
|
Signers: rankedDifficulties,
|
||||||
|
|
@ -111,9 +119,11 @@ func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigne
|
||||||
func (api *API) GetSnapshotProposer(number *rpc.BlockNumber) (common.Address, error) {
|
func (api *API) GetSnapshotProposer(number *rpc.BlockNumber) (common.Address, error) {
|
||||||
*number -= 1
|
*number -= 1
|
||||||
snap, err := api.GetSnapshot(number)
|
snap, err := api.GetSnapshot(number)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.ValidatorSet.GetProposer().Address, nil
|
return snap.ValidatorSet.GetProposer().Address, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,7 +140,9 @@ func (api *API) GetAuthor(number *rpc.BlockNumber) (*common.Address, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
author, err := api.bor.Author(header)
|
author, err := api.bor.Author(header)
|
||||||
|
|
||||||
return &author, err
|
return &author, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,6 +152,7 @@ func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,10 +169,13 @@ func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.signers(), nil
|
return snap.signers(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,10 +185,13 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.signers(), nil
|
return snap.signers(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,6 +201,7 @@ func (api *API) GetCurrentProposer() (common.Address, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.ValidatorSet.GetProposer().Address, nil
|
return snap.ValidatorSet.GetProposer().Address, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,6 +211,7 @@ func (api *API) GetCurrentValidators() ([]*Validator, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return make([]*Validator, 0), err
|
return make([]*Validator, 0), err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.ValidatorSet.Validators, nil
|
return snap.ValidatorSet.Validators, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,26 +220,36 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
||||||
if err := api.initializeRootHashCache(); err != nil {
|
if err := api.initializeRootHashCache(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
key := getRootHashKey(start, end)
|
key := getRootHashKey(start, end)
|
||||||
|
|
||||||
if root, known := api.rootHashCache.Get(key); known {
|
if root, known := api.rootHashCache.Get(key); known {
|
||||||
return root.(string), nil
|
return root.(string), nil
|
||||||
}
|
}
|
||||||
length := uint64(end - start + 1)
|
|
||||||
|
length := end - start + 1
|
||||||
|
|
||||||
if length > MaxCheckpointLength {
|
if length > MaxCheckpointLength {
|
||||||
return "", &MaxCheckpointLengthExceededError{start, end}
|
return "", &MaxCheckpointLengthExceededError{start, end}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
|
currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
|
||||||
|
|
||||||
if start > end || end > currentHeaderNumber {
|
if start > end || end > currentHeaderNumber {
|
||||||
return "", &InvalidStartEndBlockError{start, end, currentHeaderNumber}
|
return "", &InvalidStartEndBlockError{start, end, currentHeaderNumber}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockHeaders := make([]*types.Header, end-start+1)
|
blockHeaders := make([]*types.Header, end-start+1)
|
||||||
wg := new(sync.WaitGroup)
|
wg := new(sync.WaitGroup)
|
||||||
concurrent := make(chan bool, 20)
|
concurrent := make(chan bool, 20)
|
||||||
|
|
||||||
for i := start; i <= end; i++ {
|
for i := start; i <= end; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
concurrent <- true
|
concurrent <- true
|
||||||
|
|
||||||
go func(number uint64) {
|
go func(number uint64) {
|
||||||
blockHeaders[number-start] = api.chain.GetHeaderByNumber(uint64(number))
|
blockHeaders[number-start] = api.chain.GetHeaderByNumber(number)
|
||||||
|
|
||||||
<-concurrent
|
<-concurrent
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(i)
|
}(i)
|
||||||
|
|
@ -227,6 +258,7 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
||||||
close(concurrent)
|
close(concurrent)
|
||||||
|
|
||||||
headers := make([][32]byte, nextPowerOfTwo(length))
|
headers := make([][32]byte, nextPowerOfTwo(length))
|
||||||
|
|
||||||
for i := 0; i < len(blockHeaders); i++ {
|
for i := 0; i < len(blockHeaders); i++ {
|
||||||
blockHeader := blockHeaders[i]
|
blockHeader := blockHeaders[i]
|
||||||
header := crypto.Keccak256(appendBytes32(
|
header := crypto.Keccak256(appendBytes32(
|
||||||
|
|
@ -237,6 +269,7 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
||||||
))
|
))
|
||||||
|
|
||||||
var arr [32]byte
|
var arr [32]byte
|
||||||
|
|
||||||
copy(arr[:], header)
|
copy(arr[:], header)
|
||||||
headers[i] = arr
|
headers[i] = arr
|
||||||
}
|
}
|
||||||
|
|
@ -245,8 +278,10 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
||||||
if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil {
|
if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
root := hex.EncodeToString(tree.Root().Hash)
|
root := hex.EncodeToString(tree.Root().Hash)
|
||||||
api.rootHashCache.Add(key, root)
|
api.rootHashCache.Add(key, root)
|
||||||
|
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,6 +290,7 @@ func (api *API) initializeRootHashCache() error {
|
||||||
if api.rootHashCache == nil {
|
if api.rootHashCache == nil {
|
||||||
api.rootHashCache, err = lru.NewARC(10)
|
api.rootHashCache, err = lru.NewARC(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -56,9 +55,6 @@ var (
|
||||||
|
|
||||||
uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
|
uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
|
||||||
|
|
||||||
diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures
|
|
||||||
diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures
|
|
||||||
|
|
||||||
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
|
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
|
||||||
systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE")
|
systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE")
|
||||||
)
|
)
|
||||||
|
|
@ -72,18 +68,6 @@ var (
|
||||||
// that is not part of the local blockchain.
|
// that is not part of the local blockchain.
|
||||||
errUnknownBlock = errors.New("unknown block")
|
errUnknownBlock = errors.New("unknown block")
|
||||||
|
|
||||||
// errInvalidCheckpointBeneficiary is returned if a checkpoint/epoch transition
|
|
||||||
// block has a beneficiary set to non-zeroes.
|
|
||||||
errInvalidCheckpointBeneficiary = errors.New("beneficiary in checkpoint block non-zero")
|
|
||||||
|
|
||||||
// errInvalidVote is returned if a nonce value is something else that the two
|
|
||||||
// allowed constants of 0x00..0 or 0xff..f.
|
|
||||||
errInvalidVote = errors.New("vote nonce not 0x00..0 or 0xff..f")
|
|
||||||
|
|
||||||
// errInvalidCheckpointVote is returned if a checkpoint/epoch transition block
|
|
||||||
// has a vote nonce set to non-zeroes.
|
|
||||||
errInvalidCheckpointVote = errors.New("vote nonce in checkpoint block non-zero")
|
|
||||||
|
|
||||||
// errMissingVanity is returned if a block's extra-data section is shorter than
|
// errMissingVanity is returned if a block's extra-data section is shorter than
|
||||||
// 32 bytes, which is required to store the signer vanity.
|
// 32 bytes, which is required to store the signer vanity.
|
||||||
errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing")
|
errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing")
|
||||||
|
|
@ -136,6 +120,7 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache, c *params.BorConfig
|
||||||
if len(header.Extra) < extraSeal {
|
if len(header.Extra) < extraSeal {
|
||||||
return common.Address{}, errMissingSignature
|
return common.Address{}, errMissingSignature
|
||||||
}
|
}
|
||||||
|
|
||||||
signature := header.Extra[len(header.Extra)-extraSeal:]
|
signature := header.Extra[len(header.Extra)-extraSeal:]
|
||||||
|
|
||||||
// Recover the public key and the Ethereum address
|
// Recover the public key and the Ethereum address
|
||||||
|
|
@ -143,10 +128,13 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache, c *params.BorConfig
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var signer common.Address
|
var signer common.Address
|
||||||
|
|
||||||
copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
|
copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
|
||||||
|
|
||||||
sigcache.Add(hash, signer)
|
sigcache.Add(hash, signer)
|
||||||
|
|
||||||
return signer, nil
|
return signer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,6 +143,7 @@ func SealHash(header *types.Header, c *params.BorConfig) (hash common.Hash) {
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
hasher := sha3.NewLegacyKeccak256()
|
||||||
encodeSigHeader(hasher, header, c)
|
encodeSigHeader(hasher, header, c)
|
||||||
hasher.Sum(hash[:0])
|
hasher.Sum(hash[:0])
|
||||||
|
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,11 +165,13 @@ func encodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) {
|
||||||
header.MixDigest,
|
header.MixDigest,
|
||||||
header.Nonce,
|
header.Nonce,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.IsJaipur(header.Number.Uint64()) {
|
if c.IsJaipur(header.Number.Uint64()) {
|
||||||
if header.BaseFee != nil {
|
if header.BaseFee != nil {
|
||||||
enc = append(enc, header.BaseFee)
|
enc = append(enc, header.BaseFee)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rlp.Encode(w, enc); err != nil {
|
if err := rlp.Encode(w, enc); err != nil {
|
||||||
panic("can't encode: " + err.Error())
|
panic("can't encode: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -194,9 +185,11 @@ func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint6
|
||||||
if number%c.Sprint == 0 {
|
if number%c.Sprint == 0 {
|
||||||
delay = c.ProducerDelay
|
delay = c.ProducerDelay
|
||||||
}
|
}
|
||||||
|
|
||||||
if succession > 0 {
|
if succession > 0 {
|
||||||
delay += uint64(succession) * c.CalculateBackupMultiplier(number)
|
delay += uint64(succession) * c.CalculateBackupMultiplier(number)
|
||||||
}
|
}
|
||||||
|
|
||||||
return delay
|
return delay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,6 +203,7 @@ func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint6
|
||||||
func BorRLP(header *types.Header, c *params.BorConfig) []byte {
|
func BorRLP(header *types.Header, c *params.BorConfig) []byte {
|
||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
encodeSigHeader(b, header, c)
|
encodeSigHeader(b, header, c)
|
||||||
|
|
||||||
return b.Bytes()
|
return b.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +227,6 @@ type Bor struct {
|
||||||
HeimdallClient IHeimdallClient
|
HeimdallClient IHeimdallClient
|
||||||
WithoutHeimdall bool
|
WithoutHeimdall bool
|
||||||
|
|
||||||
scope event.SubscriptionScope
|
|
||||||
// The fields below are for testing only
|
// The fields below are for testing only
|
||||||
fakeDiff bool // Skip difficulty verifications
|
fakeDiff bool // Skip difficulty verifications
|
||||||
}
|
}
|
||||||
|
|
@ -314,6 +307,7 @@ func (c *Bor) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return abort, results
|
return abort, results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,6 +319,7 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
|
||||||
if header.Number == nil {
|
if header.Number == nil {
|
||||||
return errUnknownBlock
|
return errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
|
|
||||||
// Don't waste time checking blocks from the future
|
// Don't waste time checking blocks from the future
|
||||||
|
|
@ -344,32 +339,40 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
|
||||||
if !isSprintEnd && signersBytes != 0 {
|
if !isSprintEnd && signersBytes != 0 {
|
||||||
return errExtraValidators
|
return errExtraValidators
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSprintEnd && signersBytes%validatorHeaderBytesLength != 0 {
|
if isSprintEnd && signersBytes%validatorHeaderBytesLength != 0 {
|
||||||
return errInvalidSpanValidators
|
return errInvalidSpanValidators
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the mix digest is zero as we don't have fork protection currently
|
// Ensure that the mix digest is zero as we don't have fork protection currently
|
||||||
if header.MixDigest != (common.Hash{}) {
|
if header.MixDigest != (common.Hash{}) {
|
||||||
return errInvalidMixDigest
|
return errInvalidMixDigest
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the block doesn't contain any uncles which are meaningless in PoA
|
// Ensure that the block doesn't contain any uncles which are meaningless in PoA
|
||||||
if header.UncleHash != uncleHash {
|
if header.UncleHash != uncleHash {
|
||||||
return errInvalidUncleHash
|
return errInvalidUncleHash
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the block's difficulty is meaningful (may not be correct at this point)
|
// Ensure that the block's difficulty is meaningful (may not be correct at this point)
|
||||||
if number > 0 {
|
if number > 0 {
|
||||||
if header.Difficulty == nil {
|
if header.Difficulty == nil {
|
||||||
return errInvalidDifficulty
|
return errInvalidDifficulty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that the gas limit is <= 2^63-1
|
// Verify that the gas limit is <= 2^63-1
|
||||||
cap := uint64(0x7fffffffffffffff)
|
gasCap := uint64(0x7fffffffffffffff)
|
||||||
if header.GasLimit > cap {
|
|
||||||
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap)
|
if header.GasLimit > gasCap {
|
||||||
|
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, gasCap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If all checks passed, validate any special fields for hard forks
|
// If all checks passed, validate any special fields for hard forks
|
||||||
if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil {
|
if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// All basic checks passed, verify cascading fields
|
// All basic checks passed, verify cascading fields
|
||||||
return c.verifyCascadingFields(chain, header, parents)
|
return c.verifyCascadingFields(chain, header, parents)
|
||||||
}
|
}
|
||||||
|
|
@ -380,9 +383,11 @@ func validateHeaderExtraField(extraBytes []byte) error {
|
||||||
if len(extraBytes) < extraVanity {
|
if len(extraBytes) < extraVanity {
|
||||||
return errMissingVanity
|
return errMissingVanity
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(extraBytes) < extraVanity+extraSeal {
|
if len(extraBytes) < extraVanity+extraSeal {
|
||||||
return errMissingSignature
|
return errMissingSignature
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,12 +398,14 @@ func validateHeaderExtraField(extraBytes []byte) error {
|
||||||
func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error {
|
func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error {
|
||||||
// The genesis block is the always valid dead-end
|
// The genesis block is the always valid dead-end
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
|
|
||||||
if number == 0 {
|
if number == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the block's timestamp isn't too close to it's parent
|
// Ensure that the block's timestamp isn't too close to it's parent
|
||||||
var parent *types.Header
|
var parent *types.Header
|
||||||
|
|
||||||
if len(parents) > 0 {
|
if len(parents) > 0 {
|
||||||
parent = parents[len(parents)-1]
|
parent = parents[len(parents)-1]
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -413,11 +420,13 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
|
||||||
if header.GasUsed > header.GasLimit {
|
if header.GasUsed > header.GasLimit {
|
||||||
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !chain.Config().IsLondon(header.Number) {
|
if !chain.Config().IsLondon(header.Number) {
|
||||||
// Verify BaseFee not present before EIP-1559 fork.
|
// Verify BaseFee not present before EIP-1559 fork.
|
||||||
if header.BaseFee != nil {
|
if header.BaseFee != nil {
|
||||||
return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee)
|
return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
|
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -432,6 +441,7 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
|
||||||
|
|
||||||
// Retrieve the snapshot needed to verify this header and cache it
|
// Retrieve the snapshot needed to verify this header and cache it
|
||||||
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
|
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -444,6 +454,7 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
|
||||||
currentValidators := snap.ValidatorSet.Copy().Validators
|
currentValidators := snap.ValidatorSet.Copy().Validators
|
||||||
// sort validator by address
|
// sort validator by address
|
||||||
sort.Sort(ValidatorsByAddress(currentValidators))
|
sort.Sort(ValidatorsByAddress(currentValidators))
|
||||||
|
|
||||||
for i, validator := range currentValidators {
|
for i, validator := range currentValidators {
|
||||||
copy(validatorsBytes[i*validatorHeaderBytesLength:], validator.HeaderBytes())
|
copy(validatorsBytes[i*validatorHeaderBytesLength:], validator.HeaderBytes())
|
||||||
}
|
}
|
||||||
|
|
@ -458,17 +469,19 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
|
||||||
}
|
}
|
||||||
|
|
||||||
// snapshot retrieves the authorization snapshot at a given point in time.
|
// snapshot retrieves the authorization snapshot at a given point in time.
|
||||||
|
// nolint: gocognit
|
||||||
func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) {
|
func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) {
|
||||||
// Search for a snapshot in memory or on disk for checkpoints
|
// Search for a snapshot in memory or on disk for checkpoints
|
||||||
var (
|
var snap *Snapshot
|
||||||
headers []*types.Header
|
|
||||||
snap *Snapshot
|
|
||||||
)
|
|
||||||
|
|
||||||
|
headers := make([]*types.Header, 0, 16)
|
||||||
|
|
||||||
|
//nolint:govet
|
||||||
for snap == nil {
|
for snap == nil {
|
||||||
// If an in-memory snapshot was found, use that
|
// If an in-memory snapshot was found, use that
|
||||||
if s, ok := c.recents.Get(hash); ok {
|
if s, ok := c.recents.Get(hash); ok {
|
||||||
snap = s.(*Snapshot)
|
snap = s.(*Snapshot)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -476,7 +489,9 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
||||||
if number%checkpointInterval == 0 {
|
if number%checkpointInterval == 0 {
|
||||||
if s, err := loadSnapshot(c.config, c.signatures, c.db, hash, c.ethAPI); err == nil {
|
if s, err := loadSnapshot(c.config, c.signatures, c.db, hash, c.ethAPI); err == nil {
|
||||||
log.Trace("Loaded snapshot from disk", "number", number, "hash", hash)
|
log.Trace("Loaded snapshot from disk", "number", number, "hash", hash)
|
||||||
|
|
||||||
snap = s
|
snap = s
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -486,6 +501,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
||||||
// up more headers than allowed to be reorged (chain reinit from a freezer),
|
// up more headers than allowed to be reorged (chain reinit from a freezer),
|
||||||
// consider the checkpoint trusted and snapshot it.
|
// consider the checkpoint trusted and snapshot it.
|
||||||
// TODO fix this
|
// TODO fix this
|
||||||
|
// nolint:nestif
|
||||||
if number == 0 {
|
if number == 0 {
|
||||||
checkpoint := chain.GetHeaderByNumber(number)
|
checkpoint := chain.GetHeaderByNumber(number)
|
||||||
if checkpoint != nil {
|
if checkpoint != nil {
|
||||||
|
|
@ -503,7 +519,9 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
||||||
if err := snap.store(c.db); err != nil {
|
if err := snap.store(c.db); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash)
|
log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -516,6 +534,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
||||||
if header.Hash() != hash || header.Number.Uint64() != number {
|
if header.Hash() != hash || header.Number.Uint64() != number {
|
||||||
return nil, consensus.ErrUnknownAncestor
|
return nil, consensus.ErrUnknownAncestor
|
||||||
}
|
}
|
||||||
|
|
||||||
parents = parents[:len(parents)-1]
|
parents = parents[:len(parents)-1]
|
||||||
} else {
|
} else {
|
||||||
// No explicit parents (or no more left), reach out to the database
|
// No explicit parents (or no more left), reach out to the database
|
||||||
|
|
@ -524,10 +543,13 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
||||||
return nil, consensus.ErrUnknownAncestor
|
return nil, consensus.ErrUnknownAncestor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
headers = append(headers, header)
|
headers = append(headers, header)
|
||||||
number, hash = number-1, header.ParentHash
|
number, hash = number-1, header.ParentHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info("Snapshot has been found in %d headers depth.", len(headers))
|
||||||
|
|
||||||
// check if snapshot is nil
|
// check if snapshot is nil
|
||||||
if snap == nil {
|
if snap == nil {
|
||||||
return nil, fmt.Errorf("Unknown error while retrieving snapshot at block number %v", number)
|
return nil, fmt.Errorf("Unknown error while retrieving snapshot at block number %v", number)
|
||||||
|
|
@ -542,6 +564,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.recents.Add(snap.Hash, snap)
|
c.recents.Add(snap.Hash, snap)
|
||||||
|
|
||||||
// If we've generated a new checkpoint snapshot, save to disk
|
// If we've generated a new checkpoint snapshot, save to disk
|
||||||
|
|
@ -549,8 +572,10 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
||||||
if err = snap.store(c.db); err != nil {
|
if err = snap.store(c.db); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace("Stored snapshot to disk", "number", snap.Number, "hash", snap.Hash)
|
log.Trace("Stored snapshot to disk", "number", snap.Number, "hash", snap.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap, err
|
return snap, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -560,6 +585,7 @@ func (c *Bor) VerifyUncles(chain consensus.ChainReader, block *types.Block) erro
|
||||||
if len(block.Uncles()) > 0 {
|
if len(block.Uncles()) > 0 {
|
||||||
return errors.New("uncles not allowed")
|
return errors.New("uncles not allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -590,6 +616,7 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
||||||
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
|
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
|
||||||
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
|
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
|
||||||
|
|
@ -643,6 +670,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
|
||||||
if len(header.Extra) < extraVanity {
|
if len(header.Extra) < extraVanity {
|
||||||
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
|
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
header.Extra = header.Extra[:extraVanity]
|
header.Extra = header.Extra[:extraVanity]
|
||||||
|
|
||||||
// get validator set if number
|
// get validator set if number
|
||||||
|
|
@ -654,6 +682,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
|
||||||
|
|
||||||
// sort validator by address
|
// sort validator by address
|
||||||
sort.Sort(ValidatorsByAddress(newValidators))
|
sort.Sort(ValidatorsByAddress(newValidators))
|
||||||
|
|
||||||
for _, validator := range newValidators {
|
for _, validator := range newValidators {
|
||||||
header.Extra = append(header.Extra, validator.HeaderBytes()...)
|
header.Extra = append(header.Extra, validator.HeaderBytes()...)
|
||||||
}
|
}
|
||||||
|
|
@ -673,7 +702,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
|
||||||
|
|
||||||
var succession int
|
var succession int
|
||||||
// if signer is not empty
|
// if signer is not empty
|
||||||
if bytes.Compare(c.signer.Bytes(), common.Address{}.Bytes()) != 0 {
|
if c.signer != (common.Address{}) {
|
||||||
succession, err = snap.GetSignerSuccessionNumber(c.signer)
|
succession, err = snap.GetSignerSuccessionNumber(c.signer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -684,6 +713,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
|
||||||
if header.Time < uint64(time.Now().Unix()) {
|
if header.Time < uint64(time.Now().Unix()) {
|
||||||
header.Time = uint64(time.Now().Unix())
|
header.Time = uint64(time.Now().Unix())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -693,7 +723,9 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
|
||||||
stateSyncData := []*types.StateSyncData{}
|
stateSyncData := []*types.StateSyncData{}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
headerNumber := header.Number.Uint64()
|
headerNumber := header.Number.Uint64()
|
||||||
|
|
||||||
if headerNumber%c.config.Sprint == 0 {
|
if headerNumber%c.config.Sprint == 0 {
|
||||||
cx := chainContext{Chain: chain, Bor: c}
|
cx := chainContext{Chain: chain, Bor: c}
|
||||||
// check and commit span
|
// check and commit span
|
||||||
|
|
@ -728,13 +760,17 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
|
||||||
|
|
||||||
func decodeGenesisAlloc(i interface{}) (core.GenesisAlloc, error) {
|
func decodeGenesisAlloc(i interface{}) (core.GenesisAlloc, error) {
|
||||||
var alloc core.GenesisAlloc
|
var alloc core.GenesisAlloc
|
||||||
|
|
||||||
b, err := json.Marshal(i)
|
b, err := json.Marshal(i)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(b, &alloc); err != nil {
|
if err := json.Unmarshal(b, &alloc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return alloc, nil
|
return alloc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -745,12 +781,14 @@ func (c *Bor) changeContractCodeIfNeeded(headerNumber uint64, state *state.State
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to decode genesis alloc: %v", err)
|
return fmt.Errorf("failed to decode genesis alloc: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for addr, account := range allocs {
|
for addr, account := range allocs {
|
||||||
log.Info("change contract code", "address", addr)
|
log.Info("change contract code", "address", addr)
|
||||||
state.SetCode(addr, account.Code)
|
state.SetCode(addr, account.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -856,10 +894,12 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
|
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
|
||||||
|
|
||||||
// Wait until sealing is terminated or delay timeout.
|
// Wait until sealing is terminated or delay timeout.
|
||||||
log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay))
|
log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay))
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case <-stop:
|
case <-stop:
|
||||||
|
|
@ -874,6 +914,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
||||||
"in-turn-signer", snap.ValidatorSet.GetProposer().Address.Hex(),
|
"in-turn-signer", snap.ValidatorSet.GetProposer().Address.Hex(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(
|
log.Info(
|
||||||
"Sealing successful",
|
"Sealing successful",
|
||||||
"number", number,
|
"number", number,
|
||||||
|
|
@ -887,6 +928,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
||||||
log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header, c.config))
|
log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header, c.config))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -898,6 +940,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, par
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return new(big.Int).SetUint64(snap.Difficulty(c.signer))
|
return new(big.Int).SetUint64(snap.Difficulty(c.signer))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -948,6 +991,7 @@ func (c *Bor) GetCurrentSpan(headerHash common.Hash) (*Span, error) {
|
||||||
To: &toAddress,
|
To: &toAddress,
|
||||||
Data: &msgData,
|
Data: &msgData,
|
||||||
}, blockNr, nil)
|
}, blockNr, nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -998,15 +1042,16 @@ func (c *Bor) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) (
|
||||||
To: &toAddress,
|
To: &toAddress,
|
||||||
Data: &msgData,
|
Data: &msgData,
|
||||||
}, blockNr, nil)
|
}, blockNr, nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
// return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ret0 = new([]common.Address)
|
ret0 = new([]common.Address)
|
||||||
ret1 = new([]*big.Int)
|
ret1 = new([]*big.Int)
|
||||||
)
|
)
|
||||||
|
|
||||||
out := &[]interface{}{
|
out := &[]interface{}{
|
||||||
ret0,
|
ret0,
|
||||||
ret1,
|
ret1,
|
||||||
|
|
@ -1034,13 +1079,16 @@ func (c *Bor) checkAndCommitSpan(
|
||||||
) error {
|
) error {
|
||||||
headerNumber := header.Number.Uint64()
|
headerNumber := header.Number.Uint64()
|
||||||
span, err := c.GetCurrentSpan(header.ParentHash)
|
span, err := c.GetCurrentSpan(header.ParentHash)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.needToCommitSpan(span, headerNumber) {
|
if c.needToCommitSpan(span, headerNumber) {
|
||||||
err := c.fetchAndCommitSpan(span.ID+1, state, header, chain)
|
err := c.fetchAndCommitSpan(span.ID+1, state, header, chain)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1072,10 +1120,11 @@ func (c *Bor) fetchAndCommitSpan(
|
||||||
var heimdallSpan HeimdallSpan
|
var heimdallSpan HeimdallSpan
|
||||||
|
|
||||||
if c.WithoutHeimdall {
|
if c.WithoutHeimdall {
|
||||||
s, err := c.getNextHeimdallSpanForTest(newSpanID, state, header, chain)
|
s, err := c.getNextHeimdallSpanForTest(newSpanID, header, chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
heimdallSpan = *s
|
heimdallSpan = *s
|
||||||
} else {
|
} else {
|
||||||
response, err := c.HeimdallClient.FetchWithRetry(fmt.Sprintf("bor/span/%d", newSpanID), "")
|
response, err := c.HeimdallClient.FetchWithRetry(fmt.Sprintf("bor/span/%d", newSpanID), "")
|
||||||
|
|
@ -1098,27 +1147,32 @@ func (c *Bor) fetchAndCommitSpan(
|
||||||
}
|
}
|
||||||
|
|
||||||
// get validators bytes
|
// get validators bytes
|
||||||
var validators []MinimalVal
|
validators := make([]MinimalVal, 0, len(heimdallSpan.ValidatorSet.Validators))
|
||||||
for _, val := range heimdallSpan.ValidatorSet.Validators {
|
for _, val := range heimdallSpan.ValidatorSet.Validators {
|
||||||
validators = append(validators, val.MinimalVal())
|
validators = append(validators, val.MinimalVal())
|
||||||
}
|
}
|
||||||
|
|
||||||
validatorBytes, err := rlp.EncodeToBytes(validators)
|
validatorBytes, err := rlp.EncodeToBytes(validators)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// get producers bytes
|
// get producers bytes
|
||||||
var producers []MinimalVal
|
producers := make([]MinimalVal, 0, len(heimdallSpan.SelectedProducers))
|
||||||
for _, val := range heimdallSpan.SelectedProducers {
|
for _, val := range heimdallSpan.SelectedProducers {
|
||||||
producers = append(producers, val.MinimalVal())
|
producers = append(producers, val.MinimalVal())
|
||||||
}
|
}
|
||||||
|
|
||||||
producerBytes, err := rlp.EncodeToBytes(producers)
|
producerBytes, err := rlp.EncodeToBytes(producers)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// method
|
// method
|
||||||
method := "commitSpan"
|
method := "commitSpan"
|
||||||
|
|
||||||
log.Info("✅ Committing new span",
|
log.Info("✅ Committing new span",
|
||||||
"id", heimdallSpan.ID,
|
"id", heimdallSpan.ID,
|
||||||
"startBlock", heimdallSpan.StartBlock,
|
"startBlock", heimdallSpan.StartBlock,
|
||||||
|
|
@ -1156,6 +1210,7 @@ func (c *Bor) CommitStates(
|
||||||
stateSyncs := make([]*types.StateSyncData, 0)
|
stateSyncs := make([]*types.StateSyncData, 0)
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
|
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1166,7 +1221,13 @@ func (c *Bor) CommitStates(
|
||||||
"Fetching state updates from Heimdall",
|
"Fetching state updates from Heimdall",
|
||||||
"fromID", lastStateID+1,
|
"fromID", lastStateID+1,
|
||||||
"to", to.Format(time.RFC3339))
|
"to", to.Format(time.RFC3339))
|
||||||
|
|
||||||
eventRecords, err := c.HeimdallClient.FetchStateSyncEvents(lastStateID+1, to.Unix())
|
eventRecords, err := c.HeimdallClient.FetchStateSyncEvents(lastStateID+1, to.Unix())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error occurred when fetching state sync events", err)
|
||||||
|
}
|
||||||
|
|
||||||
if c.config.OverrideStateSyncRecords != nil {
|
if c.config.OverrideStateSyncRecords != nil {
|
||||||
if val, ok := c.config.OverrideStateSyncRecords[strconv.FormatUint(number, 10)]; ok {
|
if val, ok := c.config.OverrideStateSyncRecords[strconv.FormatUint(number, 10)]; ok {
|
||||||
eventRecords = eventRecords[0:val]
|
eventRecords = eventRecords[0:val]
|
||||||
|
|
@ -1174,10 +1235,12 @@ func (c *Bor) CommitStates(
|
||||||
}
|
}
|
||||||
|
|
||||||
chainID := c.chainConfig.ChainID.String()
|
chainID := c.chainConfig.ChainID.String()
|
||||||
|
|
||||||
for _, eventRecord := range eventRecords {
|
for _, eventRecord := range eventRecords {
|
||||||
if eventRecord.ID <= lastStateID {
|
if eventRecord.ID <= lastStateID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
|
if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
|
||||||
log.Error(err.Error())
|
log.Error(err.Error())
|
||||||
break
|
break
|
||||||
|
|
@ -1196,6 +1259,7 @@ func (c *Bor) CommitStates(
|
||||||
}
|
}
|
||||||
lastStateID++
|
lastStateID++
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateSyncs, nil
|
return stateSyncs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1204,6 +1268,7 @@ func validateEventRecord(eventRecord *EventRecordWithTime, number uint64, to tim
|
||||||
if lastStateID+1 != eventRecord.ID || eventRecord.ChainID != chainID || !eventRecord.Time.Before(to) {
|
if lastStateID+1 != eventRecord.ID || eventRecord.ChainID != chainID || !eventRecord.Time.Before(to) {
|
||||||
return &InvalidStateReceivedError{number, lastStateID, &to, eventRecord}
|
return &InvalidStateReceivedError{number, lastStateID, &to, eventRecord}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1217,12 +1282,12 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) {
|
||||||
|
|
||||||
func (c *Bor) getNextHeimdallSpanForTest(
|
func (c *Bor) getNextHeimdallSpanForTest(
|
||||||
newSpanID uint64,
|
newSpanID uint64,
|
||||||
state *state.StateDB,
|
|
||||||
header *types.Header,
|
header *types.Header,
|
||||||
chain core.ChainContext,
|
chain core.ChainContext,
|
||||||
) (*HeimdallSpan, error) {
|
) (*HeimdallSpan, error) {
|
||||||
headerNumber := header.Number.Uint64()
|
headerNumber := header.Number.Uint64()
|
||||||
span, err := c.GetCurrentSpan(header.ParentHash)
|
span, err := c.GetCurrentSpan(header.ParentHash)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1242,12 +1307,14 @@ func (c *Bor) getNextHeimdallSpanForTest(
|
||||||
} else {
|
} else {
|
||||||
span.StartBlock = span.EndBlock + 1
|
span.StartBlock = span.EndBlock + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
span.EndBlock = span.StartBlock + (100 * c.config.Sprint) - 1
|
span.EndBlock = span.StartBlock + (100 * c.config.Sprint) - 1
|
||||||
|
|
||||||
selectedProducers := make([]Validator, len(snap.ValidatorSet.Validators))
|
selectedProducers := make([]Validator, len(snap.ValidatorSet.Validators))
|
||||||
for i, v := range snap.ValidatorSet.Validators {
|
for i, v := range snap.ValidatorSet.Validators {
|
||||||
selectedProducers[i] = *v
|
selectedProducers[i] = *v
|
||||||
}
|
}
|
||||||
|
|
||||||
heimdallSpan := &HeimdallSpan{
|
heimdallSpan := &HeimdallSpan{
|
||||||
Span: *span,
|
Span: *span,
|
||||||
ValidatorSet: *snap.ValidatorSet,
|
ValidatorSet: *snap.ValidatorSet,
|
||||||
|
|
@ -1335,10 +1402,11 @@ func applyMessage(
|
||||||
|
|
||||||
func validatorContains(a []*Validator, x *Validator) (*Validator, bool) {
|
func validatorContains(a []*Validator, x *Validator) (*Validator, bool) {
|
||||||
for _, n := range a {
|
for _, n := range a {
|
||||||
if bytes.Compare(n.Address.Bytes(), x.Address.Bytes()) == 0 {
|
if n.Address == x.Address {
|
||||||
return n, true
|
return n, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1346,7 +1414,8 @@ func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator)
|
||||||
v := oldValidatorSet
|
v := oldValidatorSet
|
||||||
oldVals := v.Validators
|
oldVals := v.Validators
|
||||||
|
|
||||||
var changes []*Validator
|
changes := make([]*Validator, 0, len(oldVals))
|
||||||
|
|
||||||
for _, ov := range oldVals {
|
for _, ov := range oldVals {
|
||||||
if f, ok := validatorContains(newVals, ov); ok {
|
if f, ok := validatorContains(newVals, ov); ok {
|
||||||
ov.VotingPower = f.VotingPower
|
ov.VotingPower = f.VotingPower
|
||||||
|
|
@ -1363,7 +1432,10 @@ func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v.UpdateWithChangeSet(changes)
|
if err := v.UpdateWithChangeSet(changes); err != nil {
|
||||||
|
log.Error("Error while updating change set", err)
|
||||||
|
}
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
@ -12,10 +14,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenesisContractChange(t *testing.T) {
|
func TestGenesisContractChange(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
addr0 := common.Address{0x1}
|
addr0 := common.Address{0x1}
|
||||||
|
|
||||||
b := &Bor{
|
b := &Bor{
|
||||||
|
|
@ -101,6 +104,8 @@ func TestGenesisContractChange(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncodeSigHeaderJaipur(t *testing.T) {
|
func TestEncodeSigHeaderJaipur(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
// As part of the EIP-1559 fork in mumbai, an incorrect seal hash
|
// As part of the EIP-1559 fork in mumbai, an incorrect seal hash
|
||||||
// was used for Bor that did not included the BaseFee. The Jaipur
|
// was used for Bor that did not included the BaseFee. The Jaipur
|
||||||
// block is a hard fork to fix that.
|
// block is a hard fork to fix that.
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ type EventRecordWithTime struct {
|
||||||
Time time.Time `json:"record_time" yaml:"record_time"`
|
Time time.Time `json:"record_time" yaml:"record_time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representatin of span
|
// String returns the string representations of span
|
||||||
func (e *EventRecordWithTime) String() string {
|
func (e *EventRecordWithTime) String() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"id %v, contract %v, data: %v, txHash: %v, logIndex: %v, chainId: %v, time %s",
|
"id %v, contract %v, data: %v, txHash: %v, logIndex: %v, chainId: %v, time %s",
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ func NewGenesisContractsClient(
|
||||||
) *GenesisContractsClient {
|
) *GenesisContractsClient {
|
||||||
vABI, _ := abi.JSON(strings.NewReader(validatorsetABI))
|
vABI, _ := abi.JSON(strings.NewReader(validatorsetABI))
|
||||||
sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI))
|
sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI))
|
||||||
|
|
||||||
return &GenesisContractsClient{
|
return &GenesisContractsClient{
|
||||||
validatorSetABI: vABI,
|
validatorSetABI: vABI,
|
||||||
stateReceiverABI: sABI,
|
stateReceiverABI: sABI,
|
||||||
|
|
@ -56,21 +57,27 @@ func (gc *GenesisContractsClient) CommitState(
|
||||||
) error {
|
) error {
|
||||||
eventRecord := event.BuildEventRecord()
|
eventRecord := event.BuildEventRecord()
|
||||||
recordBytes, err := rlp.EncodeToBytes(eventRecord)
|
recordBytes, err := rlp.EncodeToBytes(eventRecord)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
method := "commitState"
|
method := "commitState"
|
||||||
t := event.Time.Unix()
|
t := event.Time.Unix()
|
||||||
data, err := gc.stateReceiverABI.Pack(method, big.NewInt(0).SetInt64(t), recordBytes)
|
data, err := gc.stateReceiverABI.Pack(method, big.NewInt(0).SetInt64(t), recordBytes)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to pack tx for commitState", "error", err)
|
log.Error("Unable to pack tx for commitState", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("→ committing new state", "eventRecord", event.String())
|
log.Info("→ committing new state", "eventRecord", event.String())
|
||||||
|
|
||||||
msg := getSystemMessage(common.HexToAddress(gc.StateReceiverContract), data)
|
msg := getSystemMessage(common.HexToAddress(gc.StateReceiverContract), data)
|
||||||
if err := applyMessage(msg, state, header, gc.chainConfig, chCtx); err != nil {
|
if err := applyMessage(msg, state, header, gc.chainConfig, chCtx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,6 +85,7 @@ func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int,
|
||||||
blockNr := rpc.BlockNumber(snapshotNumber)
|
blockNr := rpc.BlockNumber(snapshotNumber)
|
||||||
method := "lastStateId"
|
method := "lastStateId"
|
||||||
data, err := gc.stateReceiverABI.Pack(method)
|
data, err := gc.stateReceiverABI.Pack(method)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to pack tx for LastStateId", "error", err)
|
log.Error("Unable to pack tx for LastStateId", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -91,6 +99,7 @@ func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int,
|
||||||
To: &toAddress,
|
To: &toAddress,
|
||||||
Data: &msgData,
|
Data: &msgData,
|
||||||
}, rpc.BlockNumberOrHash{BlockNumber: &blockNr}, nil)
|
}, rpc.BlockNumberOrHash{BlockNumber: &blockNr}, nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -99,5 +108,6 @@ func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int,
|
||||||
if err := gc.stateReceiverABI.UnpackIntoInterface(ret, method, result); err != nil {
|
if err := gc.stateReceiverABI.UnpackIntoInterface(ret, method, result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return *ret, nil
|
return *ret, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@ package bor
|
||||||
|
|
||||||
func appendBytes32(data ...[]byte) []byte {
|
func appendBytes32(data ...[]byte) []byte {
|
||||||
var result []byte
|
var result []byte
|
||||||
|
|
||||||
for _, v := range data {
|
for _, v := range data {
|
||||||
paddedV, err := convertTo32(v)
|
paddedV := convertTo32(v)
|
||||||
if err == nil {
|
|
||||||
result = append(result, paddedV[:]...)
|
result = append(result, paddedV[:]...)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,25 +24,29 @@ func nextPowerOfTwo(n uint64) uint64 {
|
||||||
n |= n >> 16
|
n |= n >> 16
|
||||||
n |= n >> 32
|
n |= n >> 32
|
||||||
n++
|
n++
|
||||||
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertTo32(input []byte) (output [32]byte, err error) {
|
func convertTo32(input []byte) (output [32]byte) {
|
||||||
l := len(input)
|
l := len(input)
|
||||||
if l > 32 || l == 0 {
|
if l > 32 || l == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(output[32-l:], input[:])
|
copy(output[32-l:], input[:])
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func convert(input []([32]byte)) [][]byte {
|
func convert(input []([32]byte)) [][]byte {
|
||||||
var output [][]byte
|
output := make([][]byte, 0, len(input))
|
||||||
|
|
||||||
for _, in := range input {
|
for _, in := range input {
|
||||||
newInput := make([]byte, len(in[:]))
|
newInput := make([]byte, len(in[:]))
|
||||||
copy(newInput, in[:])
|
copy(newInput, in[:])
|
||||||
output = append(output, newInput)
|
output = append(output, newInput)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,39 +40,49 @@ func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
|
||||||
h := &HeimdallClient{
|
h := &HeimdallClient{
|
||||||
urlString: urlString,
|
urlString: urlString,
|
||||||
client: http.Client{
|
client: http.Client{
|
||||||
Timeout: time.Duration(5 * time.Second),
|
Timeout: 5 * time.Second,
|
||||||
},
|
},
|
||||||
closeCh: make(chan struct{}),
|
closeCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error) {
|
func (h *HeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error) {
|
||||||
eventRecords := make([]*EventRecordWithTime, 0)
|
eventRecords := make([]*EventRecordWithTime, 0)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
queryParams := fmt.Sprintf("from-id=%d&to-time=%d&limit=%d", fromID, to, stateFetchLimit)
|
queryParams := fmt.Sprintf("from-id=%d&to-time=%d&limit=%d", fromID, to, stateFetchLimit)
|
||||||
log.Info("Fetching state sync events", "queryParams", queryParams)
|
log.Info("Fetching state sync events", "queryParams", queryParams)
|
||||||
response, err := h.FetchWithRetry("clerk/event-record/list", queryParams)
|
response, err := h.FetchWithRetry("clerk/event-record/list", queryParams)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var _eventRecords []*EventRecordWithTime
|
var _eventRecords []*EventRecordWithTime
|
||||||
|
|
||||||
if response.Result == nil { // status 204
|
if response.Result == nil { // status 204
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(response.Result, &_eventRecords); err != nil {
|
if err := json.Unmarshal(response.Result, &_eventRecords); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
eventRecords = append(eventRecords, _eventRecords...)
|
eventRecords = append(eventRecords, _eventRecords...)
|
||||||
|
|
||||||
if len(_eventRecords) < stateFetchLimit {
|
if len(_eventRecords) < stateFetchLimit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
fromID += uint64(stateFetchLimit)
|
fromID += uint64(stateFetchLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.SliceStable(eventRecords, func(i, j int) bool {
|
sort.SliceStable(eventRecords, func(i, j int) bool {
|
||||||
return eventRecords[i].ID < eventRecords[j].ID
|
return eventRecords[i].ID < eventRecords[j].ID
|
||||||
})
|
})
|
||||||
|
|
||||||
return eventRecords, nil
|
return eventRecords, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,7 +140,7 @@ func (h *HeimdallClient) FetchWithRetry(rawPath string, rawQuery string) (*Respo
|
||||||
|
|
||||||
// internal fetch method
|
// internal fetch method
|
||||||
func (h *HeimdallClient) internalFetch(u *url.URL) (*ResponseWithHeight, error) {
|
func (h *HeimdallClient) internalFetch(u *url.URL) (*ResponseWithHeight, error) {
|
||||||
res, err := h.client.Get(u.String())
|
res, err := h.client.Get(u.String()) // nolint: noctx
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package bor
|
package bor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
@ -25,13 +24,6 @@ type Snapshot struct {
|
||||||
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
|
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
|
||||||
}
|
}
|
||||||
|
|
||||||
// signersAscending implements the sort interface to allow sorting a list of addresses
|
|
||||||
type signersAscending []common.Address
|
|
||||||
|
|
||||||
func (s signersAscending) Len() int { return len(s) }
|
|
||||||
func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 }
|
|
||||||
func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
||||||
|
|
||||||
// newSnapshot creates a new snapshot with the specified startup parameters. This
|
// newSnapshot creates a new snapshot with the specified startup parameters. This
|
||||||
// method does not initialize the set of recent signers, so only ever use if for
|
// method does not initialize the set of recent signers, so only ever use if for
|
||||||
// the genesis block.
|
// the genesis block.
|
||||||
|
|
@ -52,6 +44,7 @@ func newSnapshot(
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: NewValidatorSet(validators),
|
||||||
Recents: make(map[uint64]common.Address),
|
Recents: make(map[uint64]common.Address),
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap
|
return snap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,10 +54,13 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
snap := new(Snapshot)
|
snap := new(Snapshot)
|
||||||
|
|
||||||
if err := json.Unmarshal(blob, snap); err != nil {
|
if err := json.Unmarshal(blob, snap); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
snap.config = config
|
snap.config = config
|
||||||
snap.sigcache = sigcache
|
snap.sigcache = sigcache
|
||||||
snap.ethAPI = ethAPI
|
snap.ethAPI = ethAPI
|
||||||
|
|
@ -83,6 +79,7 @@ func (s *Snapshot) store(db ethdb.Database) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.Put(append([]byte("bor-"), s.Hash[:]...), blob)
|
return db.Put(append([]byte("bor-"), s.Hash[:]...), blob)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,6 +112,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
return nil, errOutOfRangeChain
|
return nil, errOutOfRangeChain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if headers[0].Number.Uint64() != s.Number+1 {
|
if headers[0].Number.Uint64() != s.Number+1 {
|
||||||
return nil, errOutOfRangeChain
|
return nil, errOutOfRangeChain
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +124,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
|
|
||||||
// Delete the oldest signer from the recent list to allow it signing again
|
// Delete the oldest signer from the recent list to allow it signing again
|
||||||
if number >= s.config.Sprint && number-s.config.Sprint >= 0 {
|
if number >= s.config.Sprint {
|
||||||
delete(snap.Recents, number-s.config.Sprint)
|
delete(snap.Recents, number-s.config.Sprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,6 +151,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
if err := validateHeaderExtraField(header.Extra); err != nil {
|
if err := validateHeaderExtraField(header.Extra); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
|
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
|
||||||
|
|
||||||
// get validators from headers and use that for new validator set
|
// get validators from headers and use that for new validator set
|
||||||
|
|
@ -162,6 +161,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
snap.ValidatorSet = v
|
snap.ValidatorSet = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snap.Number += uint64(len(headers))
|
snap.Number += uint64(len(headers))
|
||||||
snap.Hash = headers[len(headers)-1].Hash()
|
snap.Hash = headers[len(headers)-1].Hash()
|
||||||
|
|
||||||
|
|
@ -173,10 +173,13 @@ func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error)
|
||||||
validators := s.ValidatorSet.Validators
|
validators := s.ValidatorSet.Validators
|
||||||
proposer := s.ValidatorSet.GetProposer().Address
|
proposer := s.ValidatorSet.GetProposer().Address
|
||||||
proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
|
proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
|
||||||
|
|
||||||
if proposerIndex == -1 {
|
if proposerIndex == -1 {
|
||||||
return -1, &UnauthorizedProposerError{s.Number, proposer.Bytes()}
|
return -1, &UnauthorizedProposerError{s.Number, proposer.Bytes()}
|
||||||
}
|
}
|
||||||
|
|
||||||
signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
|
signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
|
||||||
|
|
||||||
if signerIndex == -1 {
|
if signerIndex == -1 {
|
||||||
return -1, &UnauthorizedSignerError{s.Number, signer.Bytes()}
|
return -1, &UnauthorizedSignerError{s.Number, signer.Bytes()}
|
||||||
}
|
}
|
||||||
|
|
@ -187,6 +190,7 @@ func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error)
|
||||||
tempIndex = tempIndex + len(validators)
|
tempIndex = tempIndex + len(validators)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tempIndex - proposerIndex, nil
|
return tempIndex - proposerIndex, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,13 +200,14 @@ func (s *Snapshot) signers() []common.Address {
|
||||||
for _, sig := range s.ValidatorSet.Validators {
|
for _, sig := range s.ValidatorSet.Validators {
|
||||||
sigs = append(sigs, sig.Address)
|
sigs = append(sigs, sig.Address)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sigs
|
return sigs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Difficulty returns the difficulty for a particular signer at the current snapshot number
|
// Difficulty returns the difficulty for a particular signer at the current snapshot number
|
||||||
func (s *Snapshot) Difficulty(signer common.Address) uint64 {
|
func (s *Snapshot) Difficulty(signer common.Address) uint64 {
|
||||||
// if signer is empty
|
// if signer is empty
|
||||||
if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 {
|
if signer == (common.Address{}) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
validatorSet := NewValidatorSet(validators)
|
validatorSet := NewValidatorSet(validators)
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
|
|
@ -25,17 +27,22 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
||||||
// proposer is signer
|
// proposer is signer
|
||||||
signer := validatorSet.Proposer.Address
|
signer := validatorSet.Proposer.Address
|
||||||
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, 0, successionNumber)
|
assert.Equal(t, 0, successionNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
|
|
||||||
// sort validators by address, which is what NewValidatorSet also does
|
// sort validators by address, which is what NewValidatorSet also does
|
||||||
sort.Sort(ValidatorsByAddress(validators))
|
sort.Sort(ValidatorsByAddress(validators))
|
||||||
|
|
||||||
proposerIndex := 32
|
proposerIndex := 32
|
||||||
signerIndex := 56
|
signerIndex := 56
|
||||||
// give highest ProposerPriority to a particular val, so that they become the proposer
|
// give highest ProposerPriority to a particular val, so that they become the proposer
|
||||||
|
|
@ -47,13 +54,17 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
||||||
// choose a signer at an index greater than proposer index
|
// choose a signer at an index greater than proposer index
|
||||||
signer := snap.ValidatorSet.Validators[signerIndex].Address
|
signer := snap.ValidatorSet.Validators[signerIndex].Address
|
||||||
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, signerIndex-proposerIndex, successionNumber)
|
assert.Equal(t, signerIndex-proposerIndex, successionNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
proposerIndex := 98
|
proposerIndex := 98
|
||||||
signerIndex := 11
|
signerIndex := 11
|
||||||
|
|
@ -66,13 +77,17 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
||||||
// choose a signer at an index greater than proposer index
|
// choose a signer at an index greater than proposer index
|
||||||
signer := snap.ValidatorSet.Validators[signerIndex].Address
|
signer := snap.ValidatorSet.Validators[signerIndex].Address
|
||||||
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
|
assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: NewValidatorSet(validators),
|
||||||
|
|
@ -89,6 +104,8 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: NewValidatorSet(validators),
|
||||||
|
|
@ -101,9 +118,12 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
||||||
assert.Equal(t, dummySignerAddress.Bytes(), e.Signer)
|
assert.Equal(t, dummySignerAddress.Bytes(), e.Signer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func buildRandomValidatorSet(numVals int) []*Validator {
|
func buildRandomValidatorSet(numVals int) []*Validator {
|
||||||
rand.Seed(time.Now().Unix())
|
rand.Seed(time.Now().Unix())
|
||||||
|
|
||||||
validators := make([]*Validator, numVals)
|
validators := make([]*Validator, numVals)
|
||||||
|
|
||||||
for i := 0; i < numVals; i++ {
|
for i := 0; i < numVals; i++ {
|
||||||
validators[i] = &Validator{
|
validators[i] = &Validator{
|
||||||
Address: randomAddress(),
|
Address: randomAddress(),
|
||||||
|
|
@ -114,11 +134,13 @@ func buildRandomValidatorSet(numVals int) []*Validator {
|
||||||
|
|
||||||
// sort validators by address, which is what NewValidatorSet also does
|
// sort validators by address, which is what NewValidatorSet also does
|
||||||
sort.Sort(ValidatorsByAddress(validators))
|
sort.Sort(ValidatorsByAddress(validators))
|
||||||
|
|
||||||
return validators
|
return validators
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomAddress() common.Address {
|
func randomAddress() common.Address {
|
||||||
bytes := make([]byte, 32)
|
bytes := make([]byte, 32)
|
||||||
rand.Read(bytes)
|
rand.Read(bytes)
|
||||||
|
|
||||||
return common.BytesToAddress(bytes)
|
return common.BytesToAddress(bytes)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,12 @@ func (v *Validator) Cmp(other *Validator) *Validator {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return other
|
return other
|
||||||
}
|
}
|
||||||
|
|
||||||
if other == nil {
|
if other == nil {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint:nestif
|
||||||
if v.ProposerPriority > other.ProposerPriority {
|
if v.ProposerPriority > other.ProposerPriority {
|
||||||
return v
|
return v
|
||||||
} else if v.ProposerPriority < other.ProposerPriority {
|
} else if v.ProposerPriority < other.ProposerPriority {
|
||||||
|
|
@ -66,6 +69,7 @@ func (v *Validator) String() string {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return "nil-Validator"
|
return "nil-Validator"
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("Validator{%v Power:%v Priority:%v}",
|
return fmt.Sprintf("Validator{%v Power:%v Priority:%v}",
|
||||||
v.Address.Hex(),
|
v.Address.Hex(),
|
||||||
v.VotingPower,
|
v.VotingPower,
|
||||||
|
|
@ -87,6 +91,7 @@ func (v *Validator) HeaderBytes() []byte {
|
||||||
result := make([]byte, 40)
|
result := make([]byte, 40)
|
||||||
copy(result[:20], v.Address.Bytes())
|
copy(result[:20], v.Address.Bytes())
|
||||||
copy(result[20:], v.PowerBytes())
|
copy(result[20:], v.PowerBytes())
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,6 +100,7 @@ func (v *Validator) PowerBytes() []byte {
|
||||||
powerBytes := big.NewInt(0).SetInt64(v.VotingPower).Bytes()
|
powerBytes := big.NewInt(0).SetInt64(v.VotingPower).Bytes()
|
||||||
result := make([]byte, 20)
|
result := make([]byte, 20)
|
||||||
copy(result[20-len(powerBytes):], powerBytes)
|
copy(result[20-len(powerBytes):], powerBytes)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,6 +120,7 @@ func ParseValidators(validatorsBytes []byte) ([]*Validator, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]*Validator, len(validatorsBytes)/40)
|
result := make([]*Validator, len(validatorsBytes)/40)
|
||||||
|
|
||||||
for i := 0; i < len(validatorsBytes); i += 40 {
|
for i := 0; i < len(validatorsBytes); i += 40 {
|
||||||
address := make([]byte, 20)
|
address := make([]byte, 20)
|
||||||
power := make([]byte, 20)
|
power := make([]byte, 20)
|
||||||
|
|
@ -142,6 +149,7 @@ func SortMinimalValByAddress(a []MinimalVal) []MinimalVal {
|
||||||
sort.Slice(a, func(i, j int) bool {
|
sort.Slice(a, func(i, j int) bool {
|
||||||
return bytes.Compare(a[i].Signer.Bytes(), a[j].Signer.Bytes()) < 0
|
return bytes.Compare(a[i].Signer.Bytes(), a[j].Signer.Bytes()) < 0
|
||||||
})
|
})
|
||||||
|
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,5 +158,6 @@ func ValidatorsToMinimalValidators(vals []Validator) (minVals []MinimalVal) {
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
minVals = append(minVals, val.MinimalVal())
|
minVals = append(minVals, val.MinimalVal())
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,15 @@ type ValidatorSet struct {
|
||||||
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
||||||
vals := &ValidatorSet{}
|
vals := &ValidatorSet{}
|
||||||
err := vals.updateWithChangeSet(valz, false)
|
err := vals.updateWithChangeSet(valz, false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("cannot create validator set: %s", err))
|
panic(fmt.Sprintf("cannot create validator set: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(valz) > 0 {
|
if len(valz) > 0 {
|
||||||
vals.IncrementProposerPriority(1)
|
vals.IncrementProposerPriority(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return vals
|
return vals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,9 +75,10 @@ func (vals *ValidatorSet) IsNilOrEmpty() bool {
|
||||||
|
|
||||||
// Increment ProposerPriority and update the proposer on a copy, and return it.
|
// Increment ProposerPriority and update the proposer on a copy, and return it.
|
||||||
func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet {
|
func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet {
|
||||||
copy := vals.Copy()
|
validatorCopy := vals.Copy()
|
||||||
copy.IncrementProposerPriority(times)
|
validatorCopy.IncrementProposerPriority(times)
|
||||||
return copy
|
|
||||||
|
return validatorCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
// IncrementProposerPriority increments ProposerPriority of each validator and updates the
|
// IncrementProposerPriority increments ProposerPriority of each validator and updates the
|
||||||
|
|
@ -84,6 +88,7 @@ func (vals *ValidatorSet) IncrementProposerPriority(times int) {
|
||||||
if vals.IsNilOrEmpty() {
|
if vals.IsNilOrEmpty() {
|
||||||
panic("empty validator set")
|
panic("empty validator set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if times <= 0 {
|
if times <= 0 {
|
||||||
panic("Cannot call IncrementProposerPriority with non-positive times")
|
panic("Cannot call IncrementProposerPriority with non-positive times")
|
||||||
}
|
}
|
||||||
|
|
@ -120,6 +125,7 @@ func (vals *ValidatorSet) RescalePriorities(diffMax int64) {
|
||||||
// NOTE: This may make debugging priority issues easier as well.
|
// NOTE: This may make debugging priority issues easier as well.
|
||||||
diff := computeMaxMinPriorityDiff(vals)
|
diff := computeMaxMinPriorityDiff(vals)
|
||||||
ratio := (diff + diffMax - 1) / diffMax
|
ratio := (diff + diffMax - 1) / diffMax
|
||||||
|
|
||||||
if diff > diffMax {
|
if diff > diffMax {
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
val.ProposerPriority = val.ProposerPriority / ratio
|
val.ProposerPriority = val.ProposerPriority / ratio
|
||||||
|
|
@ -145,10 +151,13 @@ func (vals *ValidatorSet) incrementProposerPriority() *Validator {
|
||||||
func (vals *ValidatorSet) computeAvgProposerPriority() int64 {
|
func (vals *ValidatorSet) computeAvgProposerPriority() int64 {
|
||||||
n := int64(len(vals.Validators))
|
n := int64(len(vals.Validators))
|
||||||
sum := big.NewInt(0)
|
sum := big.NewInt(0)
|
||||||
|
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
sum.Add(sum, big.NewInt(val.ProposerPriority))
|
sum.Add(sum, big.NewInt(val.ProposerPriority))
|
||||||
}
|
}
|
||||||
|
|
||||||
avg := sum.Div(sum, big.NewInt(n))
|
avg := sum.Div(sum, big.NewInt(n))
|
||||||
|
|
||||||
if avg.IsInt64() {
|
if avg.IsInt64() {
|
||||||
return avg.Int64()
|
return avg.Int64()
|
||||||
}
|
}
|
||||||
|
|
@ -162,17 +171,22 @@ func computeMaxMinPriorityDiff(vals *ValidatorSet) int64 {
|
||||||
if vals.IsNilOrEmpty() {
|
if vals.IsNilOrEmpty() {
|
||||||
panic("empty validator set")
|
panic("empty validator set")
|
||||||
}
|
}
|
||||||
|
|
||||||
max := int64(math.MinInt64)
|
max := int64(math.MinInt64)
|
||||||
min := int64(math.MaxInt64)
|
min := int64(math.MaxInt64)
|
||||||
|
|
||||||
for _, v := range vals.Validators {
|
for _, v := range vals.Validators {
|
||||||
if v.ProposerPriority < min {
|
if v.ProposerPriority < min {
|
||||||
min = v.ProposerPriority
|
min = v.ProposerPriority
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.ProposerPriority > max {
|
if v.ProposerPriority > max {
|
||||||
max = v.ProposerPriority
|
max = v.ProposerPriority
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diff := max - min
|
diff := max - min
|
||||||
|
|
||||||
if diff < 0 {
|
if diff < 0 {
|
||||||
return -1 * diff
|
return -1 * diff
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -185,6 +199,7 @@ func (vals *ValidatorSet) getValWithMostPriority() *Validator {
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
res = res.Cmp(val)
|
res = res.Cmp(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +207,9 @@ func (vals *ValidatorSet) shiftByAvgProposerPriority() {
|
||||||
if vals.IsNilOrEmpty() {
|
if vals.IsNilOrEmpty() {
|
||||||
panic("empty validator set")
|
panic("empty validator set")
|
||||||
}
|
}
|
||||||
|
|
||||||
avgProposerPriority := vals.computeAvgProposerPriority()
|
avgProposerPriority := vals.computeAvgProposerPriority()
|
||||||
|
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
val.ProposerPriority = safeSubClip(val.ProposerPriority, avgProposerPriority)
|
val.ProposerPriority = safeSubClip(val.ProposerPriority, avgProposerPriority)
|
||||||
}
|
}
|
||||||
|
|
@ -203,10 +220,13 @@ func validatorListCopy(valsList []*Validator) []*Validator {
|
||||||
if valsList == nil {
|
if valsList == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
valsCopy := make([]*Validator, len(valsList))
|
valsCopy := make([]*Validator, len(valsList))
|
||||||
|
|
||||||
for i, val := range valsList {
|
for i, val := range valsList {
|
||||||
valsCopy[i] = val.Copy()
|
valsCopy[i] = val.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
return valsCopy
|
return valsCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,6 +245,7 @@ func (vals *ValidatorSet) HasAddress(address []byte) bool {
|
||||||
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
||||||
return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0
|
return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0
|
||||||
})
|
})
|
||||||
|
|
||||||
return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address)
|
return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,9 +255,10 @@ func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *
|
||||||
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
||||||
return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0
|
return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0
|
||||||
})
|
})
|
||||||
if idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address.Bytes()) {
|
if idx < len(vals.Validators) && vals.Validators[idx].Address == address {
|
||||||
return idx, vals.Validators[idx].Copy()
|
return idx, vals.Validators[idx].Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, nil
|
return -1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,7 +269,9 @@ func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator)
|
||||||
if index < 0 || index >= len(vals.Validators) {
|
if index < 0 || index >= len(vals.Validators) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
val = vals.Validators[index]
|
val = vals.Validators[index]
|
||||||
|
|
||||||
return val.Address.Bytes(), val.Copy()
|
return val.Address.Bytes(), val.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -258,7 +282,6 @@ func (vals *ValidatorSet) Size() int {
|
||||||
|
|
||||||
// Force recalculation of the set's total voting power.
|
// Force recalculation of the set's total voting power.
|
||||||
func (vals *ValidatorSet) updateTotalVotingPower() error {
|
func (vals *ValidatorSet) updateTotalVotingPower() error {
|
||||||
|
|
||||||
sum := int64(0)
|
sum := int64(0)
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
// mind overflow
|
// mind overflow
|
||||||
|
|
@ -267,7 +290,9 @@ func (vals *ValidatorSet) updateTotalVotingPower() error {
|
||||||
return &TotalVotingPowerExceededError{sum, vals.Validators}
|
return &TotalVotingPowerExceededError{sum, vals.Validators}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vals.totalVotingPower = sum
|
vals.totalVotingPower = sum
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,11 +301,13 @@ func (vals *ValidatorSet) updateTotalVotingPower() error {
|
||||||
func (vals *ValidatorSet) TotalVotingPower() int64 {
|
func (vals *ValidatorSet) TotalVotingPower() int64 {
|
||||||
if vals.totalVotingPower == 0 {
|
if vals.totalVotingPower == 0 {
|
||||||
log.Info("invoking updateTotalVotingPower before returning it")
|
log.Info("invoking updateTotalVotingPower before returning it")
|
||||||
|
|
||||||
if err := vals.updateTotalVotingPower(); err != nil {
|
if err := vals.updateTotalVotingPower(); err != nil {
|
||||||
// Can/should we do better?
|
// Can/should we do better?
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vals.totalVotingPower
|
return vals.totalVotingPower
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,9 +317,11 @@ func (vals *ValidatorSet) GetProposer() (proposer *Validator) {
|
||||||
if len(vals.Validators) == 0 {
|
if len(vals.Validators) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if vals.Proposer == nil {
|
if vals.Proposer == nil {
|
||||||
vals.Proposer = vals.findProposer()
|
vals.Proposer = vals.findProposer()
|
||||||
}
|
}
|
||||||
|
|
||||||
return vals.Proposer.Copy()
|
return vals.Proposer.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,6 +332,7 @@ func (vals *ValidatorSet) findProposer() *Validator {
|
||||||
proposer = proposer.Cmp(val)
|
proposer = proposer.Cmp(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return proposer
|
return proposer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,6 +373,7 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
|
||||||
|
|
||||||
removals = make([]*Validator, 0, len(changes))
|
removals = make([]*Validator, 0, len(changes))
|
||||||
updates = make([]*Validator, 0, len(changes))
|
updates = make([]*Validator, 0, len(changes))
|
||||||
|
|
||||||
var prevAddr common.Address
|
var prevAddr common.Address
|
||||||
|
|
||||||
// Scan changes by address and append valid validators to updates or removals lists.
|
// Scan changes by address and append valid validators to updates or removals lists.
|
||||||
|
|
@ -351,22 +382,27 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
|
||||||
err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes)
|
err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if valUpdate.VotingPower < 0 {
|
if valUpdate.VotingPower < 0 {
|
||||||
err = fmt.Errorf("voting power can't be negative: %v", valUpdate)
|
err = fmt.Errorf("voting power can't be negative: %v", valUpdate)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if valUpdate.VotingPower > MaxTotalVotingPower {
|
if valUpdate.VotingPower > MaxTotalVotingPower {
|
||||||
err = fmt.Errorf("to prevent clipping/ overflow, voting power can't be higher than %v: %v ",
|
err = fmt.Errorf("to prevent clipping/ overflow, voting power can't be higher than %v: %v ",
|
||||||
MaxTotalVotingPower, valUpdate)
|
MaxTotalVotingPower, valUpdate)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if valUpdate.VotingPower == 0 {
|
if valUpdate.VotingPower == 0 {
|
||||||
removals = append(removals, valUpdate)
|
removals = append(removals, valUpdate)
|
||||||
} else {
|
} else {
|
||||||
updates = append(updates, valUpdate)
|
updates = append(updates, valUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
prevAddr = valUpdate.Address
|
prevAddr = valUpdate.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
return updates, removals, err
|
return updates, removals, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -382,12 +418,12 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
|
||||||
// by processChanges for duplicates and invalid values.
|
// by processChanges for duplicates and invalid values.
|
||||||
// No changes are made to the validator set 'vals'.
|
// No changes are made to the validator set 'vals'.
|
||||||
func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVotingPower int64, numNewValidators int, err error) {
|
func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVotingPower int64, numNewValidators int, err error) {
|
||||||
|
|
||||||
updatedTotalVotingPower = vals.TotalVotingPower()
|
updatedTotalVotingPower = vals.TotalVotingPower()
|
||||||
|
|
||||||
for _, valUpdate := range updates {
|
for _, valUpdate := range updates {
|
||||||
address := valUpdate.Address
|
address := valUpdate.Address
|
||||||
_, val := vals.GetByAddress(address)
|
_, val := vals.GetByAddress(address)
|
||||||
|
|
||||||
if val == nil {
|
if val == nil {
|
||||||
// New validator, add its voting power the the total.
|
// New validator, add its voting power the the total.
|
||||||
updatedTotalVotingPower += valUpdate.VotingPower
|
updatedTotalVotingPower += valUpdate.VotingPower
|
||||||
|
|
@ -396,11 +432,14 @@ func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVoting
|
||||||
// Updated validator, add the difference in power to the total.
|
// Updated validator, add the difference in power to the total.
|
||||||
updatedTotalVotingPower += valUpdate.VotingPower - val.VotingPower
|
updatedTotalVotingPower += valUpdate.VotingPower - val.VotingPower
|
||||||
}
|
}
|
||||||
|
|
||||||
overflow := updatedTotalVotingPower > MaxTotalVotingPower
|
overflow := updatedTotalVotingPower > MaxTotalVotingPower
|
||||||
|
|
||||||
if overflow {
|
if overflow {
|
||||||
err = fmt.Errorf(
|
err = fmt.Errorf(
|
||||||
"failed to add/update validator %v, total voting power would exceed the max allowed %v",
|
"failed to add/update validator %v, total voting power would exceed the max allowed %v",
|
||||||
valUpdate, MaxTotalVotingPower)
|
valUpdate, MaxTotalVotingPower)
|
||||||
|
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -414,10 +453,10 @@ func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVoting
|
||||||
// 'updates' parameter must be a list of unique validators to be added or updated.
|
// 'updates' parameter must be a list of unique validators to be added or updated.
|
||||||
// No changes are made to the validator set 'vals'.
|
// No changes are made to the validator set 'vals'.
|
||||||
func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotalVotingPower int64) {
|
func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotalVotingPower int64) {
|
||||||
|
|
||||||
for _, valUpdate := range updates {
|
for _, valUpdate := range updates {
|
||||||
address := valUpdate.Address
|
address := valUpdate.Address
|
||||||
_, val := vals.GetByAddress(address)
|
_, val := vals.GetByAddress(address)
|
||||||
|
|
||||||
if val == nil {
|
if val == nil {
|
||||||
// add val
|
// add val
|
||||||
// Set ProposerPriority to -C*totalVotingPower (with C ~= 1.125) to make sure validators can't
|
// Set ProposerPriority to -C*totalVotingPower (with C ~= 1.125) to make sure validators can't
|
||||||
|
|
@ -432,7 +471,6 @@ func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotal
|
||||||
valUpdate.ProposerPriority = val.ProposerPriority
|
valUpdate.ProposerPriority = val.ProposerPriority
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merges the vals' validator list with the updates list.
|
// Merges the vals' validator list with the updates list.
|
||||||
|
|
@ -440,7 +478,6 @@ func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotal
|
||||||
// Expects updates to be a list of updates sorted by address with no duplicates or errors,
|
// Expects updates to be a list of updates sorted by address with no duplicates or errors,
|
||||||
// must have been validated with verifyUpdates() and priorities computed with computeNewPriorities().
|
// must have been validated with verifyUpdates() and priorities computed with computeNewPriorities().
|
||||||
func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
||||||
|
|
||||||
existing := vals.Validators
|
existing := vals.Validators
|
||||||
merged := make([]*Validator, len(existing)+len(updates))
|
merged := make([]*Validator, len(existing)+len(updates))
|
||||||
i := 0
|
i := 0
|
||||||
|
|
@ -478,24 +515,25 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
||||||
// Checks that the validators to be removed are part of the validator set.
|
// Checks that the validators to be removed are part of the validator set.
|
||||||
// No changes are made to the validator set 'vals'.
|
// No changes are made to the validator set 'vals'.
|
||||||
func verifyRemovals(deletes []*Validator, vals *ValidatorSet) error {
|
func verifyRemovals(deletes []*Validator, vals *ValidatorSet) error {
|
||||||
|
|
||||||
for _, valUpdate := range deletes {
|
for _, valUpdate := range deletes {
|
||||||
address := valUpdate.Address
|
address := valUpdate.Address
|
||||||
_, val := vals.GetByAddress(address)
|
_, val := vals.GetByAddress(address)
|
||||||
|
|
||||||
if val == nil {
|
if val == nil {
|
||||||
return fmt.Errorf("failed to find validator %X to remove", address)
|
return fmt.Errorf("failed to find validator %X to remove", address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(deletes) > len(vals.Validators) {
|
if len(deletes) > len(vals.Validators) {
|
||||||
panic("more deletes than validators")
|
panic("more deletes than validators")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the validators specified in 'deletes' from validator set 'vals'.
|
// Removes the validators specified in 'deletes' from validator set 'vals'.
|
||||||
// Should not fail as verification has been done before.
|
// Should not fail as verification has been done before.
|
||||||
func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
||||||
|
|
||||||
existing := vals.Validators
|
existing := vals.Validators
|
||||||
|
|
||||||
merged := make([]*Validator, len(existing)-len(deletes))
|
merged := make([]*Validator, len(existing)-len(deletes))
|
||||||
|
|
@ -509,6 +547,7 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
||||||
merged[i] = existing[0]
|
merged[i] = existing[0]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
existing = existing[1:]
|
existing = existing[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -526,7 +565,6 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
||||||
// are not allowed and will trigger an error if present in 'changes'.
|
// are not allowed and will trigger an error if present in 'changes'.
|
||||||
// The 'allowDeletes' flag is set to false by NewValidatorSet() and to true by UpdateWithChangeSet().
|
// The 'allowDeletes' flag is set to false by NewValidatorSet() and to true by UpdateWithChangeSet().
|
||||||
func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes bool) error {
|
func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes bool) error {
|
||||||
|
|
||||||
if len(changes) <= 0 {
|
if len(changes) <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -596,19 +634,19 @@ func (vals *ValidatorSet) UpdateWithChangeSet(changes []*Validator) error {
|
||||||
|
|
||||||
func IsErrTooMuchChange(err error) bool {
|
func IsErrTooMuchChange(err error) bool {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case errTooMuchChange:
|
case tooMuchChangeError:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type errTooMuchChange struct {
|
type tooMuchChangeError struct {
|
||||||
got int64
|
got int64
|
||||||
needed int64
|
needed int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e errTooMuchChange) Error() string {
|
func (e tooMuchChangeError) Error() string {
|
||||||
return fmt.Sprintf("Invalid commit -- insufficient old voting power: got %v, needed %v", e.got, e.needed)
|
return fmt.Sprintf("Invalid commit -- insufficient old voting power: got %v, needed %v", e.got, e.needed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -622,11 +660,14 @@ func (vals *ValidatorSet) StringIndented(indent string) string {
|
||||||
if vals == nil {
|
if vals == nil {
|
||||||
return "nil-ValidatorSet"
|
return "nil-ValidatorSet"
|
||||||
}
|
}
|
||||||
|
|
||||||
var valStrings []string
|
var valStrings []string
|
||||||
|
|
||||||
vals.Iterate(func(index int, val *Validator) bool {
|
vals.Iterate(func(index int, val *Validator) bool {
|
||||||
valStrings = append(valStrings, val.String())
|
valStrings = append(valStrings, val.String())
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
return fmt.Sprintf(`ValidatorSet{
|
return fmt.Sprintf(`ValidatorSet{
|
||||||
%s Proposer: %v
|
%s Proposer: %v
|
||||||
%s Validators:
|
%s Validators:
|
||||||
|
|
@ -636,7 +677,6 @@ func (vals *ValidatorSet) StringIndented(indent string) string {
|
||||||
indent,
|
indent,
|
||||||
indent, strings.Join(valStrings, "\n"+indent+" "),
|
indent, strings.Join(valStrings, "\n"+indent+" "),
|
||||||
indent)
|
indent)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
@ -668,6 +708,7 @@ func safeAdd(a, b int64) (int64, bool) {
|
||||||
} else if b < 0 && a < math.MinInt64-b {
|
} else if b < 0 && a < math.MinInt64-b {
|
||||||
return -1, true
|
return -1, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return a + b, false
|
return a + b, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -677,6 +718,7 @@ func safeSub(a, b int64) (int64, bool) {
|
||||||
} else if b < 0 && a > math.MaxInt64+b {
|
} else if b < 0 && a > math.MaxInt64+b {
|
||||||
return -1, true
|
return -1, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return a - b, false
|
return a - b, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -686,8 +728,10 @@ func safeAddClip(a, b int64) int64 {
|
||||||
if b < 0 {
|
if b < 0 {
|
||||||
return math.MinInt64
|
return math.MinInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
return math.MaxInt64
|
return math.MaxInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -697,7 +741,9 @@ func safeSubClip(a, b int64) int64 {
|
||||||
if b > 0 {
|
if b > 0 {
|
||||||
return math.MinInt64
|
return math.MinInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
return math.MaxInt64
|
return math.MaxInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ func (a *Account) MarkDown() string {
|
||||||
"- [```account list```](./account_list.md): List the wallets in the Bor client.",
|
"- [```account list```](./account_list.md): List the wallets in the Bor client.",
|
||||||
"- [```account import```](./account_import.md): Import an account to the Bor client.",
|
"- [```account import```](./account_import.md): Import an account to the Bor client.",
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ func (a *AccountImportCommand) MarkDown() string {
|
||||||
"The ```account import``` command imports an account in Json format to the Bor data directory.",
|
"The ```account import``` command imports an account in Json format to the Bor data directory.",
|
||||||
a.Flags().MarkDown(),
|
a.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,7 +59,9 @@ func (a *AccountImportCommand) Run(args []string) int {
|
||||||
a.UI.Error("Expected one argument")
|
a.UI.Error("Expected one argument")
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := crypto.LoadECDSA(args[0])
|
key, err := crypto.LoadECDSA(args[0])
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.UI.Error(fmt.Sprintf("Failed to load the private key '%s': %v", args[0], err))
|
a.UI.Error(fmt.Sprintf("Failed to load the private key '%s': %v", args[0], err))
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -80,6 +83,8 @@ func (a *AccountImportCommand) Run(args []string) int {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Could not create the account: %v", err)
|
utils.Fatalf("Could not create the account: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a.UI.Output(fmt.Sprintf("Account created: %s", acct.Address.String()))
|
a.UI.Output(fmt.Sprintf("Account created: %s", acct.Address.String()))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ func (a *AccountListCommand) MarkDown() string {
|
||||||
"The `account list` command lists all the accounts in the Bor data directory.",
|
"The `account list` command lists all the accounts in the Bor data directory.",
|
||||||
a.Flags().MarkDown(),
|
a.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,7 +54,9 @@ func (a *AccountListCommand) Run(args []string) int {
|
||||||
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
a.UI.Output(formatAccounts(keystore.Accounts()))
|
a.UI.Output(formatAccounts(keystore.Accounts()))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,10 +67,12 @@ func formatAccounts(accts []accounts.Account) string {
|
||||||
|
|
||||||
rows := make([]string, len(accts)+1)
|
rows := make([]string, len(accts)+1)
|
||||||
rows[0] = "Index|Address"
|
rows[0] = "Index|Address"
|
||||||
|
|
||||||
for i, d := range accts {
|
for i, d := range accts {
|
||||||
rows[i+1] = fmt.Sprintf("%d|%s",
|
rows[i+1] = fmt.Sprintf("%d|%s",
|
||||||
i,
|
i,
|
||||||
d.Address.String())
|
d.Address.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatList(rows)
|
return formatList(rows)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ func (a *AccountNewCommand) MarkDown() string {
|
||||||
"The `account new` command creates a new local account file on the Bor data directory. Bor should not be running to execute this command.",
|
"The `account new` command creates a new local account file on the Bor data directory. Bor should not be running to execute this command.",
|
||||||
a.Flags().MarkDown(),
|
a.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/console"
|
"github.com/ethereum/go-ethereum/console"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -33,6 +33,7 @@ func (c *AttachCommand) MarkDown() string {
|
||||||
"Connect to remote Bor IPC console.",
|
"Connect to remote Bor IPC console.",
|
||||||
c.Flags().MarkDown(),
|
c.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,7 +50,6 @@ func (c *AttachCommand) Synopsis() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AttachCommand) Flags() *flagset.Flagset {
|
func (c *AttachCommand) Flags() *flagset.Flagset {
|
||||||
|
|
||||||
f := flagset.NewFlagSet("attach")
|
f := flagset.NewFlagSet("attach")
|
||||||
|
|
||||||
f.StringFlag(&flagset.StringFlag{
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
|
@ -75,13 +75,13 @@ func (c *AttachCommand) Flags() *flagset.Flagset {
|
||||||
|
|
||||||
// Run implements the cli.Command interface
|
// Run implements the cli.Command interface
|
||||||
func (c *AttachCommand) Run(args []string) int {
|
func (c *AttachCommand) Run(args []string) int {
|
||||||
|
|
||||||
flags := c.Flags()
|
flags := c.Flags()
|
||||||
|
|
||||||
//check if first arg is flag or IPC location
|
//check if first arg is flag or IPC location
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
args = append(args, "")
|
args = append(args, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
if args[0] != "" && strings.HasPrefix(args[0], "--") {
|
if args[0] != "" && strings.HasPrefix(args[0], "--") {
|
||||||
if err := flags.Parse(args); err != nil {
|
if err := flags.Parse(args); err != nil {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
|
|
@ -94,6 +94,7 @@ func (c *AttachCommand) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.remoteConsole(); err != nil {
|
if err := c.remoteConsole(); err != nil {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -104,25 +105,30 @@ func (c *AttachCommand) Run(args []string) int {
|
||||||
|
|
||||||
// remoteConsole will connect to a remote bor instance, attaching a JavaScript
|
// remoteConsole will connect to a remote bor instance, attaching a JavaScript
|
||||||
// console to it.
|
// console to it.
|
||||||
|
// nolint: unparam
|
||||||
func (c *AttachCommand) remoteConsole() error {
|
func (c *AttachCommand) remoteConsole() error {
|
||||||
// Attach to a remotely running geth instance and start the JavaScript console
|
// Attach to a remotely running geth instance and start the JavaScript console
|
||||||
|
|
||||||
path := node.DefaultDataDir()
|
path := node.DefaultDataDir()
|
||||||
|
|
||||||
if c.Endpoint == "" {
|
if c.Endpoint == "" {
|
||||||
if c.Meta.dataDir != "" {
|
if c.Meta.dataDir != "" {
|
||||||
path = c.Meta.dataDir
|
path = c.Meta.dataDir
|
||||||
}
|
}
|
||||||
|
|
||||||
if path != "" {
|
if path != "" {
|
||||||
homeDir, _ := os.UserHomeDir()
|
homeDir, _ := os.UserHomeDir()
|
||||||
path = filepath.Join(homeDir, "/.bor/data")
|
path = filepath.Join(homeDir, "/.bor/data")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Endpoint = fmt.Sprintf("%s/bor.ipc", path)
|
c.Endpoint = fmt.Sprintf("%s/bor.ipc", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := dialRPC(c.Endpoint)
|
client, err := dialRPC(c.Endpoint)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Unable to attach to remote bor: %v", err)
|
utils.Fatalf("Unable to attach to remote bor: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config := console.Config{
|
config := console.Config{
|
||||||
DataDir: path,
|
DataDir: path,
|
||||||
DocRoot: c.JSpathFlag,
|
DocRoot: c.JSpathFlag,
|
||||||
|
|
@ -134,7 +140,12 @@ func (c *AttachCommand) remoteConsole() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to start the JavaScript console: %v", err)
|
utils.Fatalf("Failed to start the JavaScript console: %v", err)
|
||||||
}
|
}
|
||||||
defer console.Stop(false)
|
|
||||||
|
defer func() {
|
||||||
|
if err := console.Stop(false); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if c.ExecCMD != "" {
|
if c.ExecCMD != "" {
|
||||||
console.Evaluate(c.ExecCMD)
|
console.Evaluate(c.ExecCMD)
|
||||||
|
|
@ -159,6 +170,7 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
|
||||||
// these prefixes.
|
// these prefixes.
|
||||||
endpoint = endpoint[4:]
|
endpoint = endpoint[4:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return rpc.Dial(endpoint)
|
return rpc.Dial(endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,10 +182,12 @@ func (c *AttachCommand) makeConsolePreloads() []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Otherwise resolve absolute paths and return them
|
// Otherwise resolve absolute paths and return them
|
||||||
var preloads []string
|
splitFlags := strings.Split(c.PreloadJSFlag, ",")
|
||||||
|
preloads := make([]string, 0, len(splitFlags))
|
||||||
|
|
||||||
for _, file := range strings.Split(c.PreloadJSFlag, ",") {
|
for _, file := range splitFlags {
|
||||||
preloads = append(preloads, strings.TrimSpace(file))
|
preloads = append(preloads, strings.TrimSpace(file))
|
||||||
}
|
}
|
||||||
|
|
||||||
return preloads
|
return preloads
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -45,6 +46,7 @@ func (c *BootnodeCommand) MarkDown() string {
|
||||||
"# Bootnode",
|
"# Bootnode",
|
||||||
c.Flags().MarkDown(),
|
c.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,6 +105,7 @@ func (b *BootnodeCommand) Synopsis() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run implements the cli.Command interface
|
// Run implements the cli.Command interface
|
||||||
|
// nolint: gocognit
|
||||||
func (b *BootnodeCommand) Run(args []string) int {
|
func (b *BootnodeCommand) Run(args []string) int {
|
||||||
flags := b.Flags()
|
flags := b.Flags()
|
||||||
if err := flags.Parse(args); err != nil {
|
if err := flags.Parse(args); err != nil {
|
||||||
|
|
@ -118,6 +121,7 @@ func (b *BootnodeCommand) Run(args []string) int {
|
||||||
} else {
|
} else {
|
||||||
glogger.Verbosity(log.LvlInfo)
|
glogger.Verbosity(log.LvlInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Root().SetHandler(glogger)
|
log.Root().SetHandler(glogger)
|
||||||
|
|
||||||
natm, err := nat.Parse(b.nat)
|
natm, err := nat.Parse(b.nat)
|
||||||
|
|
@ -128,6 +132,7 @@ func (b *BootnodeCommand) Run(args []string) int {
|
||||||
|
|
||||||
// create a one time key
|
// create a one time key
|
||||||
var nodeKey *ecdsa.PrivateKey
|
var nodeKey *ecdsa.PrivateKey
|
||||||
|
// nolint: nestif
|
||||||
if b.nodeKey != "" {
|
if b.nodeKey != "" {
|
||||||
// try to read the key either from file or command line
|
// try to read the key either from file or command line
|
||||||
if _, err := os.Stat(b.nodeKey); errors.Is(err, os.ErrNotExist) {
|
if _, err := os.Stat(b.nodeKey); errors.Is(err, os.ErrNotExist) {
|
||||||
|
|
@ -157,7 +162,7 @@ func (b *BootnodeCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
// save the public key
|
// save the public key
|
||||||
pubRaw := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:])
|
pubRaw := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:])
|
||||||
if err := ioutil.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 0755); err != nil {
|
if err := ioutil.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 0600); err != nil {
|
||||||
b.UI.Error(fmt.Sprintf("failed to write node pub key: %v", err))
|
b.UI.Error(fmt.Sprintf("failed to write node pub key: %v", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
@ -169,7 +174,9 @@ func (b *BootnodeCommand) Run(args []string) int {
|
||||||
b.UI.Error(fmt.Sprintf("could not resolve udp addr '%s': %v", b.listenAddr, err))
|
b.UI.Error(fmt.Sprintf("could not resolve udp addr '%s': %v", b.listenAddr, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp", addr)
|
conn, err := net.ListenUDP("udp", addr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.UI.Error(fmt.Sprintf("failed to listen udp addr '%s': %v", b.listenAddr, err))
|
b.UI.Error(fmt.Sprintf("failed to listen udp addr '%s': %v", b.listenAddr, err))
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -180,7 +187,9 @@ func (b *BootnodeCommand) Run(args []string) int {
|
||||||
if !realaddr.IP.IsLoopback() {
|
if !realaddr.IP.IsLoopback() {
|
||||||
go nat.Map(natm, nil, "udp", realaddr.Port, realaddr.Port, "ethereum discovery")
|
go nat.Map(natm, nil, "udp", realaddr.Port, realaddr.Port, "ethereum discovery")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ext, err := natm.ExternalIP(); err == nil {
|
if ext, err := natm.ExternalIP(); err == nil {
|
||||||
|
// nolint: govet
|
||||||
realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}
|
realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,6 +207,7 @@ func (b *BootnodeCommand) Run(args []string) int {
|
||||||
PrivateKey: nodeKey,
|
PrivateKey: nodeKey,
|
||||||
Log: log.Root(),
|
Log: log.Root(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.v5 {
|
if b.v5 {
|
||||||
if _, err := discover.ListenV5(conn, ln, cfg); err != nil {
|
if _, err := discover.ListenV5(conn, ln, cfg); err != nil {
|
||||||
utils.Fatalf("%v", err)
|
utils.Fatalf("%v", err)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
"github.com/shirou/gopsutil/cpu"
|
"github.com/shirou/gopsutil/cpu"
|
||||||
"github.com/shirou/gopsutil/disk"
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
|
@ -25,6 +26,7 @@ func (c *FingerprintCommand) MarkDown() string {
|
||||||
"# Fingerprint",
|
"# Fingerprint",
|
||||||
"Display the system fingerprint",
|
"Display the system fingerprint",
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,6 +47,7 @@ func getCoresCount(cp []cpu.InfoStat) int {
|
||||||
for i := 0; i < len(cp); i++ {
|
for i := 0; i < len(cp); i++ {
|
||||||
cores += int(cp[i].Cores)
|
cores += int(cp[i].Cores)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cores
|
return cores
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +79,7 @@ func formatFingerprint(borFingerprint *BorFingerprint) string {
|
||||||
fmt.Sprintf("RAM :: total : %v GB, free : %v GB, used : %v GB", borFingerprint.MemoryDetails.TotalMem, borFingerprint.MemoryDetails.FreeMem, borFingerprint.MemoryDetails.UsedMem),
|
fmt.Sprintf("RAM :: total : %v GB, free : %v GB, used : %v GB", borFingerprint.MemoryDetails.TotalMem, borFingerprint.MemoryDetails.FreeMem, borFingerprint.MemoryDetails.UsedMem),
|
||||||
fmt.Sprintf("STORAGE :: total : %v GB, free : %v GB, used : %v GB", borFingerprint.DiskDetails.TotalDisk, borFingerprint.DiskDetails.FreeDisk, borFingerprint.DiskDetails.UsedDisk),
|
fmt.Sprintf("STORAGE :: total : %v GB, free : %v GB, used : %v GB", borFingerprint.DiskDetails.TotalDisk, borFingerprint.DiskDetails.FreeDisk, borFingerprint.DiskDetails.UsedDisk),
|
||||||
})
|
})
|
||||||
|
|
||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,13 +89,13 @@ func convertBytesToGB(bytesValue uint64) float64 {
|
||||||
|
|
||||||
// Checks if fio exists on the node
|
// Checks if fio exists on the node
|
||||||
func (c *FingerprintCommand) checkFio() error {
|
func (c *FingerprintCommand) checkFio() error {
|
||||||
|
|
||||||
cmd := exec.Command("/bin/sh", "-c", "fio -v")
|
cmd := exec.Command("/bin/sh", "-c", "fio -v")
|
||||||
|
|
||||||
_, err := cmd.CombinedOutput()
|
_, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
message := "\nFio package not installed. Install Fio for IOPS Benchmarking :\n\nDebianOS : 'sudo apt-get update && sudo apt-get install fio -y'\nAWS AMI/CentOS : 'sudo yum install fio -y'\nOracle LinuxOS : 'sudo dnf install fio -y'\n"
|
message := "\nFio package not installed. Install Fio for IOPS Benchmarking :\n\nDebianOS : 'sudo apt-get update && sudo apt-get install fio -y'\nAWS AMI/CentOS : 'sudo yum install fio -y'\nOracle LinuxOS : 'sudo dnf install fio -y'\n"
|
||||||
c.UI.Output(message)
|
c.UI.Output(message)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,9 +105,12 @@ func (c *FingerprintCommand) checkFio() error {
|
||||||
// Run the IOPS benchmark for the node
|
// Run the IOPS benchmark for the node
|
||||||
func (c *FingerprintCommand) benchmark() error {
|
func (c *FingerprintCommand) benchmark() error {
|
||||||
var b []byte
|
var b []byte
|
||||||
|
|
||||||
err := c.checkFio()
|
err := c.checkFio()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
// Missing Fio is not a fatal error. A message will be logged in console when it is missing in "checkFio()".
|
||||||
|
return nil //nolint:nilerr
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output("\nRunning a 10 second test...\n")
|
c.UI.Output("\nRunning a 10 second test...\n")
|
||||||
|
|
@ -123,7 +130,6 @@ func (c *FingerprintCommand) benchmark() error {
|
||||||
|
|
||||||
// Run implements the cli.Command interface
|
// Run implements the cli.Command interface
|
||||||
func (c *FingerprintCommand) Run(args []string) int {
|
func (c *FingerprintCommand) Run(args []string) int {
|
||||||
|
|
||||||
v, err := mem.VirtualMemory()
|
v, err := mem.VirtualMemory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ func (c *ChainCommand) MarkDown() string {
|
||||||
"- [```chain sethead```](./chain_sethead.md): Set the current chain to a certain block.",
|
"- [```chain sethead```](./chain_sethead.md): Set the current chain to a certain block.",
|
||||||
"- [```chain watch```](./chain_watch.md): Watch the chainHead, reorg and fork events in real-time.",
|
"- [```chain watch```](./chain_watch.md): Watch the chainHead, reorg and fork events in real-time.",
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ func (a *ChainSetHeadCommand) MarkDown() string {
|
||||||
"- ```number```: The block number to roll back.",
|
"- ```number```: The block number to roll back.",
|
||||||
a.Flags().MarkDown(),
|
a.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,6 +46,7 @@ func (c *ChainSetHeadCommand) Flags() *flagset.Flagset {
|
||||||
Default: false,
|
Default: false,
|
||||||
Value: &c.yes,
|
Value: &c.yes,
|
||||||
})
|
})
|
||||||
|
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,6 +90,7 @@ func (c *ChainSetHeadCommand) Run(args []string) int {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if response != "y" {
|
if response != "y" {
|
||||||
c.UI.Output("set head aborted")
|
c.UI.Output("set head aborted")
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -100,5 +103,6 @@ func (c *ChainSetHeadCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output("Done!")
|
c.UI.Output("Done!")
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ func (c *ChainWatchCommand) MarkDown() string {
|
||||||
"# Chain watch",
|
"# Chain watch",
|
||||||
"The ```chain watch``` command is used to view the chainHead, reorg and fork events in real-time.",
|
"The ```chain watch``` command is used to view the chainHead, reorg and fork events in real-time.",
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,7 +71,10 @@ func (c *ChainWatchCommand) Run(args []string) int {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-signalCh
|
<-signalCh
|
||||||
sub.CloseSend()
|
|
||||||
|
if err := sub.CloseSend(); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
@ -80,6 +84,7 @@ func (c *ChainWatchCommand) Run(args []string) int {
|
||||||
c.UI.Output(err.Error())
|
c.UI.Output(err.Error())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output(formatHeadEvent(msg))
|
c.UI.Output(formatHeadEvent(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,5 +100,6 @@ func formatHeadEvent(msg *proto.ChainWatchResponse) string {
|
||||||
} else if msg.Type == core.Chain2HeadReorgEvent {
|
} else if msg.Type == core.Chain2HeadReorgEvent {
|
||||||
out = fmt.Sprintf("Reorg Detected \nAdded : %v \nRemoved : %v", msg.Newchain, msg.Oldchain)
|
out = fmt.Sprintf("Reorg Detected \nAdded : %v \nRemoved : %v", msg.Newchain, msg.Oldchain)
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,16 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/server"
|
"github.com/ethereum/go-ethereum/internal/cli/server"
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
"github.com/ryanuber/columnize"
|
"github.com/ryanuber/columnize"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
emptyPlaceHolder = "<none>"
|
||||||
|
)
|
||||||
|
|
||||||
type MarkDownCommand interface {
|
type MarkDownCommand interface {
|
||||||
MarkDown
|
MarkDown
|
||||||
cli.Command
|
cli.Command
|
||||||
|
|
@ -48,6 +53,7 @@ func Run(args []string) int {
|
||||||
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
|
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return exitCode
|
return exitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,6 +70,7 @@ func Commands() map[string]MarkDownCommandFactory {
|
||||||
meta := &Meta{
|
meta := &Meta{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[string]MarkDownCommandFactory{
|
return map[string]MarkDownCommandFactory{
|
||||||
"server": func() (MarkDownCommand, error) {
|
"server": func() (MarkDownCommand, error) {
|
||||||
return &server.Command{
|
return &server.Command{
|
||||||
|
|
@ -180,6 +187,7 @@ func (m *Meta2) NewFlagSet(n string) *flagset.Flagset {
|
||||||
Usage: "Address of the grpc endpoint",
|
Usage: "Address of the grpc endpoint",
|
||||||
Default: "127.0.0.1:3131",
|
Default: "127.0.0.1:3131",
|
||||||
})
|
})
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,6 +196,7 @@ func (m *Meta2) Conn() (*grpc.ClientConn, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to connect to server: %v", err)
|
return nil, fmt.Errorf("failed to connect to server: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,6 +205,7 @@ func (m *Meta2) BorConn() (proto.BorClient, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return proto.NewBorClient(conn), nil
|
return proto.NewBorClient(conn), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,18 +253,21 @@ func (m *Meta) GetKeystore() (*keystore.KeyStore, error) {
|
||||||
scryptP := keystore.StandardScryptP
|
scryptP := keystore.StandardScryptP
|
||||||
|
|
||||||
keys := keystore.NewKeyStore(keydir, scryptN, scryptP)
|
keys := keystore.NewKeyStore(keydir, scryptN, scryptP)
|
||||||
|
|
||||||
return keys, nil
|
return keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatList(in []string) string {
|
func formatList(in []string) string {
|
||||||
columnConf := columnize.DefaultConfig()
|
columnConf := columnize.DefaultConfig()
|
||||||
columnConf.Empty = "<none>"
|
columnConf.Empty = emptyPlaceHolder
|
||||||
|
|
||||||
return columnize.Format(in, columnConf)
|
return columnize.Format(in, columnConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatKV(in []string) string {
|
func formatKV(in []string) string {
|
||||||
columnConf := columnize.DefaultConfig()
|
columnConf := columnize.DefaultConfig()
|
||||||
columnConf.Empty = "<none>"
|
columnConf.Empty = emptyPlaceHolder
|
||||||
columnConf.Glue = " = "
|
columnConf.Glue = " = "
|
||||||
|
|
||||||
return columnize.Format(in, columnConf)
|
return columnize.Format(in, columnConf)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
||||||
"github.com/golang/protobuf/jsonpb"
|
|
||||||
gproto "github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/jsonpb" // nolint:staticcheck
|
||||||
|
gproto "github.com/golang/protobuf/proto" // nolint:staticcheck
|
||||||
"github.com/golang/protobuf/ptypes/empty"
|
"github.com/golang/protobuf/ptypes/empty"
|
||||||
grpc_net_conn "github.com/mitchellh/go-grpc-net-conn"
|
grpc_net_conn "github.com/mitchellh/go-grpc-net-conn"
|
||||||
)
|
)
|
||||||
|
|
@ -55,6 +56,7 @@ func (d *DebugCommand) MarkDown() string {
|
||||||
d.Flags().MarkDown(),
|
d.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
items = append(items, examples...)
|
items = append(items, examples...)
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,6 +114,7 @@ func (d *DebugCommand) Run(args []string) int {
|
||||||
// User specified output directory
|
// User specified output directory
|
||||||
tmp = filepath.Join(d.output, stamped)
|
tmp = filepath.Join(d.output, stamped)
|
||||||
_, err := os.Stat(tmp)
|
_, err := os.Stat(tmp)
|
||||||
|
|
||||||
if !os.IsNotExist(err) {
|
if !os.IsNotExist(err) {
|
||||||
d.UI.Error("Output directory already exists")
|
d.UI.Error("Output directory already exists")
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -139,6 +142,7 @@ func (d *DebugCommand) Run(args []string) int {
|
||||||
req := &proto.PprofRequest{
|
req := &proto.PprofRequest{
|
||||||
Seconds: int64(d.seconds),
|
Seconds: int64(d.seconds),
|
||||||
}
|
}
|
||||||
|
|
||||||
switch profile {
|
switch profile {
|
||||||
case "cpu":
|
case "cpu":
|
||||||
req.Type = proto.PprofRequest_CPU
|
req.Type = proto.PprofRequest_CPU
|
||||||
|
|
@ -148,7 +152,9 @@ func (d *DebugCommand) Run(args []string) int {
|
||||||
req.Type = proto.PprofRequest_LOOKUP
|
req.Type = proto.PprofRequest_LOOKUP
|
||||||
req.Profile = profile
|
req.Profile = profile
|
||||||
}
|
}
|
||||||
|
|
||||||
stream, err := clt.Pprof(ctx, req)
|
stream, err := clt.Pprof(ctx, req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -157,6 +163,7 @@ func (d *DebugCommand) Run(args []string) int {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := msg.Event.(*proto.PprofResponse_Open_); !ok {
|
if _, ok := msg.Event.(*proto.PprofResponse_Open_); !ok {
|
||||||
return fmt.Errorf("expected open message")
|
return fmt.Errorf("expected open message")
|
||||||
}
|
}
|
||||||
|
|
@ -179,6 +186,7 @@ func (d *DebugCommand) Run(args []string) int {
|
||||||
if _, err := io.Copy(file, conn); err != nil {
|
if _, err := io.Copy(file, conn); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,7 +218,7 @@ func (d *DebugCommand) Run(args []string) int {
|
||||||
d.UI.Output(err.Error())
|
d.UI.Output(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(filepath.Join(tmp, "status.json"), []byte(data), 0644); err != nil {
|
if err := ioutil.WriteFile(filepath.Join(tmp, "status.json"), []byte(data), 0600); err != nil {
|
||||||
d.UI.Output(fmt.Sprintf("Failed to write status: %v", err))
|
d.UI.Output(fmt.Sprintf("Failed to write status: %v", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
@ -230,6 +238,7 @@ func (d *DebugCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
d.UI.Output(fmt.Sprintf("Created debug archive: %s", archiveFile))
|
d.UI.Output(fmt.Sprintf("Created debug archive: %s", archiveFile))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCodeBlock(t *testing.T) {
|
func TestCodeBlock(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
lines := []string{
|
lines := []string{
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ func (a *PeersCommand) MarkDown() string {
|
||||||
"- [```peers remove```](./peers_remove.md): Disconnects the local client from a connected peer if exists.",
|
"- [```peers remove```](./peers_remove.md): Disconnects the local client from a connected peer if exists.",
|
||||||
"- [```peers status```](./peers_status.md): Display the status of a peer by its id.",
|
"- [```peers status```](./peers_status.md): Display the status of a peer by its id.",
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ func (p *PeersAddCommand) MarkDown() string {
|
||||||
"The ```peers add <enode>``` command joins the local client to another remote peer.",
|
"The ```peers add <enode>``` command joins the local client to another remote peer.",
|
||||||
p.Flags().MarkDown(),
|
p.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,5 +80,6 @@ func (c *PeersAddCommand) Run(args []string) int {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ func (p *PeersListCommand) MarkDown() string {
|
||||||
"The ```peers list``` command lists the connected peers.",
|
"The ```peers list``` command lists the connected peers.",
|
||||||
p.Flags().MarkDown(),
|
p.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,12 +61,14 @@ func (c *PeersListCommand) Run(args []string) int {
|
||||||
|
|
||||||
req := &proto.PeersListRequest{}
|
req := &proto.PeersListRequest{}
|
||||||
resp, err := borClt.PeersList(context.Background(), req)
|
resp, err := borClt.PeersList(context.Background(), req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output(formatPeers(resp.Peers))
|
c.UI.Output(formatPeers(resp.Peers))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +79,7 @@ func formatPeers(peers []*proto.Peer) string {
|
||||||
|
|
||||||
rows := make([]string, len(peers)+1)
|
rows := make([]string, len(peers)+1)
|
||||||
rows[0] = "ID|Enode|Name|Caps|Static|Trusted"
|
rows[0] = "ID|Enode|Name|Caps|Static|Trusted"
|
||||||
|
|
||||||
for i, d := range peers {
|
for i, d := range peers {
|
||||||
enode := strings.TrimPrefix(d.Enode, "enode://")
|
enode := strings.TrimPrefix(d.Enode, "enode://")
|
||||||
|
|
||||||
|
|
@ -87,5 +91,6 @@ func formatPeers(peers []*proto.Peer) string {
|
||||||
d.Static,
|
d.Static,
|
||||||
d.Trusted)
|
d.Trusted)
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatList(rows)
|
return formatList(rows)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ func (p *PeersRemoveCommand) MarkDown() string {
|
||||||
"The ```peers remove <enode>``` command disconnects the local client from a connected peer if exists.",
|
"The ```peers remove <enode>``` command disconnects the local client from a connected peer if exists.",
|
||||||
p.Flags().MarkDown(),
|
p.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,5 +80,6 @@ func (c *PeersRemoveCommand) Run(args []string) int {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ func (p *PeersStatusCommand) MarkDown() string {
|
||||||
"The ```peers status <peer id>``` command displays the status of a peer by its id.",
|
"The ```peers status <peer id>``` command displays the status of a peer by its id.",
|
||||||
p.Flags().MarkDown(),
|
p.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,12 +69,14 @@ func (c *PeersStatusCommand) Run(args []string) int {
|
||||||
Enode: args[0],
|
Enode: args[0],
|
||||||
}
|
}
|
||||||
resp, err := borClt.PeersStatus(context.Background(), req)
|
resp, err := borClt.PeersStatus(context.Background(), req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output(formatPeer(resp.Peer))
|
c.UI.Output(formatPeer(resp.Peer))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,5 +90,6 @@ func formatPeer(peer *proto.Peer) string {
|
||||||
fmt.Sprintf("Static|%v", peer.Static),
|
fmt.Sprintf("Static|%v", peer.Static),
|
||||||
fmt.Sprintf("Trusted|%v", peer.Trusted),
|
fmt.Sprintf("Trusted|%v", peer.Trusted),
|
||||||
})
|
})
|
||||||
|
|
||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
||||||
|
|
||||||
"github.com/golang/protobuf/ptypes/empty"
|
"github.com/golang/protobuf/ptypes/empty"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -20,6 +21,7 @@ func (p *StatusCommand) MarkDown() string {
|
||||||
"# Status",
|
"# Status",
|
||||||
"The ```status``` command outputs the status of the client.",
|
"The ```status``` command outputs the status of the client.",
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,6 +58,7 @@ func (c *StatusCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output(printStatus(status))
|
c.UI.Output(printStatus(status))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,6 +72,7 @@ func printStatus(status *proto.StatusResponse) string {
|
||||||
|
|
||||||
forks := make([]string, len(status.Forks)+1)
|
forks := make([]string, len(status.Forks)+1)
|
||||||
forks[0] = "Name|Block|Enabled"
|
forks[0] = "Name|Block|Enabled"
|
||||||
|
|
||||||
for i, d := range status.Forks {
|
for i, d := range status.Forks {
|
||||||
forks[i+1] = fmt.Sprintf("%s|%d|%v", d.Name, d.Block, !d.Disabled)
|
forks[i+1] = fmt.Sprintf("%s|%d|%v", d.Name, d.Block, !d.Disabled)
|
||||||
}
|
}
|
||||||
|
|
@ -92,5 +96,6 @@ func printStatus(status *proto.StatusResponse) string {
|
||||||
"\nForks",
|
"\nForks",
|
||||||
formatList(forks),
|
formatList(forks),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(full, "\n")
|
return strings.Join(full, "\n")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -27,6 +28,7 @@ func (d *VersionCommand) MarkDown() string {
|
||||||
"The ```bor version``` command outputs the version of the binary.",
|
"The ```bor version``` command outputs the version of the binary.",
|
||||||
}
|
}
|
||||||
items = append(items, examples...)
|
items = append(items, examples...)
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue