Merge pull request #410 from cffls/v0.3.0-dev-lint

Lint consensus/bor and internal/cli
This commit is contained in:
Jerry 2022-05-26 12:28:40 -07:00 committed by GitHub
commit 96228cc2dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 417 additions and 99 deletions

View file

@ -6,7 +6,7 @@ on:
pull_request:
branches:
- "**"
types: [opened, synchronize]
types: [opened, synchronize, edited]
concurrency:
group: build-${{ github.event.pull_request.number || github.ref }}

View file

@ -28,7 +28,7 @@ linters:
- exportloopref
- gocognit
- gofmt
- gomnd
# - gomnd
- gomoddirectives
- gosec
- makezero
@ -42,7 +42,7 @@ linters:
- predeclared
#- promlinter
#- revive
- tagliatelle
# - tagliatelle
- tenv
- thelper
- tparallel
@ -65,7 +65,7 @@ linters-settings:
local-prefixes: github.com/ethereum/go-ethereum
nestif:
min-complexity: 3
min-complexity: 5
prealloc:
for-loops: true
@ -183,4 +183,4 @@ issues:
max-issues-per-linter: 0
max-same-issues: 0
#new: true
new-from-rev: origin/master
# new-from-rev: origin/master

View file

@ -65,7 +65,9 @@ escape:
cd $(path) && go test -gcflags "-m -m" -run none -bench=BenchmarkJumpdest* -benchmem -memprofile mem.out
lint:
@./build/bin/golangci-lint run --config ./.golangci.yml
@./build/bin/golangci-lint run --config ./.golangci.yml \
internal/cli \
consensus/bor
lintci-deps:
rm -f ./build/bin/golangci-lint

View file

@ -13,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rpc"
lru "github.com/hashicorp/golang-lru"
"github.com/xsleonard/go-merkle"
"golang.org/x/crypto/sha3"
@ -44,6 +45,7 @@ func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
if header == nil {
return nil, errUnknownBlock
}
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 {
var ss []difficultiesKV
ss := make([]difficultiesKV, 0, len(values))
for k, v := range values {
ss = append(ss, difficultiesKV{k, v})
}
sort.Slice(ss, func(i, j int) bool {
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
func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigners, error) {
snapNumber := *number - 1
var difficulties = make(map[common.Address]uint64)
snap, err := api.GetSnapshot(&snapNumber)
if err != nil {
return BlockSigners{}, err
}
proposer := snap.ValidatorSet.GetProposer().Address
proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
@ -88,6 +94,7 @@ func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigne
if tempIndex < proposerIndex {
tempIndex = tempIndex + len(signers)
}
difficulties[signers[i]] = uint64(len(signers) - (tempIndex - proposerIndex))
}
@ -97,6 +104,7 @@ func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigne
if err != nil {
return BlockSigners{}, err
}
diff := int(difficulties[*author])
blockSigners := &BlockSigners{
Signers: rankedDifficulties,
@ -111,9 +119,11 @@ func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigne
func (api *API) GetSnapshotProposer(number *rpc.BlockNumber) (common.Address, error) {
*number -= 1
snap, err := api.GetSnapshot(number)
if err != nil {
return common.Address{}, err
}
return snap.ValidatorSet.GetProposer().Address, nil
}
@ -130,7 +140,9 @@ func (api *API) GetAuthor(number *rpc.BlockNumber) (*common.Address, error) {
if header == nil {
return nil, errUnknownBlock
}
author, err := api.bor.Author(header)
return &author, err
}
@ -140,6 +152,7 @@ func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
if header == nil {
return nil, errUnknownBlock
}
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 {
return nil, errUnknownBlock
}
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil {
return nil, err
}
return snap.signers(), nil
}
@ -169,10 +185,13 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
if header == nil {
return nil, errUnknownBlock
}
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil {
return nil, err
}
return snap.signers(), nil
}
@ -182,6 +201,7 @@ func (api *API) GetCurrentProposer() (common.Address, error) {
if err != nil {
return common.Address{}, err
}
return snap.ValidatorSet.GetProposer().Address, nil
}
@ -191,6 +211,7 @@ func (api *API) GetCurrentValidators() ([]*Validator, error) {
if err != nil {
return make([]*Validator, 0), err
}
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 {
return "", err
}
key := getRootHashKey(start, end)
if root, known := api.rootHashCache.Get(key); known {
return root.(string), nil
}
length := uint64(end - start + 1)
length := end - start + 1
if length > MaxCheckpointLength {
return "", &MaxCheckpointLengthExceededError{start, end}
}
currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
if start > end || end > currentHeaderNumber {
return "", &InvalidStartEndBlockError{start, end, currentHeaderNumber}
}
blockHeaders := make([]*types.Header, end-start+1)
wg := new(sync.WaitGroup)
concurrent := make(chan bool, 20)
for i := start; i <= end; i++ {
wg.Add(1)
concurrent <- true
go func(number uint64) {
blockHeaders[number-start] = api.chain.GetHeaderByNumber(uint64(number))
blockHeaders[number-start] = api.chain.GetHeaderByNumber(number)
<-concurrent
wg.Done()
}(i)
@ -227,6 +258,7 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
close(concurrent)
headers := make([][32]byte, nextPowerOfTwo(length))
for i := 0; i < len(blockHeaders); i++ {
blockHeader := blockHeaders[i]
header := crypto.Keccak256(appendBytes32(
@ -237,6 +269,7 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
))
var arr [32]byte
copy(arr[:], header)
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 {
return "", err
}
root := hex.EncodeToString(tree.Root().Hash)
api.rootHashCache.Add(key, root)
return root, nil
}
@ -255,6 +290,7 @@ func (api *API) initializeRootHashCache() error {
if api.rootHashCache == nil {
api.rootHashCache, err = lru.NewARC(10)
}
return err
}

View file

@ -32,7 +32,6 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"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.
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
systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE")
)
@ -72,18 +68,6 @@ var (
// that is not part of the local blockchain.
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
// 32 bytes, which is required to store the signer vanity.
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 {
return common.Address{}, errMissingSignature
}
signature := header.Extra[len(header.Extra)-extraSeal:]
// 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 {
return common.Address{}, err
}
var signer common.Address
copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
sigcache.Add(hash, signer)
return signer, nil
}
@ -155,6 +143,7 @@ func SealHash(header *types.Header, c *params.BorConfig) (hash common.Hash) {
hasher := sha3.NewLegacyKeccak256()
encodeSigHeader(hasher, header, c)
hasher.Sum(hash[:0])
return hash
}
@ -176,11 +165,13 @@ func encodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) {
header.MixDigest,
header.Nonce,
}
if c.IsJaipur(header.Number.Uint64()) {
if header.BaseFee != nil {
enc = append(enc, header.BaseFee)
}
}
if err := rlp.Encode(w, enc); err != nil {
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 {
delay = c.ProducerDelay
}
if succession > 0 {
delay += uint64(succession) * c.CalculateBackupMultiplier(number)
}
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 {
b := new(bytes.Buffer)
encodeSigHeader(b, header, c)
return b.Bytes()
}
@ -233,7 +227,6 @@ type Bor struct {
HeimdallClient IHeimdallClient
WithoutHeimdall bool
scope event.SubscriptionScope
// The fields below are for testing only
fakeDiff bool // Skip difficulty verifications
}
@ -314,6 +307,7 @@ func (c *Bor) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.
}
}
}()
return abort, results
}
@ -325,6 +319,7 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
if header.Number == nil {
return errUnknownBlock
}
number := header.Number.Uint64()
// 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 {
return errExtraValidators
}
if isSprintEnd && signersBytes%validatorHeaderBytesLength != 0 {
return errInvalidSpanValidators
}
// Ensure that the mix digest is zero as we don't have fork protection currently
if header.MixDigest != (common.Hash{}) {
return errInvalidMixDigest
}
// Ensure that the block doesn't contain any uncles which are meaningless in PoA
if header.UncleHash != uncleHash {
return errInvalidUncleHash
}
// Ensure that the block's difficulty is meaningful (may not be correct at this point)
if number > 0 {
if header.Difficulty == nil {
return errInvalidDifficulty
}
}
// Verify that the gas limit is <= 2^63-1
cap := uint64(0x7fffffffffffffff)
if header.GasLimit > cap {
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap)
gasCap := uint64(0x7fffffffffffffff)
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 err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil {
return err
}
// All basic checks passed, verify cascading fields
return c.verifyCascadingFields(chain, header, parents)
}
@ -380,9 +383,11 @@ func validateHeaderExtraField(extraBytes []byte) error {
if len(extraBytes) < extraVanity {
return errMissingVanity
}
if len(extraBytes) < extraVanity+extraSeal {
return errMissingSignature
}
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 {
// The genesis block is the always valid dead-end
number := header.Number.Uint64()
if number == 0 {
return nil
}
// Ensure that the block's timestamp isn't too close to it's parent
var parent *types.Header
if len(parents) > 0 {
parent = parents[len(parents)-1]
} else {
@ -413,11 +420,13 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
if header.GasUsed > header.GasLimit {
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
}
if !chain.Config().IsLondon(header.Number) {
// Verify BaseFee not present before EIP-1559 fork.
if header.BaseFee != nil {
return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee)
}
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
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
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
if err != nil {
return err
}
@ -444,6 +454,7 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
currentValidators := snap.ValidatorSet.Copy().Validators
// sort validator by address
sort.Sort(ValidatorsByAddress(currentValidators))
for i, validator := range currentValidators {
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.
// nolint: gocognit
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
var (
headers []*types.Header
snap *Snapshot
)
var snap *Snapshot
headers := make([]*types.Header, 0, 16)
//nolint:govet
for snap == nil {
// If an in-memory snapshot was found, use that
if s, ok := c.recents.Get(hash); ok {
snap = s.(*Snapshot)
break
}
@ -476,7 +489,9 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
if number%checkpointInterval == 0 {
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)
snap = s
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),
// consider the checkpoint trusted and snapshot it.
// TODO fix this
// nolint:nestif
if number == 0 {
checkpoint := chain.GetHeaderByNumber(number)
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 {
return nil, err
}
log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash)
break
}
}
@ -516,6 +534,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
if header.Hash() != hash || header.Number.Uint64() != number {
return nil, consensus.ErrUnknownAncestor
}
parents = parents[:len(parents)-1]
} else {
// 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
}
}
headers = append(headers, header)
number, hash = number-1, header.ParentHash
}
log.Info("Snapshot has been found in %d headers depth.", len(headers))
// check if snapshot is nil
if snap == nil {
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 {
return nil, err
}
c.recents.Add(snap.Hash, snap)
// 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 {
return nil, err
}
log.Trace("Stored snapshot to disk", "number", snap.Number, "hash", snap.Hash)
}
return snap, err
}
@ -560,6 +585,7 @@ func (c *Bor) VerifyUncles(chain consensus.ChainReader, block *types.Block) erro
if len(block.Uncles()) > 0 {
return errors.New("uncles not allowed")
}
return nil
}
@ -590,6 +616,7 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
if err != nil {
return err
}
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
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 {
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
}
header.Extra = header.Extra[:extraVanity]
// 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.Sort(ValidatorsByAddress(newValidators))
for _, validator := range newValidators {
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
// 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)
if err != nil {
return err
@ -684,6 +713,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
if header.Time < uint64(time.Now().Unix()) {
header.Time = uint64(time.Now().Unix())
}
return nil
}
@ -693,7 +723,9 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
stateSyncData := []*types.StateSyncData{}
var err error
headerNumber := header.Number.Uint64()
if headerNumber%c.config.Sprint == 0 {
cx := chainContext{Chain: chain, Bor: c}
// 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) {
var alloc core.GenesisAlloc
b, err := json.Marshal(i)
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &alloc); err != nil {
return nil, err
}
return alloc, nil
}
@ -745,12 +781,14 @@ func (c *Bor) changeContractCodeIfNeeded(headerNumber uint64, state *state.State
if err != nil {
return fmt.Errorf("failed to decode genesis alloc: %v", err)
}
for addr, account := range allocs {
log.Info("change contract code", "address", addr)
state.SetCode(addr, account.Code)
}
}
}
return nil
}
@ -856,10 +894,12 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
if err != nil {
return err
}
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
// Wait until sealing is terminated or delay timeout.
log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay))
go func() {
select {
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(),
)
}
log.Info(
"Sealing successful",
"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))
}
}()
return nil
}
@ -898,6 +940,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, par
if err != nil {
return nil
}
return new(big.Int).SetUint64(snap.Difficulty(c.signer))
}
@ -948,6 +991,7 @@ func (c *Bor) GetCurrentSpan(headerHash common.Hash) (*Span, error) {
To: &toAddress,
Data: &msgData,
}, blockNr, nil)
if err != nil {
return nil, err
}
@ -998,15 +1042,16 @@ func (c *Bor) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) (
To: &toAddress,
Data: &msgData,
}, blockNr, nil)
if err != nil {
panic(err)
// return nil, err
}
var (
ret0 = new([]common.Address)
ret1 = new([]*big.Int)
)
out := &[]interface{}{
ret0,
ret1,
@ -1034,13 +1079,16 @@ func (c *Bor) checkAndCommitSpan(
) error {
headerNumber := header.Number.Uint64()
span, err := c.GetCurrentSpan(header.ParentHash)
if err != nil {
return err
}
if c.needToCommitSpan(span, headerNumber) {
err := c.fetchAndCommitSpan(span.ID+1, state, header, chain)
return err
}
return nil
}
@ -1072,10 +1120,11 @@ func (c *Bor) fetchAndCommitSpan(
var heimdallSpan HeimdallSpan
if c.WithoutHeimdall {
s, err := c.getNextHeimdallSpanForTest(newSpanID, state, header, chain)
s, err := c.getNextHeimdallSpanForTest(newSpanID, header, chain)
if err != nil {
return err
}
heimdallSpan = *s
} else {
response, err := c.HeimdallClient.FetchWithRetry(fmt.Sprintf("bor/span/%d", newSpanID), "")
@ -1098,27 +1147,32 @@ func (c *Bor) fetchAndCommitSpan(
}
// get validators bytes
var validators []MinimalVal
validators := make([]MinimalVal, 0, len(heimdallSpan.ValidatorSet.Validators))
for _, val := range heimdallSpan.ValidatorSet.Validators {
validators = append(validators, val.MinimalVal())
}
validatorBytes, err := rlp.EncodeToBytes(validators)
if err != nil {
return err
}
// get producers bytes
var producers []MinimalVal
producers := make([]MinimalVal, 0, len(heimdallSpan.SelectedProducers))
for _, val := range heimdallSpan.SelectedProducers {
producers = append(producers, val.MinimalVal())
}
producerBytes, err := rlp.EncodeToBytes(producers)
if err != nil {
return err
}
// method
method := "commitSpan"
log.Info("✅ Committing new span",
"id", heimdallSpan.ID,
"startBlock", heimdallSpan.StartBlock,
@ -1156,6 +1210,7 @@ func (c *Bor) CommitStates(
stateSyncs := make([]*types.StateSyncData, 0)
number := header.Number.Uint64()
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
if err != nil {
return nil, err
}
@ -1166,7 +1221,13 @@ func (c *Bor) CommitStates(
"Fetching state updates from Heimdall",
"fromID", lastStateID+1,
"to", to.Format(time.RFC3339))
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 val, ok := c.config.OverrideStateSyncRecords[strconv.FormatUint(number, 10)]; ok {
eventRecords = eventRecords[0:val]
@ -1174,10 +1235,12 @@ func (c *Bor) CommitStates(
}
chainID := c.chainConfig.ChainID.String()
for _, eventRecord := range eventRecords {
if eventRecord.ID <= lastStateID {
continue
}
if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
log.Error(err.Error())
break
@ -1196,6 +1259,7 @@ func (c *Bor) CommitStates(
}
lastStateID++
}
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) {
return &InvalidStateReceivedError{number, lastStateID, &to, eventRecord}
}
return nil
}
@ -1217,12 +1282,12 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) {
func (c *Bor) getNextHeimdallSpanForTest(
newSpanID uint64,
state *state.StateDB,
header *types.Header,
chain core.ChainContext,
) (*HeimdallSpan, error) {
headerNumber := header.Number.Uint64()
span, err := c.GetCurrentSpan(header.ParentHash)
if err != nil {
return nil, err
}
@ -1242,12 +1307,14 @@ func (c *Bor) getNextHeimdallSpanForTest(
} else {
span.StartBlock = span.EndBlock + 1
}
span.EndBlock = span.StartBlock + (100 * c.config.Sprint) - 1
selectedProducers := make([]Validator, len(snap.ValidatorSet.Validators))
for i, v := range snap.ValidatorSet.Validators {
selectedProducers[i] = *v
}
heimdallSpan := &HeimdallSpan{
Span: *span,
ValidatorSet: *snap.ValidatorSet,
@ -1335,10 +1402,11 @@ func applyMessage(
func validatorContains(a []*Validator, x *Validator) (*Validator, bool) {
for _, n := range a {
if bytes.Compare(n.Address.Bytes(), x.Address.Bytes()) == 0 {
if n.Address == x.Address {
return n, true
}
}
return nil, false
}
@ -1346,7 +1414,8 @@ func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator)
v := oldValidatorSet
oldVals := v.Validators
var changes []*Validator
changes := make([]*Validator, 0, len(oldVals))
for _, ov := range oldVals {
if f, ok := validatorContains(newVals, ov); ok {
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
}

View file

@ -4,6 +4,8 @@ import (
"math/big"
"testing"
"github.com/stretchr/testify/assert"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
@ -12,10 +14,11 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/assert"
)
func TestGenesisContractChange(t *testing.T) {
t.Parallel()
addr0 := common.Address{0x1}
b := &Bor{
@ -101,6 +104,8 @@ func TestGenesisContractChange(t *testing.T) {
}
func TestEncodeSigHeaderJaipur(t *testing.T) {
t.Parallel()
// 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
// block is a hard fork to fix that.

View file

@ -23,7 +23,7 @@ type EventRecordWithTime struct {
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 {
return fmt.Sprintf(
"id %v, contract %v, data: %v, txHash: %v, logIndex: %v, chainId: %v, time %s",

View file

@ -38,6 +38,7 @@ func NewGenesisContractsClient(
) *GenesisContractsClient {
vABI, _ := abi.JSON(strings.NewReader(validatorsetABI))
sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI))
return &GenesisContractsClient{
validatorSetABI: vABI,
stateReceiverABI: sABI,
@ -56,21 +57,27 @@ func (gc *GenesisContractsClient) CommitState(
) error {
eventRecord := event.BuildEventRecord()
recordBytes, err := rlp.EncodeToBytes(eventRecord)
if err != nil {
return err
}
method := "commitState"
t := event.Time.Unix()
data, err := gc.stateReceiverABI.Pack(method, big.NewInt(0).SetInt64(t), recordBytes)
if err != nil {
log.Error("Unable to pack tx for commitState", "error", err)
return err
}
log.Info("→ committing new state", "eventRecord", event.String())
msg := getSystemMessage(common.HexToAddress(gc.StateReceiverContract), data)
if err := applyMessage(msg, state, header, gc.chainConfig, chCtx); err != nil {
return err
}
return nil
}
@ -78,6 +85,7 @@ func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int,
blockNr := rpc.BlockNumber(snapshotNumber)
method := "lastStateId"
data, err := gc.stateReceiverABI.Pack(method)
if err != nil {
log.Error("Unable to pack tx for LastStateId", "error", err)
return nil, err
@ -91,6 +99,7 @@ func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int,
To: &toAddress,
Data: &msgData,
}, rpc.BlockNumberOrHash{BlockNumber: &blockNr}, nil)
if err != nil {
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 {
return nil, err
}
return *ret, nil
}

View file

@ -2,12 +2,12 @@ package bor
func appendBytes32(data ...[]byte) []byte {
var result []byte
for _, v := range data {
paddedV, err := convertTo32(v)
if err == nil {
result = append(result, paddedV[:]...)
}
paddedV := convertTo32(v)
result = append(result, paddedV[:]...)
}
return result
}
@ -24,25 +24,29 @@ func nextPowerOfTwo(n uint64) uint64 {
n |= n >> 16
n |= n >> 32
n++
return n
}
func convertTo32(input []byte) (output [32]byte, err error) {
func convertTo32(input []byte) (output [32]byte) {
l := len(input)
if l > 32 || l == 0 {
return
}
copy(output[32-l:], input[:])
return
}
func convert(input []([32]byte)) [][]byte {
var output [][]byte
output := make([][]byte, 0, len(input))
for _, in := range input {
newInput := make([]byte, len(in[:]))
copy(newInput, in[:])
output = append(output, newInput)
}
return output
}

View file

@ -40,39 +40,49 @@ func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
h := &HeimdallClient{
urlString: urlString,
client: http.Client{
Timeout: time.Duration(5 * time.Second),
Timeout: 5 * time.Second,
},
closeCh: make(chan struct{}),
}
return h, nil
}
func (h *HeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error) {
eventRecords := make([]*EventRecordWithTime, 0)
for {
queryParams := fmt.Sprintf("from-id=%d&to-time=%d&limit=%d", fromID, to, stateFetchLimit)
log.Info("Fetching state sync events", "queryParams", queryParams)
response, err := h.FetchWithRetry("clerk/event-record/list", queryParams)
if err != nil {
return nil, err
}
var _eventRecords []*EventRecordWithTime
if response.Result == nil { // status 204
break
}
if err := json.Unmarshal(response.Result, &_eventRecords); err != nil {
return nil, err
}
eventRecords = append(eventRecords, _eventRecords...)
if len(_eventRecords) < stateFetchLimit {
break
}
fromID += uint64(stateFetchLimit)
}
sort.SliceStable(eventRecords, func(i, j int) bool {
return eventRecords[i].ID < eventRecords[j].ID
})
return eventRecords, nil
}
@ -130,7 +140,7 @@ func (h *HeimdallClient) FetchWithRetry(rawPath string, rawQuery string) (*Respo
// internal fetch method
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 {
return nil, err
}

View file

@ -1,7 +1,6 @@
package bor
import (
"bytes"
"encoding/json"
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
}
// 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
// method does not initialize the set of recent signers, so only ever use if for
// the genesis block.
@ -52,6 +44,7 @@ func newSnapshot(
ValidatorSet: NewValidatorSet(validators),
Recents: make(map[uint64]common.Address),
}
return snap
}
@ -61,10 +54,13 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat
if err != nil {
return nil, err
}
snap := new(Snapshot)
if err := json.Unmarshal(blob, snap); err != nil {
return nil, err
}
snap.config = config
snap.sigcache = sigcache
snap.ethAPI = ethAPI
@ -83,6 +79,7 @@ func (s *Snapshot) store(db ethdb.Database) error {
if err != nil {
return err
}
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
}
}
if headers[0].Number.Uint64() != s.Number+1 {
return nil, errOutOfRangeChain
}
@ -126,7 +124,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
number := header.Number.Uint64()
// 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)
}
@ -153,6 +151,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
if err := validateHeaderExtraField(header.Extra); err != nil {
return nil, err
}
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
// 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.Number += uint64(len(headers))
snap.Hash = headers[len(headers)-1].Hash()
@ -173,10 +173,13 @@ func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error)
validators := s.ValidatorSet.Validators
proposer := s.ValidatorSet.GetProposer().Address
proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
if proposerIndex == -1 {
return -1, &UnauthorizedProposerError{s.Number, proposer.Bytes()}
}
signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
if signerIndex == -1 {
return -1, &UnauthorizedSignerError{s.Number, signer.Bytes()}
}
@ -187,6 +190,7 @@ func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error)
tempIndex = tempIndex + len(validators)
}
}
return tempIndex - proposerIndex, nil
}
@ -196,13 +200,14 @@ func (s *Snapshot) signers() []common.Address {
for _, sig := range s.ValidatorSet.Validators {
sigs = append(sigs, sig.Address)
}
return sigs
}
// Difficulty returns the difficulty for a particular signer at the current snapshot number
func (s *Snapshot) Difficulty(signer common.Address) uint64 {
// if signer is empty
if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 {
if signer == (common.Address{}) {
return 1
}

View file

@ -16,6 +16,8 @@ const (
)
func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
t.Parallel()
validators := buildRandomValidatorSet(numVals)
validatorSet := NewValidatorSet(validators)
snap := Snapshot{
@ -25,17 +27,22 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
// proposer is signer
signer := validatorSet.Proposer.Address
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
if err != nil {
t.Fatalf("%s", err)
}
assert.Equal(t, 0, successionNumber)
}
func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
t.Parallel()
validators := buildRandomValidatorSet(numVals)
// sort validators by address, which is what NewValidatorSet also does
sort.Sort(ValidatorsByAddress(validators))
proposerIndex := 32
signerIndex := 56
// 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
signer := snap.ValidatorSet.Validators[signerIndex].Address
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
if err != nil {
t.Fatalf("%s", err)
}
assert.Equal(t, signerIndex-proposerIndex, successionNumber)
}
func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
t.Parallel()
validators := buildRandomValidatorSet(numVals)
proposerIndex := 98
signerIndex := 11
@ -66,13 +77,17 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
// choose a signer at an index greater than proposer index
signer := snap.ValidatorSet.Validators[signerIndex].Address
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
if err != nil {
t.Fatalf("%s", err)
}
assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
}
func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
t.Parallel()
validators := buildRandomValidatorSet(numVals)
snap := Snapshot{
ValidatorSet: NewValidatorSet(validators),
@ -89,6 +104,8 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
}
func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
t.Parallel()
validators := buildRandomValidatorSet(numVals)
snap := Snapshot{
ValidatorSet: NewValidatorSet(validators),
@ -101,9 +118,12 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
assert.Equal(t, dummySignerAddress.Bytes(), e.Signer)
}
// nolint: unparam
func buildRandomValidatorSet(numVals int) []*Validator {
rand.Seed(time.Now().Unix())
validators := make([]*Validator, numVals)
for i := 0; i < numVals; i++ {
validators[i] = &Validator{
Address: randomAddress(),
@ -114,11 +134,13 @@ func buildRandomValidatorSet(numVals int) []*Validator {
// sort validators by address, which is what NewValidatorSet also does
sort.Sort(ValidatorsByAddress(validators))
return validators
}
func randomAddress() common.Address {
bytes := make([]byte, 32)
rand.Read(bytes)
return common.BytesToAddress(bytes)
}

View file

@ -43,9 +43,12 @@ func (v *Validator) Cmp(other *Validator) *Validator {
if v == nil {
return other
}
if other == nil {
return v
}
// nolint:nestif
if v.ProposerPriority > other.ProposerPriority {
return v
} else if v.ProposerPriority < other.ProposerPriority {
@ -66,6 +69,7 @@ func (v *Validator) String() string {
if v == nil {
return "nil-Validator"
}
return fmt.Sprintf("Validator{%v Power:%v Priority:%v}",
v.Address.Hex(),
v.VotingPower,
@ -87,6 +91,7 @@ func (v *Validator) HeaderBytes() []byte {
result := make([]byte, 40)
copy(result[:20], v.Address.Bytes())
copy(result[20:], v.PowerBytes())
return result
}
@ -95,6 +100,7 @@ func (v *Validator) PowerBytes() []byte {
powerBytes := big.NewInt(0).SetInt64(v.VotingPower).Bytes()
result := make([]byte, 20)
copy(result[20-len(powerBytes):], powerBytes)
return result
}
@ -114,6 +120,7 @@ func ParseValidators(validatorsBytes []byte) ([]*Validator, error) {
}
result := make([]*Validator, len(validatorsBytes)/40)
for i := 0; i < len(validatorsBytes); i += 40 {
address := make([]byte, 20)
power := make([]byte, 20)
@ -142,6 +149,7 @@ func SortMinimalValByAddress(a []MinimalVal) []MinimalVal {
sort.Slice(a, func(i, j int) bool {
return bytes.Compare(a[i].Signer.Bytes(), a[j].Signer.Bytes()) < 0
})
return a
}
@ -150,5 +158,6 @@ func ValidatorsToMinimalValidators(vals []Validator) (minVals []MinimalVal) {
for _, val := range vals {
minVals = append(minVals, val.MinimalVal())
}
return
}

View file

@ -56,12 +56,15 @@ type ValidatorSet struct {
func NewValidatorSet(valz []*Validator) *ValidatorSet {
vals := &ValidatorSet{}
err := vals.updateWithChangeSet(valz, false)
if err != nil {
panic(fmt.Sprintf("cannot create validator set: %s", err))
}
if len(valz) > 0 {
vals.IncrementProposerPriority(1)
}
return vals
}
@ -72,9 +75,10 @@ func (vals *ValidatorSet) IsNilOrEmpty() bool {
// Increment ProposerPriority and update the proposer on a copy, and return it.
func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet {
copy := vals.Copy()
copy.IncrementProposerPriority(times)
return copy
validatorCopy := vals.Copy()
validatorCopy.IncrementProposerPriority(times)
return validatorCopy
}
// IncrementProposerPriority increments ProposerPriority of each validator and updates the
@ -84,6 +88,7 @@ func (vals *ValidatorSet) IncrementProposerPriority(times int) {
if vals.IsNilOrEmpty() {
panic("empty validator set")
}
if times <= 0 {
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.
diff := computeMaxMinPriorityDiff(vals)
ratio := (diff + diffMax - 1) / diffMax
if diff > diffMax {
for _, val := range vals.Validators {
val.ProposerPriority = val.ProposerPriority / ratio
@ -145,10 +151,13 @@ func (vals *ValidatorSet) incrementProposerPriority() *Validator {
func (vals *ValidatorSet) computeAvgProposerPriority() int64 {
n := int64(len(vals.Validators))
sum := big.NewInt(0)
for _, val := range vals.Validators {
sum.Add(sum, big.NewInt(val.ProposerPriority))
}
avg := sum.Div(sum, big.NewInt(n))
if avg.IsInt64() {
return avg.Int64()
}
@ -162,17 +171,22 @@ func computeMaxMinPriorityDiff(vals *ValidatorSet) int64 {
if vals.IsNilOrEmpty() {
panic("empty validator set")
}
max := int64(math.MinInt64)
min := int64(math.MaxInt64)
for _, v := range vals.Validators {
if v.ProposerPriority < min {
min = v.ProposerPriority
}
if v.ProposerPriority > max {
max = v.ProposerPriority
}
}
diff := max - min
if diff < 0 {
return -1 * diff
} else {
@ -185,6 +199,7 @@ func (vals *ValidatorSet) getValWithMostPriority() *Validator {
for _, val := range vals.Validators {
res = res.Cmp(val)
}
return res
}
@ -192,7 +207,9 @@ func (vals *ValidatorSet) shiftByAvgProposerPriority() {
if vals.IsNilOrEmpty() {
panic("empty validator set")
}
avgProposerPriority := vals.computeAvgProposerPriority()
for _, val := range vals.Validators {
val.ProposerPriority = safeSubClip(val.ProposerPriority, avgProposerPriority)
}
@ -203,10 +220,13 @@ func validatorListCopy(valsList []*Validator) []*Validator {
if valsList == nil {
return nil
}
valsCopy := make([]*Validator, len(valsList))
for i, val := range valsList {
valsCopy[i] = val.Copy()
}
return valsCopy
}
@ -225,6 +245,7 @@ func (vals *ValidatorSet) HasAddress(address []byte) bool {
idx := sort.Search(len(vals.Validators), func(i int) bool {
return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0
})
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 {
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 -1, nil
}
@ -247,7 +269,9 @@ func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator)
if index < 0 || index >= len(vals.Validators) {
return nil, nil
}
val = vals.Validators[index]
return val.Address.Bytes(), val.Copy()
}
@ -258,7 +282,6 @@ func (vals *ValidatorSet) Size() int {
// Force recalculation of the set's total voting power.
func (vals *ValidatorSet) updateTotalVotingPower() error {
sum := int64(0)
for _, val := range vals.Validators {
// mind overflow
@ -267,7 +290,9 @@ func (vals *ValidatorSet) updateTotalVotingPower() error {
return &TotalVotingPowerExceededError{sum, vals.Validators}
}
}
vals.totalVotingPower = sum
return nil
}
@ -276,11 +301,13 @@ func (vals *ValidatorSet) updateTotalVotingPower() error {
func (vals *ValidatorSet) TotalVotingPower() int64 {
if vals.totalVotingPower == 0 {
log.Info("invoking updateTotalVotingPower before returning it")
if err := vals.updateTotalVotingPower(); err != nil {
// Can/should we do better?
panic(err)
}
}
return vals.totalVotingPower
}
@ -290,9 +317,11 @@ func (vals *ValidatorSet) GetProposer() (proposer *Validator) {
if len(vals.Validators) == 0 {
return nil
}
if vals.Proposer == nil {
vals.Proposer = vals.findProposer()
}
return vals.Proposer.Copy()
}
@ -303,6 +332,7 @@ func (vals *ValidatorSet) findProposer() *Validator {
proposer = proposer.Cmp(val)
}
}
return proposer
}
@ -343,6 +373,7 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
removals = make([]*Validator, 0, len(changes))
updates = make([]*Validator, 0, len(changes))
var prevAddr common.Address
// 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)
return nil, nil, err
}
if valUpdate.VotingPower < 0 {
err = fmt.Errorf("voting power can't be negative: %v", valUpdate)
return nil, nil, err
}
if valUpdate.VotingPower > MaxTotalVotingPower {
err = fmt.Errorf("to prevent clipping/ overflow, voting power can't be higher than %v: %v ",
MaxTotalVotingPower, valUpdate)
return nil, nil, err
}
if valUpdate.VotingPower == 0 {
removals = append(removals, valUpdate)
} else {
updates = append(updates, valUpdate)
}
prevAddr = valUpdate.Address
}
return updates, removals, err
}
@ -382,12 +418,12 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
// by processChanges for duplicates and invalid values.
// No changes are made to the validator set 'vals'.
func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVotingPower int64, numNewValidators int, err error) {
updatedTotalVotingPower = vals.TotalVotingPower()
for _, valUpdate := range updates {
address := valUpdate.Address
_, val := vals.GetByAddress(address)
if val == nil {
// New validator, add its voting power the the total.
updatedTotalVotingPower += valUpdate.VotingPower
@ -396,11 +432,14 @@ func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVoting
// Updated validator, add the difference in power to the total.
updatedTotalVotingPower += valUpdate.VotingPower - val.VotingPower
}
overflow := updatedTotalVotingPower > MaxTotalVotingPower
if overflow {
err = fmt.Errorf(
"failed to add/update validator %v, total voting power would exceed the max allowed %v",
valUpdate, MaxTotalVotingPower)
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.
// No changes are made to the validator set 'vals'.
func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotalVotingPower int64) {
for _, valUpdate := range updates {
address := valUpdate.Address
_, val := vals.GetByAddress(address)
if val == nil {
// add val
// 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
}
}
}
// 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,
// must have been validated with verifyUpdates() and priorities computed with computeNewPriorities().
func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
existing := vals.Validators
merged := make([]*Validator, len(existing)+len(updates))
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.
// No changes are made to the validator set 'vals'.
func verifyRemovals(deletes []*Validator, vals *ValidatorSet) error {
for _, valUpdate := range deletes {
address := valUpdate.Address
_, val := vals.GetByAddress(address)
if val == nil {
return fmt.Errorf("failed to find validator %X to remove", address)
}
}
if len(deletes) > len(vals.Validators) {
panic("more deletes than validators")
}
return nil
}
// Removes the validators specified in 'deletes' from validator set 'vals'.
// Should not fail as verification has been done before.
func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
existing := vals.Validators
merged := make([]*Validator, len(existing)-len(deletes))
@ -509,6 +547,7 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
merged[i] = existing[0]
i++
}
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'.
// The 'allowDeletes' flag is set to false by NewValidatorSet() and to true by UpdateWithChangeSet().
func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes bool) error {
if len(changes) <= 0 {
return nil
}
@ -596,19 +634,19 @@ func (vals *ValidatorSet) UpdateWithChangeSet(changes []*Validator) error {
func IsErrTooMuchChange(err error) bool {
switch err.(type) {
case errTooMuchChange:
case tooMuchChangeError:
return true
default:
return false
}
}
type errTooMuchChange struct {
type tooMuchChangeError struct {
got 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)
}
@ -622,11 +660,14 @@ func (vals *ValidatorSet) StringIndented(indent string) string {
if vals == nil {
return "nil-ValidatorSet"
}
var valStrings []string
vals.Iterate(func(index int, val *Validator) bool {
valStrings = append(valStrings, val.String())
return false
})
return fmt.Sprintf(`ValidatorSet{
%s Proposer: %v
%s Validators:
@ -636,7 +677,6 @@ func (vals *ValidatorSet) StringIndented(indent string) string {
indent,
indent, strings.Join(valStrings, "\n"+indent+" "),
indent)
}
//-------------------------------------
@ -668,6 +708,7 @@ func safeAdd(a, b int64) (int64, bool) {
} else if b < 0 && a < math.MinInt64-b {
return -1, true
}
return a + b, false
}
@ -677,6 +718,7 @@ func safeSub(a, b int64) (int64, bool) {
} else if b < 0 && a > math.MaxInt64+b {
return -1, true
}
return a - b, false
}
@ -686,8 +728,10 @@ func safeAddClip(a, b int64) int64 {
if b < 0 {
return math.MinInt64
}
return math.MaxInt64
}
return c
}
@ -697,7 +741,9 @@ func safeSubClip(a, b int64) int64 {
if b > 0 {
return math.MinInt64
}
return math.MaxInt64
}
return c
}

View file

@ -19,6 +19,7 @@ func (a *Account) MarkDown() string {
"- [```account list```](./account_list.md): List the wallets in the Bor client.",
"- [```account import```](./account_import.md): Import an account to the Bor client.",
}
return strings.Join(items, "\n\n")
}

View file

@ -20,6 +20,7 @@ func (a *AccountImportCommand) MarkDown() string {
"The ```account import``` command imports an account in Json format to the Bor data directory.",
a.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}
@ -58,7 +59,9 @@ func (a *AccountImportCommand) Run(args []string) int {
a.UI.Error("Expected one argument")
return 1
}
key, err := crypto.LoadECDSA(args[0])
if err != nil {
a.UI.Error(fmt.Sprintf("Failed to load the private key '%s': %v", args[0], err))
return 1
@ -80,6 +83,8 @@ func (a *AccountImportCommand) Run(args []string) int {
if err != nil {
utils.Fatalf("Could not create the account: %v", err)
}
a.UI.Output(fmt.Sprintf("Account created: %s", acct.Address.String()))
return 0
}

View file

@ -19,6 +19,7 @@ func (a *AccountListCommand) MarkDown() string {
"The `account list` command lists all the accounts in the Bor data directory.",
a.Flags().MarkDown(),
}
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))
return 1
}
a.UI.Output(formatAccounts(keystore.Accounts()))
return 0
}
@ -64,10 +67,12 @@ func formatAccounts(accts []accounts.Account) string {
rows := make([]string, len(accts)+1)
rows[0] = "Index|Address"
for i, d := range accts {
rows[i+1] = fmt.Sprintf("%d|%s",
i,
d.Address.String())
}
return formatList(rows)
}

View file

@ -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.",
a.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}

View file

@ -6,12 +6,12 @@ import (
"path/filepath"
"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/console"
"github.com/ethereum/go-ethereum/internal/cli/flagset"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/mitchellh/cli"
)
@ -33,6 +33,7 @@ func (c *AttachCommand) MarkDown() string {
"Connect to remote Bor IPC console.",
c.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}
@ -49,7 +50,6 @@ func (c *AttachCommand) Synopsis() string {
}
func (c *AttachCommand) Flags() *flagset.Flagset {
f := flagset.NewFlagSet("attach")
f.StringFlag(&flagset.StringFlag{
@ -75,13 +75,13 @@ func (c *AttachCommand) Flags() *flagset.Flagset {
// Run implements the cli.Command interface
func (c *AttachCommand) Run(args []string) int {
flags := c.Flags()
//check if first arg is flag or IPC location
if len(args) == 0 {
args = append(args, "")
}
if args[0] != "" && strings.HasPrefix(args[0], "--") {
if err := flags.Parse(args); err != nil {
c.UI.Error(err.Error())
@ -94,6 +94,7 @@ func (c *AttachCommand) Run(args []string) int {
return 1
}
}
if err := c.remoteConsole(); err != nil {
c.UI.Error(err.Error())
return 1
@ -104,25 +105,30 @@ func (c *AttachCommand) Run(args []string) int {
// remoteConsole will connect to a remote bor instance, attaching a JavaScript
// console to it.
// nolint: unparam
func (c *AttachCommand) remoteConsole() error {
// Attach to a remotely running geth instance and start the JavaScript console
path := node.DefaultDataDir()
if c.Endpoint == "" {
if c.Meta.dataDir != "" {
path = c.Meta.dataDir
}
if path != "" {
homeDir, _ := os.UserHomeDir()
path = filepath.Join(homeDir, "/.bor/data")
}
c.Endpoint = fmt.Sprintf("%s/bor.ipc", path)
}
client, err := dialRPC(c.Endpoint)
if err != nil {
utils.Fatalf("Unable to attach to remote bor: %v", err)
}
config := console.Config{
DataDir: path,
DocRoot: c.JSpathFlag,
@ -134,7 +140,12 @@ func (c *AttachCommand) remoteConsole() error {
if err != nil {
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 != "" {
console.Evaluate(c.ExecCMD)
@ -159,6 +170,7 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
// these prefixes.
endpoint = endpoint[4:]
}
return rpc.Dial(endpoint)
}
@ -170,10 +182,12 @@ func (c *AttachCommand) makeConsolePreloads() []string {
return nil
}
// 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))
}
return preloads
}

View file

@ -19,6 +19,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/mitchellh/cli"
)
@ -45,6 +46,7 @@ func (c *BootnodeCommand) MarkDown() string {
"# Bootnode",
c.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}
@ -103,6 +105,7 @@ func (b *BootnodeCommand) Synopsis() string {
}
// Run implements the cli.Command interface
// nolint: gocognit
func (b *BootnodeCommand) Run(args []string) int {
flags := b.Flags()
if err := flags.Parse(args); err != nil {
@ -118,6 +121,7 @@ func (b *BootnodeCommand) Run(args []string) int {
} else {
glogger.Verbosity(log.LvlInfo)
}
log.Root().SetHandler(glogger)
natm, err := nat.Parse(b.nat)
@ -128,6 +132,7 @@ func (b *BootnodeCommand) Run(args []string) int {
// create a one time key
var nodeKey *ecdsa.PrivateKey
// nolint: nestif
if b.nodeKey != "" {
// try to read the key either from file or command line
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
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))
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))
return 1
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
b.UI.Error(fmt.Sprintf("failed to listen udp addr '%s': %v", b.listenAddr, err))
return 1
@ -180,7 +187,9 @@ func (b *BootnodeCommand) Run(args []string) int {
if !realaddr.IP.IsLoopback() {
go nat.Map(natm, nil, "udp", realaddr.Port, realaddr.Port, "ethereum discovery")
}
if ext, err := natm.ExternalIP(); err == nil {
// nolint: govet
realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}
}
}
@ -198,6 +207,7 @@ func (b *BootnodeCommand) Run(args []string) int {
PrivateKey: nodeKey,
Log: log.Root(),
}
if b.v5 {
if _, err := discover.ListenV5(conn, ln, cfg); err != nil {
utils.Fatalf("%v", err)

View file

@ -7,6 +7,7 @@ import (
"strings"
"github.com/ethereum/go-ethereum/params"
"github.com/mitchellh/cli"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
@ -25,6 +26,7 @@ func (c *FingerprintCommand) MarkDown() string {
"# Fingerprint",
"Display the system fingerprint",
}
return strings.Join(items, "\n\n")
}
@ -45,6 +47,7 @@ func getCoresCount(cp []cpu.InfoStat) int {
for i := 0; i < len(cp); i++ {
cores += int(cp[i].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("STORAGE :: total : %v GB, free : %v GB, used : %v GB", borFingerprint.DiskDetails.TotalDisk, borFingerprint.DiskDetails.FreeDisk, borFingerprint.DiskDetails.UsedDisk),
})
return base
}
@ -85,13 +89,13 @@ func convertBytesToGB(bytesValue uint64) float64 {
// Checks if fio exists on the node
func (c *FingerprintCommand) checkFio() error {
cmd := exec.Command("/bin/sh", "-c", "fio -v")
_, err := cmd.CombinedOutput()
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"
c.UI.Output(message)
return err
}
@ -101,9 +105,12 @@ func (c *FingerprintCommand) checkFio() error {
// Run the IOPS benchmark for the node
func (c *FingerprintCommand) benchmark() error {
var b []byte
err := c.checkFio()
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")
@ -123,7 +130,6 @@ func (c *FingerprintCommand) benchmark() error {
// Run implements the cli.Command interface
func (c *FingerprintCommand) Run(args []string) int {
v, err := mem.VirtualMemory()
if err != nil {
c.UI.Error(err.Error())

View file

@ -19,6 +19,7 @@ func (c *ChainCommand) MarkDown() string {
"- [```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.",
}
return strings.Join(items, "\n\n")
}

View file

@ -26,6 +26,7 @@ func (a *ChainSetHeadCommand) MarkDown() string {
"- ```number```: The block number to roll back.",
a.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}
@ -45,6 +46,7 @@ func (c *ChainSetHeadCommand) Flags() *flagset.Flagset {
Default: false,
Value: &c.yes,
})
return flags
}
@ -88,6 +90,7 @@ func (c *ChainSetHeadCommand) Run(args []string) int {
c.UI.Error(err.Error())
return 1
}
if response != "y" {
c.UI.Output("set head aborted")
return 0
@ -100,5 +103,6 @@ func (c *ChainSetHeadCommand) Run(args []string) int {
}
c.UI.Output("Done!")
return 0
}

View file

@ -24,6 +24,7 @@ func (c *ChainWatchCommand) MarkDown() string {
"# Chain watch",
"The ```chain watch``` command is used to view the chainHead, reorg and fork events in real-time.",
}
return strings.Join(items, "\n\n")
}
@ -70,7 +71,10 @@ func (c *ChainWatchCommand) Run(args []string) int {
go func() {
<-signalCh
sub.CloseSend()
if err := sub.CloseSend(); err != nil {
c.UI.Error(err.Error())
}
}()
for {
@ -80,6 +84,7 @@ func (c *ChainWatchCommand) Run(args []string) int {
c.UI.Output(err.Error())
break
}
c.UI.Output(formatHeadEvent(msg))
}
@ -95,5 +100,6 @@ func formatHeadEvent(msg *proto.ChainWatchResponse) string {
} else if msg.Type == core.Chain2HeadReorgEvent {
out = fmt.Sprintf("Reorg Detected \nAdded : %v \nRemoved : %v", msg.Newchain, msg.Oldchain)
}
return out
}

View file

@ -9,11 +9,16 @@ import (
"github.com/ethereum/go-ethereum/internal/cli/server"
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
"github.com/ethereum/go-ethereum/node"
"github.com/mitchellh/cli"
"github.com/ryanuber/columnize"
"google.golang.org/grpc"
)
const (
emptyPlaceHolder = "<none>"
)
type MarkDownCommand interface {
MarkDown
cli.Command
@ -48,6 +53,7 @@ func Run(args []string) int {
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
return 1
}
return exitCode
}
@ -64,6 +70,7 @@ func Commands() map[string]MarkDownCommandFactory {
meta := &Meta{
UI: ui,
}
return map[string]MarkDownCommandFactory{
"server": func() (MarkDownCommand, error) {
return &server.Command{
@ -180,6 +187,7 @@ func (m *Meta2) NewFlagSet(n string) *flagset.Flagset {
Usage: "Address of the grpc endpoint",
Default: "127.0.0.1:3131",
})
return f
}
@ -188,6 +196,7 @@ func (m *Meta2) Conn() (*grpc.ClientConn, error) {
if err != nil {
return nil, fmt.Errorf("failed to connect to server: %v", err)
}
return conn, nil
}
@ -196,6 +205,7 @@ func (m *Meta2) BorConn() (proto.BorClient, error) {
if err != nil {
return nil, err
}
return proto.NewBorClient(conn), nil
}
@ -243,18 +253,21 @@ func (m *Meta) GetKeystore() (*keystore.KeyStore, error) {
scryptP := keystore.StandardScryptP
keys := keystore.NewKeyStore(keydir, scryptN, scryptP)
return keys, nil
}
func formatList(in []string) string {
columnConf := columnize.DefaultConfig()
columnConf.Empty = "<none>"
columnConf.Empty = emptyPlaceHolder
return columnize.Format(in, columnConf)
}
func formatKV(in []string) string {
columnConf := columnize.DefaultConfig()
columnConf.Empty = "<none>"
columnConf.Empty = emptyPlaceHolder
columnConf.Glue = " = "
return columnize.Format(in, columnConf)
}

View file

@ -18,8 +18,9 @@ import (
"github.com/ethereum/go-ethereum/internal/cli/flagset"
"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"
grpc_net_conn "github.com/mitchellh/go-grpc-net-conn"
)
@ -55,6 +56,7 @@ func (d *DebugCommand) MarkDown() string {
d.Flags().MarkDown(),
}
items = append(items, examples...)
return strings.Join(items, "\n\n")
}
@ -112,6 +114,7 @@ func (d *DebugCommand) Run(args []string) int {
// User specified output directory
tmp = filepath.Join(d.output, stamped)
_, err := os.Stat(tmp)
if !os.IsNotExist(err) {
d.UI.Error("Output directory already exists")
return 1
@ -139,6 +142,7 @@ func (d *DebugCommand) Run(args []string) int {
req := &proto.PprofRequest{
Seconds: int64(d.seconds),
}
switch profile {
case "cpu":
req.Type = proto.PprofRequest_CPU
@ -148,7 +152,9 @@ func (d *DebugCommand) Run(args []string) int {
req.Type = proto.PprofRequest_LOOKUP
req.Profile = profile
}
stream, err := clt.Pprof(ctx, req)
if err != nil {
return err
}
@ -157,6 +163,7 @@ func (d *DebugCommand) Run(args []string) int {
if err != nil {
return err
}
if _, ok := msg.Event.(*proto.PprofResponse_Open_); !ok {
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 {
return err
}
return nil
}
@ -210,7 +218,7 @@ func (d *DebugCommand) Run(args []string) int {
d.UI.Output(err.Error())
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))
return 1
}
@ -230,6 +238,7 @@ func (d *DebugCommand) Run(args []string) int {
}
d.UI.Output(fmt.Sprintf("Created debug archive: %s", archiveFile))
return 0
}

View file

@ -7,6 +7,7 @@ import (
)
func TestCodeBlock(t *testing.T) {
t.Parallel()
assert := assert.New(t)
lines := []string{

View file

@ -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 status```](./peers_status.md): Display the status of a peer by its id.",
}
return strings.Join(items, "\n\n")
}

View file

@ -22,6 +22,7 @@ func (p *PeersAddCommand) MarkDown() string {
"The ```peers add <enode>``` command joins the local client to another remote peer.",
p.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}
@ -79,5 +80,6 @@ func (c *PeersAddCommand) Run(args []string) int {
c.UI.Error(err.Error())
return 1
}
return 0
}

View file

@ -21,6 +21,7 @@ func (p *PeersListCommand) MarkDown() string {
"The ```peers list``` command lists the connected peers.",
p.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}
@ -60,12 +61,14 @@ func (c *PeersListCommand) Run(args []string) int {
req := &proto.PeersListRequest{}
resp, err := borClt.PeersList(context.Background(), req)
if err != nil {
c.UI.Error(err.Error())
return 1
}
c.UI.Output(formatPeers(resp.Peers))
return 0
}
@ -76,6 +79,7 @@ func formatPeers(peers []*proto.Peer) string {
rows := make([]string, len(peers)+1)
rows[0] = "ID|Enode|Name|Caps|Static|Trusted"
for i, d := range peers {
enode := strings.TrimPrefix(d.Enode, "enode://")
@ -87,5 +91,6 @@ func formatPeers(peers []*proto.Peer) string {
d.Static,
d.Trusted)
}
return formatList(rows)
}

View file

@ -22,6 +22,7 @@ func (p *PeersRemoveCommand) MarkDown() string {
"The ```peers remove <enode>``` command disconnects the local client from a connected peer if exists.",
p.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}
@ -79,5 +80,6 @@ func (c *PeersRemoveCommand) Run(args []string) int {
c.UI.Error(err.Error())
return 1
}
return 0
}

View file

@ -21,6 +21,7 @@ func (p *PeersStatusCommand) MarkDown() string {
"The ```peers status <peer id>``` command displays the status of a peer by its id.",
p.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}
@ -68,12 +69,14 @@ func (c *PeersStatusCommand) Run(args []string) int {
Enode: args[0],
}
resp, err := borClt.PeersStatus(context.Background(), req)
if err != nil {
c.UI.Error(err.Error())
return 1
}
c.UI.Output(formatPeer(resp.Peer))
return 0
}
@ -87,5 +90,6 @@ func formatPeer(peer *proto.Peer) string {
fmt.Sprintf("Static|%v", peer.Static),
fmt.Sprintf("Trusted|%v", peer.Trusted),
})
return base
}

View file

@ -6,6 +6,7 @@ import (
"strings"
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
"github.com/golang/protobuf/ptypes/empty"
)
@ -20,6 +21,7 @@ func (p *StatusCommand) MarkDown() string {
"# Status",
"The ```status``` command outputs the status of the client.",
}
return strings.Join(items, "\n\n")
}
@ -56,6 +58,7 @@ func (c *StatusCommand) Run(args []string) int {
}
c.UI.Output(printStatus(status))
return 0
}
@ -69,6 +72,7 @@ func printStatus(status *proto.StatusResponse) string {
forks := make([]string, len(status.Forks)+1)
forks[0] = "Name|Block|Enabled"
for i, d := range status.Forks {
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",
formatList(forks),
}
return strings.Join(full, "\n")
}

View file

@ -4,6 +4,7 @@ import (
"strings"
"github.com/ethereum/go-ethereum/params"
"github.com/mitchellh/cli"
)
@ -27,6 +28,7 @@ func (d *VersionCommand) MarkDown() string {
"The ```bor version``` command outputs the version of the binary.",
}
items = append(items, examples...)
return strings.Join(items, "\n\n")
}