mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 22:26:42 +00:00
Prepare Bor package for testing (#416)
* Limit state sync by gas * Added logging for state-sync total gas usage * Added number of event-records in log * Minor Changes * Minor Fix * Adding individual gasUsed * Minor Fix * it works * fix tests * log wiggle and delay with block number * log delays as numbers * linters * fix tests * restore linters for the project * fix linters * fix * fix * fix * linters * generation * fix tests * remove heimdall wrapper response * linters * remove possible collisions * remove possible collisions * remove possible collisions * tests for unique address generation * generalize set * bor miner tests got restored * fixes after CR * final step and mining test * fix * fix e2e * more tests for Heimdall requests * fix linters Co-authored-by: Ferran <ferranbt@protonmail.com> Co-authored-by: Shivam Sharma <shivam691999@gmail.com>
This commit is contained in:
parent
8808c231df
commit
9c8bf51f57
68 changed files with 2517 additions and 1181 deletions
|
|
@ -1,6 +1,7 @@
|
|||
# This file configures github.com/golangci/golangci-lint.
|
||||
|
||||
run:
|
||||
go: '1.18'
|
||||
timeout: 20m
|
||||
tests: true
|
||||
# default is true. Enables skipping of directories:
|
||||
|
|
@ -183,4 +184,4 @@ issues:
|
|||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
#new: true
|
||||
# new-from-rev: origin/master
|
||||
new-from-rev: origin/master
|
||||
20
Makefile
20
Makefile
|
|
@ -65,9 +65,7 @@ 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 \
|
||||
internal/cli \
|
||||
consensus/bor
|
||||
@./build/bin/golangci-lint run --config ./.golangci.yml
|
||||
|
||||
lintci-deps:
|
||||
rm -f ./build/bin/golangci-lint
|
||||
|
|
@ -87,16 +85,20 @@ clean:
|
|||
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
||||
|
||||
devtools:
|
||||
env GOBIN= go install golang.org/x/tools/cmd/stringer@latest
|
||||
env GOBIN= go install github.com/kevinburke/go-bindata/go-bindata@latest
|
||||
env GOBIN= go install github.com/fjl/gencodec@latest
|
||||
env GOBIN= go install github.com/golang/protobuf/protoc-gen-go@latest
|
||||
env GOBIN= go install ./cmd/abigen
|
||||
# Notice! If you adding new binary - add it also to tests/deps/fake.go file
|
||||
$(GOBUILD) -o $(GOBIN)/stringer github.com/golang.org/x/tools/cmd/stringer
|
||||
$(GOBUILD) -o $(GOBIN)/go-bindata github.com/kevinburke/go-bindata/go-bindata
|
||||
$(GOBUILD) -o $(GOBIN)/codecgen github.com/ugorji/go/codec/codecgen
|
||||
$(GOBUILD) -o $(GOBIN)/abigen ./cmd/abigen
|
||||
$(GOBUILD) -o $(GOBIN)/mockgen github.com/golang/mock/mockgen
|
||||
$(GOBUILD) -o $(GOBIN)/protoc-gen-go github.com/golang/protobuf/protoc-gen-go
|
||||
PATH=$(GOBIN):$(PATH) go generate ./common
|
||||
PATH=$(GOBIN):$(PATH) go generate ./core/types
|
||||
PATH=$(GOBIN):$(PATH) go generate ./consensus/bor
|
||||
@type "solc" 2> /dev/null || echo 'Please install solc'
|
||||
@type "protoc" 2> /dev/null || echo 'Please install protoc'
|
||||
|
||||
# Cross Compilation Targets (xgo)
|
||||
|
||||
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
|
||||
@echo "Full cross compilation done:"
|
||||
@ls -ld $(GOBIN)/geth-*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ const (
|
|||
)
|
||||
|
||||
func main() {
|
||||
|
||||
commands := cli.Commands()
|
||||
|
||||
dest := flag.String("d", DefaultDir, "Destination directory where the docs will be generated")
|
||||
|
|
@ -35,10 +34,12 @@ func main() {
|
|||
|
||||
keys := make([]string, len(commands))
|
||||
i := 0
|
||||
|
||||
for k := range commands {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, name := range keys {
|
||||
|
|
@ -60,12 +61,17 @@ func main() {
|
|||
|
||||
func overwriteFile(filePath string, text string) {
|
||||
log.Printf("Writing to page: %s\n", filePath)
|
||||
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
f.WriteString(text)
|
||||
if err := f.Close(); err != nil {
|
||||
|
||||
if _, err = f.WriteString(text); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
if err = f.Close(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
28
common/debug/debug.go
Normal file
28
common/debug/debug.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package debug
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Callers returns given number of callers with packages
|
||||
func Callers(show int) []string {
|
||||
fpcs := make([]uintptr, show)
|
||||
|
||||
n := runtime.Callers(2, fpcs)
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
callers := make([]string, 0, len(fpcs))
|
||||
|
||||
for _, p := range fpcs {
|
||||
caller := runtime.FuncForPC(p - 1)
|
||||
if caller == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
callers = append(callers, caller.Name())
|
||||
}
|
||||
|
||||
return callers
|
||||
}
|
||||
11
common/set/slice.go
Normal file
11
common/set/slice.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package set
|
||||
|
||||
func New[T comparable](slice []T) map[T]struct{} {
|
||||
m := make(map[T]struct{}, len(slice))
|
||||
|
||||
for _, el := range slice {
|
||||
m[el] = struct{}{}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
6
consensus/bor/abi/interface.go
Normal file
6
consensus/bor/abi/interface.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package abi
|
||||
|
||||
type ABI interface {
|
||||
Pack(name string, args ...interface{}) ([]byte, error)
|
||||
UnpackIntoInterface(v interface{}, name string, data []byte) error
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
|
@ -206,10 +207,10 @@ func (api *API) GetCurrentProposer() (common.Address, error) {
|
|||
}
|
||||
|
||||
// GetCurrentValidators gets the current validators
|
||||
func (api *API) GetCurrentValidators() ([]*Validator, error) {
|
||||
func (api *API) GetCurrentValidators() ([]*valset.Validator, error) {
|
||||
snap, err := api.GetSnapshot(nil)
|
||||
if err != nil {
|
||||
return make([]*Validator, 0), err
|
||||
return make([]*valset.Validator, 0), err
|
||||
}
|
||||
|
||||
return snap.ValidatorSet.Validators, nil
|
||||
|
|
@ -236,7 +237,7 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
|||
currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
|
||||
|
||||
if start > end || end > currentHeaderNumber {
|
||||
return "", &InvalidStartEndBlockError{start, end, currentHeaderNumber}
|
||||
return "", &valset.InvalidStartEndBlockError{Start: start, End: end, CurrentHeader: currentHeaderNumber}
|
||||
}
|
||||
|
||||
blockHeaders := make([]*types.Header, end-start+1)
|
||||
|
|
|
|||
14
consensus/bor/api/caller.go
Normal file
14
consensus/bor/api/caller.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=./caller_mock.go -package=api . Caller
|
||||
type Caller interface {
|
||||
Call(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *ethapi.StateOverride) (hexutil.Bytes, error)
|
||||
}
|
||||
53
consensus/bor/api/caller_mock.go
Normal file
53
consensus/bor/api/caller_mock.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/ethereum/go-ethereum/consensus/bor/api (interfaces: Caller)
|
||||
|
||||
// Package api is a generated GoMock package.
|
||||
package api
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
hexutil "github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethapi "github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
rpc "github.com/ethereum/go-ethereum/rpc"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockCaller is a mock of Caller interface.
|
||||
type MockCaller struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCallerMockRecorder
|
||||
}
|
||||
|
||||
// MockCallerMockRecorder is the mock recorder for MockCaller.
|
||||
type MockCallerMockRecorder struct {
|
||||
mock *MockCaller
|
||||
}
|
||||
|
||||
// NewMockCaller creates a new mock instance.
|
||||
func NewMockCaller(ctrl *gomock.Controller) *MockCaller {
|
||||
mock := &MockCaller{ctrl: ctrl}
|
||||
mock.recorder = &MockCallerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockCaller) EXPECT() *MockCallerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Call mocks base method.
|
||||
func (m *MockCaller) Call(arg0 context.Context, arg1 ethapi.TransactionArgs, arg2 rpc.BlockNumberOrHash, arg3 *ethapi.StateOverride) (hexutil.Bytes, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Call", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(hexutil.Bytes)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Call indicates an expected call of Call.
|
||||
func (mr *MockCallerMockRecorder) Call(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockCaller)(nil).Call), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
|
@ -2,37 +2,34 @@ package bor
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/api"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/statefull"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
|
@ -56,7 +53,6 @@ var (
|
|||
uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
|
||||
|
||||
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
|
||||
systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE")
|
||||
)
|
||||
|
||||
// Various error messages to mark blocks invalid. These should be private to
|
||||
|
|
@ -100,9 +96,6 @@ var (
|
|||
// errOutOfRangeChain is returned if an authorization list is attempted to
|
||||
// be modified via out-of-range or non-contiguous headers.
|
||||
errOutOfRangeChain = errors.New("out of range or non-contiguous chain")
|
||||
|
||||
// errShutdownDetected is returned if a shutdown was detected
|
||||
errShutdownDetected = errors.New("shutdown detected")
|
||||
)
|
||||
|
||||
// SignerFn is a signer callback function to request a header to be signed by a
|
||||
|
|
@ -220,24 +213,25 @@ type Bor struct {
|
|||
signFn SignerFn // Signer function to authorize hashes with
|
||||
lock sync.RWMutex // Protects the signer fields
|
||||
|
||||
ethAPI *ethapi.PublicBlockChainAPI
|
||||
GenesisContractsClient *GenesisContractsClient
|
||||
validatorSetABI abi.ABI
|
||||
stateReceiverABI abi.ABI
|
||||
ethAPI api.Caller
|
||||
spanner Spanner
|
||||
GenesisContractsClient GenesisContract
|
||||
HeimdallClient IHeimdallClient
|
||||
WithoutHeimdall bool
|
||||
|
||||
// The fields below are for testing only
|
||||
fakeDiff bool // Skip difficulty verifications
|
||||
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// New creates a Matic Bor consensus engine.
|
||||
func New(
|
||||
chainConfig *params.ChainConfig,
|
||||
db ethdb.Database,
|
||||
ethAPI *ethapi.PublicBlockChainAPI,
|
||||
heimdallURL string,
|
||||
withoutHeimdall bool,
|
||||
ethAPI api.Caller,
|
||||
spanner Spanner,
|
||||
heimdallClient IHeimdallClient,
|
||||
genesisContracts GenesisContract,
|
||||
) *Bor {
|
||||
// get bor config
|
||||
borConfig := chainConfig.Bor
|
||||
|
|
@ -246,14 +240,10 @@ func New(
|
|||
if borConfig != nil && borConfig.Sprint == 0 {
|
||||
borConfig.Sprint = defaultSprintLength
|
||||
}
|
||||
|
||||
// Allocate the snapshot caches and create the engine
|
||||
recents, _ := lru.NewARC(inmemorySnapshots)
|
||||
signatures, _ := lru.NewARC(inmemorySignatures)
|
||||
vABI, _ := abi.JSON(strings.NewReader(validatorsetABI))
|
||||
sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI))
|
||||
heimdallClient, _ := NewHeimdallClient(heimdallURL)
|
||||
genesisContractsClient := NewGenesisContractsClient(chainConfig, borConfig.ValidatorContract, borConfig.StateReceiverContract, ethAPI)
|
||||
|
||||
c := &Bor{
|
||||
chainConfig: chainConfig,
|
||||
config: borConfig,
|
||||
|
|
@ -261,11 +251,9 @@ func New(
|
|||
ethAPI: ethAPI,
|
||||
recents: recents,
|
||||
signatures: signatures,
|
||||
validatorSetABI: vABI,
|
||||
stateReceiverABI: sABI,
|
||||
GenesisContractsClient: genesisContractsClient,
|
||||
spanner: spanner,
|
||||
GenesisContractsClient: genesisContracts,
|
||||
HeimdallClient: heimdallClient,
|
||||
WithoutHeimdall: withoutHeimdall,
|
||||
}
|
||||
|
||||
// make sure we can decode all the GenesisAlloc in the BorConfig.
|
||||
|
|
@ -332,7 +320,7 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
|
|||
}
|
||||
|
||||
// check extr adata
|
||||
isSprintEnd := (number+1)%c.config.Sprint == 0
|
||||
isSprintEnd := IsSprintStart(number+1, c.config.Sprint)
|
||||
|
||||
// Ensure that the extra-data contains a signer list on checkpoint, but none otherwise
|
||||
signersBytes := len(header.Extra) - extraVanity - extraSeal
|
||||
|
|
@ -441,19 +429,18 @@ 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
|
||||
}
|
||||
|
||||
// verify the validator list in the last sprint block
|
||||
if isSprintStart(number, c.config.Sprint) {
|
||||
if IsSprintStart(number, c.config.Sprint) {
|
||||
parentValidatorBytes := parent.Extra[extraVanity : len(parent.Extra)-extraSeal]
|
||||
validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength)
|
||||
|
||||
currentValidators := snap.ValidatorSet.Copy().Validators
|
||||
// sort validator by address
|
||||
sort.Sort(ValidatorsByAddress(currentValidators))
|
||||
sort.Sort(valset.ValidatorsByAddress(currentValidators))
|
||||
|
||||
for i, validator := range currentValidators {
|
||||
copy(validatorsBytes[i*validatorHeaderBytesLength:], validator.HeaderBytes())
|
||||
|
|
@ -487,7 +474,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
|||
|
||||
// If an on-disk checkpoint snapshot can be found, use that
|
||||
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); err == nil {
|
||||
log.Trace("Loaded snapshot from disk", "number", number, "hash", hash)
|
||||
|
||||
snap = s
|
||||
|
|
@ -509,13 +496,13 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
|||
hash := checkpoint.Hash()
|
||||
|
||||
// get validators and current span
|
||||
validators, err := c.GetCurrentValidators(hash, number+1)
|
||||
validators, err := c.spanner.GetCurrentValidators(hash, number+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// new snap shot
|
||||
snap = newSnapshot(c.config, c.signatures, number, hash, validators, c.ethAPI)
|
||||
snap = newSnapshot(c.config, c.signatures, number, hash, validators)
|
||||
if err := snap.store(c.db); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -674,14 +661,14 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
|
|||
header.Extra = header.Extra[:extraVanity]
|
||||
|
||||
// get validator set if number
|
||||
if (number+1)%c.config.Sprint == 0 {
|
||||
newValidators, err := c.GetCurrentValidators(header.ParentHash, number+1)
|
||||
if IsSprintStart(number+1, c.config.Sprint) {
|
||||
newValidators, err := c.spanner.GetCurrentValidators(header.ParentHash, number+1)
|
||||
if err != nil {
|
||||
return errors.New("unknown validators")
|
||||
}
|
||||
|
||||
// sort validator by address
|
||||
sort.Sort(ValidatorsByAddress(newValidators))
|
||||
sort.Sort(valset.ValidatorsByAddress(newValidators))
|
||||
|
||||
for _, validator := range newValidators {
|
||||
header.Extra = append(header.Extra, validator.HeaderBytes()...)
|
||||
|
|
@ -727,14 +714,14 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
|
|||
headerNumber := header.Number.Uint64()
|
||||
|
||||
if headerNumber%c.config.Sprint == 0 {
|
||||
cx := chainContext{Chain: chain, Bor: c}
|
||||
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
||||
// check and commit span
|
||||
if err := c.checkAndCommitSpan(state, header, cx); err != nil {
|
||||
log.Error("Error while committing span", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !c.WithoutHeimdall {
|
||||
if c.HeimdallClient != nil {
|
||||
// commit statees
|
||||
stateSyncData, err = c.CommitStates(state, header, cx)
|
||||
if err != nil {
|
||||
|
|
@ -762,7 +749,6 @@ func decodeGenesisAlloc(i interface{}) (core.GenesisAlloc, error) {
|
|||
var alloc core.GenesisAlloc
|
||||
|
||||
b, err := json.Marshal(i)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -800,7 +786,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
|
|||
headerNumber := header.Number.Uint64()
|
||||
|
||||
if headerNumber%c.config.Sprint == 0 {
|
||||
cx := chainContext{Chain: chain, Bor: c}
|
||||
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
||||
|
||||
// check and commit span
|
||||
err := c.checkAndCommitSpan(state, header, cx)
|
||||
|
|
@ -809,7 +795,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if !c.WithoutHeimdall {
|
||||
if c.HeimdallClient != nil {
|
||||
// commit states
|
||||
stateSyncData, err = c.CommitStates(state, header, cx)
|
||||
if err != nil {
|
||||
|
|
@ -832,7 +818,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
|
|||
block := types.NewBlock(header, txs, nil, receipts, new(trie.Trie))
|
||||
|
||||
// set state sync
|
||||
bc := chain.(*core.BlockChain)
|
||||
bc := chain.(core.BorStateSyncer)
|
||||
bc.SetStateSync(stateSyncData)
|
||||
|
||||
// return the final block for sealing
|
||||
|
|
@ -890,15 +876,13 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
|||
wiggle := time.Duration(successionNumber) * time.Duration(c.config.CalculateBackupMultiplier(number)) * time.Second
|
||||
|
||||
// Sign all the things!
|
||||
sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header, c.config))
|
||||
err = Sign(signFn, signer, header, c.config)
|
||||
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))
|
||||
log.Info("Waiting for slot to sign and propagate", "number", number, "hash", header.Hash, "delay-in-sec", uint(delay), "delay", common.PrettyDuration(delay))
|
||||
|
||||
go func() {
|
||||
select {
|
||||
|
|
@ -910,6 +894,8 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
|||
log.Info(
|
||||
"Sealing out-of-turn",
|
||||
"number", number,
|
||||
"hash", header.Hash,
|
||||
"wiggle-in-sec", uint(wiggle),
|
||||
"wiggle", common.PrettyDuration(wiggle),
|
||||
"in-turn-signer", snap.ValidatorSet.GetProposer().Address.Hex(),
|
||||
)
|
||||
|
|
@ -932,6 +918,17 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
|||
return nil
|
||||
}
|
||||
|
||||
func Sign(signFn SignerFn, signer common.Address, header *types.Header, c *params.BorConfig) error {
|
||||
sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header, c))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
|
||||
// that a new block should have based on the previous blocks in the chain and the
|
||||
// current signer.
|
||||
|
|
@ -962,114 +959,11 @@ func (c *Bor) APIs(chain consensus.ChainHeaderReader) []rpc.API {
|
|||
|
||||
// Close implements consensus.Engine. It's a noop for bor as there are no background threads.
|
||||
func (c *Bor) Close() error {
|
||||
c.closeOnce.Do(func() {
|
||||
c.HeimdallClient.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCurrentSpan get current span from contract
|
||||
func (c *Bor) GetCurrentSpan(headerHash common.Hash) (*Span, error) {
|
||||
// block
|
||||
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||
|
||||
// method
|
||||
method := "getCurrentSpan"
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
data, err := c.validatorSetABI.Pack(method)
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for getCurrentSpan", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgData := (hexutil.Bytes)(data)
|
||||
toAddress := common.HexToAddress(c.config.ValidatorContract)
|
||||
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||
result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{
|
||||
Gas: &gas,
|
||||
To: &toAddress,
|
||||
Data: &msgData,
|
||||
}, blockNr, nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// span result
|
||||
ret := new(struct {
|
||||
Number *big.Int
|
||||
StartBlock *big.Int
|
||||
EndBlock *big.Int
|
||||
})
|
||||
if err := c.validatorSetABI.UnpackIntoInterface(ret, method, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create new span
|
||||
span := Span{
|
||||
ID: ret.Number.Uint64(),
|
||||
StartBlock: ret.StartBlock.Uint64(),
|
||||
EndBlock: ret.EndBlock.Uint64(),
|
||||
}
|
||||
|
||||
return &span, nil
|
||||
}
|
||||
|
||||
// GetCurrentValidators get current validators
|
||||
func (c *Bor) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*Validator, error) {
|
||||
// block
|
||||
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||
|
||||
// method
|
||||
method := "getBorValidators"
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
data, err := c.validatorSetABI.Pack(method, big.NewInt(0).SetUint64(blockNumber))
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for getValidator", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// call
|
||||
msgData := (hexutil.Bytes)(data)
|
||||
toAddress := common.HexToAddress(c.config.ValidatorContract)
|
||||
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||
result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{
|
||||
Gas: &gas,
|
||||
To: &toAddress,
|
||||
Data: &msgData,
|
||||
}, blockNr, nil)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var (
|
||||
ret0 = new([]common.Address)
|
||||
ret1 = new([]*big.Int)
|
||||
)
|
||||
|
||||
out := &[]interface{}{
|
||||
ret0,
|
||||
ret1,
|
||||
}
|
||||
|
||||
if err := c.validatorSetABI.UnpackIntoInterface(out, method, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
valz := make([]*Validator, len(*ret0))
|
||||
for i, a := range *ret0 {
|
||||
valz[i] = &Validator{
|
||||
Address: a,
|
||||
VotingPower: (*ret1)[i].Int64(),
|
||||
}
|
||||
}
|
||||
|
||||
return valz, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Bor) checkAndCommitSpan(
|
||||
|
|
@ -1078,21 +972,20 @@ func (c *Bor) checkAndCommitSpan(
|
|||
chain core.ChainContext,
|
||||
) error {
|
||||
headerNumber := header.Number.Uint64()
|
||||
span, err := c.GetCurrentSpan(header.ParentHash)
|
||||
|
||||
span, err := c.spanner.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 c.FetchAndCommitSpan(span.ID+1, state, header, chain)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Bor) needToCommitSpan(span *Span, headerNumber uint64) bool {
|
||||
func (c *Bor) needToCommitSpan(span *span.Span, headerNumber uint64) bool {
|
||||
// if span is nil
|
||||
if span == nil {
|
||||
return false
|
||||
|
|
@ -1111,15 +1004,16 @@ func (c *Bor) needToCommitSpan(span *Span, headerNumber uint64) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (c *Bor) fetchAndCommitSpan(
|
||||
func (c *Bor) FetchAndCommitSpan(
|
||||
newSpanID uint64,
|
||||
state *state.StateDB,
|
||||
header *types.Header,
|
||||
chain core.ChainContext,
|
||||
) error {
|
||||
var heimdallSpan HeimdallSpan
|
||||
var heimdallSpan span.HeimdallSpan
|
||||
|
||||
if c.WithoutHeimdall {
|
||||
if c.HeimdallClient == nil {
|
||||
// fixme: move to a new mock or fake and remove c.HeimdallClient completely
|
||||
s, err := c.getNextHeimdallSpanForTest(newSpanID, header, chain)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -1127,105 +1021,51 @@ func (c *Bor) fetchAndCommitSpan(
|
|||
|
||||
heimdallSpan = *s
|
||||
} else {
|
||||
response, err := c.HeimdallClient.FetchWithRetry(fmt.Sprintf("bor/span/%d", newSpanID), "")
|
||||
response, err := c.HeimdallClient.Span(newSpanID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(response.Result, &heimdallSpan); err != nil {
|
||||
return err
|
||||
}
|
||||
heimdallSpan = *response
|
||||
}
|
||||
|
||||
// check if chain id matches with heimdall span
|
||||
// check if chain id matches with Heimdall span
|
||||
if heimdallSpan.ChainID != c.chainConfig.ChainID.String() {
|
||||
return fmt.Errorf(
|
||||
"Chain id proposed span, %s, and bor chain id, %s, doesn't match",
|
||||
"chain id proposed span, %s, and bor chain id, %s, doesn't match",
|
||||
heimdallSpan.ChainID,
|
||||
c.chainConfig.ChainID,
|
||||
)
|
||||
}
|
||||
|
||||
// get validators bytes
|
||||
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
|
||||
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,
|
||||
"endBlock", heimdallSpan.EndBlock,
|
||||
"validatorBytes", hex.EncodeToString(validatorBytes),
|
||||
"producerBytes", hex.EncodeToString(producerBytes),
|
||||
)
|
||||
|
||||
// get packed data
|
||||
data, err := c.validatorSetABI.Pack(method,
|
||||
big.NewInt(0).SetUint64(heimdallSpan.ID),
|
||||
big.NewInt(0).SetUint64(heimdallSpan.StartBlock),
|
||||
big.NewInt(0).SetUint64(heimdallSpan.EndBlock),
|
||||
validatorBytes,
|
||||
producerBytes,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for commitSpan", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// get system message
|
||||
msg := getSystemMessage(common.HexToAddress(c.config.ValidatorContract), data)
|
||||
|
||||
// apply message
|
||||
return applyMessage(msg, state, header, c.chainConfig, chain)
|
||||
return c.spanner.CommitSpan(heimdallSpan, state, header, chain)
|
||||
}
|
||||
|
||||
// CommitStates commit states
|
||||
func (c *Bor) CommitStates(
|
||||
state *state.StateDB,
|
||||
header *types.Header,
|
||||
chain chainContext,
|
||||
chain statefull.ChainContext,
|
||||
) ([]*types.StateSyncData, error) {
|
||||
stateSyncs := make([]*types.StateSyncData, 0)
|
||||
number := header.Number.Uint64()
|
||||
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
|
||||
|
||||
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.Sprint).Time), 0)
|
||||
lastStateID := _lastStateID.Uint64()
|
||||
|
||||
log.Info(
|
||||
"Fetching state updates from Heimdall",
|
||||
"fromID", lastStateID+1,
|
||||
"to", to.Format(time.RFC3339))
|
||||
|
||||
eventRecords, err := c.HeimdallClient.FetchStateSyncEvents(lastStateID+1, to.Unix())
|
||||
|
||||
eventRecords, err := c.HeimdallClient.StateSyncEvents(lastStateID+1, to.Unix())
|
||||
if err != nil {
|
||||
log.Error("Error occurred when fetching state sync events", err)
|
||||
log.Error("Error occurred when fetching state sync events", "stateID", lastStateID+1, "error", err)
|
||||
}
|
||||
|
||||
if c.config.OverrideStateSyncRecords != nil {
|
||||
|
|
@ -1234,6 +1074,8 @@ func (c *Bor) CommitStates(
|
|||
}
|
||||
}
|
||||
|
||||
totalGas := 0 /// limit on gas for state sync per block
|
||||
|
||||
chainID := c.chainConfig.ChainID.String()
|
||||
|
||||
for _, eventRecord := range eventRecords {
|
||||
|
|
@ -1242,7 +1084,7 @@ func (c *Bor) CommitStates(
|
|||
}
|
||||
|
||||
if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
|
||||
log.Error(err.Error())
|
||||
log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error())
|
||||
break
|
||||
}
|
||||
|
||||
|
|
@ -1252,18 +1094,23 @@ func (c *Bor) CommitStates(
|
|||
Data: hex.EncodeToString(eventRecord.Data),
|
||||
TxHash: eventRecord.TxHash,
|
||||
}
|
||||
|
||||
stateSyncs = append(stateSyncs, &stateData)
|
||||
|
||||
if err := c.GenesisContractsClient.CommitState(eventRecord, state, header, chain); err != nil {
|
||||
gasUsed, err := c.GenesisContractsClient.CommitState(eventRecord, state, header, chain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalGas += int(gasUsed)
|
||||
|
||||
lastStateID++
|
||||
}
|
||||
|
||||
return stateSyncs, nil
|
||||
}
|
||||
|
||||
func validateEventRecord(eventRecord *EventRecordWithTime, number uint64, to time.Time, lastStateID uint64, chainID string) error {
|
||||
func validateEventRecord(eventRecord *clerk.EventRecordWithTime, number uint64, to time.Time, lastStateID uint64, chainID string) error {
|
||||
// event id should be sequential and event.Time should lie in the range [from, to)
|
||||
if lastStateID+1 != eventRecord.ID || eventRecord.ChainID != chainID || !eventRecord.Time.Before(to) {
|
||||
return &InvalidStateReceivedError{number, lastStateID, &to, eventRecord}
|
||||
|
|
@ -1276,6 +1123,10 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) {
|
|||
c.HeimdallClient = h
|
||||
}
|
||||
|
||||
func (c *Bor) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||
return c.spanner.GetCurrentValidators(headerHash, blockNumber)
|
||||
}
|
||||
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
|
|
@ -1284,16 +1135,16 @@ func (c *Bor) getNextHeimdallSpanForTest(
|
|||
newSpanID uint64,
|
||||
header *types.Header,
|
||||
chain core.ChainContext,
|
||||
) (*HeimdallSpan, error) {
|
||||
) (*span.HeimdallSpan, error) {
|
||||
headerNumber := header.Number.Uint64()
|
||||
span, err := c.GetCurrentSpan(header.ParentHash)
|
||||
|
||||
spanBor, err := c.spanner.GetCurrentSpan(header.ParentHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get local chain context object
|
||||
localContext := chain.(chainContext)
|
||||
localContext := chain.(statefull.ChainContext)
|
||||
// Retrieve the snapshot needed to verify this header and cache it
|
||||
snap, err := c.snapshot(localContext.Chain, headerNumber-1, header.ParentHash, nil)
|
||||
if err != nil {
|
||||
|
|
@ -1301,22 +1152,22 @@ func (c *Bor) getNextHeimdallSpanForTest(
|
|||
}
|
||||
|
||||
// new span
|
||||
span.ID = newSpanID
|
||||
if span.EndBlock == 0 {
|
||||
span.StartBlock = 256
|
||||
spanBor.ID = newSpanID
|
||||
if spanBor.EndBlock == 0 {
|
||||
spanBor.StartBlock = 256
|
||||
} else {
|
||||
span.StartBlock = span.EndBlock + 1
|
||||
spanBor.StartBlock = spanBor.EndBlock + 1
|
||||
}
|
||||
|
||||
span.EndBlock = span.StartBlock + (100 * c.config.Sprint) - 1
|
||||
spanBor.EndBlock = spanBor.StartBlock + (100 * c.config.Sprint) - 1
|
||||
|
||||
selectedProducers := make([]Validator, len(snap.ValidatorSet.Validators))
|
||||
selectedProducers := make([]valset.Validator, len(snap.ValidatorSet.Validators))
|
||||
for i, v := range snap.ValidatorSet.Validators {
|
||||
selectedProducers[i] = *v
|
||||
}
|
||||
|
||||
heimdallSpan := &HeimdallSpan{
|
||||
Span: *span,
|
||||
heimdallSpan := &span.HeimdallSpan{
|
||||
Span: *spanBor,
|
||||
ValidatorSet: *snap.ValidatorSet,
|
||||
SelectedProducers: selectedProducers,
|
||||
ChainID: c.chainConfig.ChainID.String(),
|
||||
|
|
@ -1325,82 +1176,7 @@ func (c *Bor) getNextHeimdallSpanForTest(
|
|||
return heimdallSpan, nil
|
||||
}
|
||||
|
||||
//
|
||||
// Chain context
|
||||
//
|
||||
|
||||
// chain context
|
||||
type chainContext struct {
|
||||
Chain consensus.ChainHeaderReader
|
||||
Bor consensus.Engine
|
||||
}
|
||||
|
||||
func (c chainContext) Engine() consensus.Engine {
|
||||
return c.Bor
|
||||
}
|
||||
|
||||
func (c chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
|
||||
return c.Chain.GetHeader(hash, number)
|
||||
}
|
||||
|
||||
// callmsg implements core.Message to allow passing it as a transaction simulator.
|
||||
type callmsg struct {
|
||||
ethereum.CallMsg
|
||||
}
|
||||
|
||||
func (m callmsg) From() common.Address { return m.CallMsg.From }
|
||||
func (m callmsg) Nonce() uint64 { return 0 }
|
||||
func (m callmsg) CheckNonce() bool { return false }
|
||||
func (m callmsg) To() *common.Address { return m.CallMsg.To }
|
||||
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||
func (m callmsg) Gas() uint64 { return m.CallMsg.Gas }
|
||||
func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
|
||||
func (m callmsg) Data() []byte { return m.CallMsg.Data }
|
||||
|
||||
// get system message
|
||||
func getSystemMessage(toAddress common.Address, data []byte) callmsg {
|
||||
return callmsg{
|
||||
ethereum.CallMsg{
|
||||
From: systemAddress,
|
||||
Gas: math.MaxUint64 / 2,
|
||||
GasPrice: big.NewInt(0),
|
||||
Value: big.NewInt(0),
|
||||
To: &toAddress,
|
||||
Data: data,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// apply message
|
||||
func applyMessage(
|
||||
msg callmsg,
|
||||
state *state.StateDB,
|
||||
header *types.Header,
|
||||
chainConfig *params.ChainConfig,
|
||||
chainContext core.ChainContext,
|
||||
) error {
|
||||
// Create a new context to be used in the EVM environment
|
||||
blockContext := core.NewEVMBlockContext(header, chainContext, &header.Coinbase)
|
||||
// Create a new environment which holds all relevant information
|
||||
// about the transaction and calling mechanisms.
|
||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, state, chainConfig, vm.Config{})
|
||||
// Apply the transaction to the current state (included in the env)
|
||||
_, _, err := vmenv.Call(
|
||||
vm.AccountRef(msg.From()),
|
||||
*msg.To(),
|
||||
msg.Data(),
|
||||
msg.Gas(),
|
||||
msg.Value(),
|
||||
)
|
||||
// Update the state with pending changes
|
||||
if err != nil {
|
||||
state.Finalise(true)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatorContains(a []*Validator, x *Validator) (*Validator, bool) {
|
||||
func validatorContains(a []*valset.Validator, x *valset.Validator) (*valset.Validator, bool) {
|
||||
for _, n := range a {
|
||||
if n.Address == x.Address {
|
||||
return n, true
|
||||
|
|
@ -1410,11 +1186,11 @@ func validatorContains(a []*Validator, x *Validator) (*Validator, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator) *ValidatorSet {
|
||||
func getUpdatedValidatorSet(oldValidatorSet *valset.ValidatorSet, newVals []*valset.Validator) *valset.ValidatorSet {
|
||||
v := oldValidatorSet
|
||||
oldVals := v.Validators
|
||||
|
||||
changes := make([]*Validator, 0, len(oldVals))
|
||||
changes := make([]*valset.Validator, 0, len(oldVals))
|
||||
|
||||
for _, ov := range oldVals {
|
||||
if f, ok := validatorContains(newVals, ov); ok {
|
||||
|
|
@ -1433,12 +1209,12 @@ func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator)
|
|||
}
|
||||
|
||||
if err := v.UpdateWithChangeSet(changes); err != nil {
|
||||
log.Error("Error while updating change set", err)
|
||||
log.Error("Error while updating change set", "error", err)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func isSprintStart(number, sprint uint64) bool {
|
||||
func IsSprintStart(number, sprint uint64) bool {
|
||||
return number%sprint == 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package bor
|
||||
package clerk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -23,10 +23,10 @@ type EventRecordWithTime struct {
|
|||
Time time.Time `json:"record_time" yaml:"record_time"`
|
||||
}
|
||||
|
||||
// String returns the string representations of span
|
||||
func (e *EventRecordWithTime) String() string {
|
||||
// String returns the string representation of EventRecord
|
||||
func (e *EventRecordWithTime) String(gasUsed uint64) string {
|
||||
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, gasUsed %d",
|
||||
e.ID,
|
||||
e.Contract.String(),
|
||||
e.Data.String(),
|
||||
|
|
@ -34,6 +34,7 @@ func (e *EventRecordWithTime) String() string {
|
|||
e.LogIndex,
|
||||
e.ChainID,
|
||||
e.Time.Format(time.RFC3339),
|
||||
gasUsed,
|
||||
)
|
||||
}
|
||||
|
||||
133
consensus/bor/contract/client.go
Normal file
133
consensus/bor/contract/client.go
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -3,37 +3,10 @@ package bor
|
|||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
)
|
||||
|
||||
// TotalVotingPowerExceededError is returned when the maximum allowed total voting power is exceeded
|
||||
type TotalVotingPowerExceededError struct {
|
||||
Sum int64
|
||||
Validators []*Validator
|
||||
}
|
||||
|
||||
func (e *TotalVotingPowerExceededError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"Total voting power should be guarded to not exceed %v; got: %v; for validator set: %v",
|
||||
MaxTotalVotingPower,
|
||||
e.Sum,
|
||||
e.Validators,
|
||||
)
|
||||
}
|
||||
|
||||
type InvalidStartEndBlockError struct {
|
||||
Start uint64
|
||||
End uint64
|
||||
CurrentHeader uint64
|
||||
}
|
||||
|
||||
func (e *InvalidStartEndBlockError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"Invalid parameters start: %d and end block: %d params",
|
||||
e.Start,
|
||||
e.End,
|
||||
)
|
||||
}
|
||||
|
||||
type MaxCheckpointLengthExceededError struct {
|
||||
Start uint64
|
||||
End uint64
|
||||
|
|
@ -129,12 +102,12 @@ type InvalidStateReceivedError struct {
|
|||
Number uint64
|
||||
LastStateID uint64
|
||||
To *time.Time
|
||||
Event *EventRecordWithTime
|
||||
Event *clerk.EventRecordWithTime
|
||||
}
|
||||
|
||||
func (e *InvalidStateReceivedError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"Received invalid event %s at block %d. Requested events until %s. Last state id was %d",
|
||||
"Received invalid event %v at block %d. Requested events until %s. Last state id was %d",
|
||||
e.Event,
|
||||
e.Number,
|
||||
e.To.Format(time.RFC3339),
|
||||
|
|
|
|||
16
consensus/bor/genesis.go
Normal file
16
consensus/bor/genesis.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package bor
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/statefull"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=./genesis_contract_mock.go -package=bor . GenesisContract
|
||||
type GenesisContract interface {
|
||||
CommitState(event *clerk.EventRecordWithTime, state *state.StateDB, header *types.Header, chCtx statefull.ChainContext) (uint64, error)
|
||||
LastStateId(snapshotNumber uint64) (*big.Int, error)
|
||||
}
|
||||
69
consensus/bor/genesis_contract_mock.go
Normal file
69
consensus/bor/genesis_contract_mock.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: GenesisContract)
|
||||
|
||||
// Package bor is a generated GoMock package.
|
||||
package bor
|
||||
|
||||
import (
|
||||
big "math/big"
|
||||
reflect "reflect"
|
||||
|
||||
clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
statefull "github.com/ethereum/go-ethereum/consensus/bor/statefull"
|
||||
state "github.com/ethereum/go-ethereum/core/state"
|
||||
types "github.com/ethereum/go-ethereum/core/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockGenesisContract is a mock of GenesisContract interface.
|
||||
type MockGenesisContract struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockGenesisContractMockRecorder
|
||||
}
|
||||
|
||||
// MockGenesisContractMockRecorder is the mock recorder for MockGenesisContract.
|
||||
type MockGenesisContractMockRecorder struct {
|
||||
mock *MockGenesisContract
|
||||
}
|
||||
|
||||
// NewMockGenesisContract creates a new mock instance.
|
||||
func NewMockGenesisContract(ctrl *gomock.Controller) *MockGenesisContract {
|
||||
mock := &MockGenesisContract{ctrl: ctrl}
|
||||
mock.recorder = &MockGenesisContractMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockGenesisContract) EXPECT() *MockGenesisContractMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CommitState mocks base method.
|
||||
func (m *MockGenesisContract) CommitState(arg0 *clerk.EventRecordWithTime, arg1 *state.StateDB, arg2 *types.Header, arg3 statefull.ChainContext) (uint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CommitState", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(uint64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CommitState indicates an expected call of CommitState.
|
||||
func (mr *MockGenesisContractMockRecorder) CommitState(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitState", reflect.TypeOf((*MockGenesisContract)(nil).CommitState), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// LastStateId mocks base method.
|
||||
func (m *MockGenesisContract) LastStateId(arg0 uint64) (*big.Int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LastStateId", arg0)
|
||||
ret0, _ := ret[0].(*big.Int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// LastStateId indicates an expected call of LastStateId.
|
||||
func (mr *MockGenesisContractMockRecorder) LastStateId(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastStateId", reflect.TypeOf((*MockGenesisContract)(nil).LastStateId), arg0)
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
13
consensus/bor/heimdall.go
Normal file
13
consensus/bor/heimdall.go
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package bor
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=../../tests/bor/mocks/IHeimdallClient.go -package=mocks . IHeimdallClient
|
||||
type IHeimdallClient interface {
|
||||
StateSyncEvents(fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error)
|
||||
Span(spanID uint64) (*span.HeimdallSpan, error)
|
||||
Close()
|
||||
}
|
||||
222
consensus/bor/heimdall/client.go
Normal file
222
consensus/bor/heimdall/client.go
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
package heimdall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
// errShutdownDetected is returned if a shutdown was detected
|
||||
var errShutdownDetected = errors.New("shutdown detected")
|
||||
|
||||
const (
|
||||
stateFetchLimit = 50
|
||||
apiHeimdallTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
type StateSyncEventsResponse struct {
|
||||
Height string `json:"height"`
|
||||
Result []*clerk.EventRecordWithTime `json:"result"`
|
||||
}
|
||||
|
||||
type SpanResponse struct {
|
||||
Height string `json:"height"`
|
||||
Result span.HeimdallSpan `json:"result"`
|
||||
}
|
||||
|
||||
type HeimdallClient struct {
|
||||
urlString string
|
||||
client http.Client
|
||||
closeCh chan struct{}
|
||||
}
|
||||
|
||||
func NewHeimdallClient(urlString string) *HeimdallClient {
|
||||
return &HeimdallClient{
|
||||
urlString: urlString,
|
||||
client: http.Client{
|
||||
Timeout: apiHeimdallTimeout,
|
||||
},
|
||||
closeCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
fetchStateSyncEventsFormat = "from-id=%d&to-time=%d&limit=%d"
|
||||
fetchStateSyncEventsPath = "clerk/event-record/list"
|
||||
|
||||
fetchSpanFormat = "bor/span/%d"
|
||||
)
|
||||
|
||||
func (h *HeimdallClient) StateSyncEvents(fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) {
|
||||
eventRecords := make([]*clerk.EventRecordWithTime, 0)
|
||||
|
||||
for {
|
||||
url, err := stateSyncURL(h.urlString, fromID, to)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Info("Fetching state sync events", "queryParams", url.RawQuery)
|
||||
|
||||
response, err := FetchWithRetry[StateSyncEventsResponse](h.client, url, h.closeCh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response == nil || response.Result == nil {
|
||||
// status 204
|
||||
break
|
||||
}
|
||||
|
||||
eventRecords = append(eventRecords, response.Result...)
|
||||
|
||||
if len(response.Result) < stateFetchLimit {
|
||||
break
|
||||
}
|
||||
|
||||
fromID += uint64(stateFetchLimit)
|
||||
}
|
||||
|
||||
sort.SliceStable(eventRecords, func(i, j int) bool {
|
||||
return eventRecords[i].ID < eventRecords[j].ID
|
||||
})
|
||||
|
||||
return eventRecords, nil
|
||||
}
|
||||
|
||||
func (h *HeimdallClient) Span(spanID uint64) (*span.HeimdallSpan, error) {
|
||||
url, err := spanURL(h.urlString, spanID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := FetchWithRetry[SpanResponse](h.client, url, h.closeCh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &response.Result, nil
|
||||
}
|
||||
|
||||
// FetchWithRetry returns data from heimdall with retry
|
||||
func FetchWithRetry[T any](client http.Client, url *url.URL, closeCh chan struct{}) (*T, error) {
|
||||
// attempt counter
|
||||
attempt := 1
|
||||
result := new(T)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), apiHeimdallTimeout)
|
||||
|
||||
// request data once
|
||||
body, err := internalFetch(ctx, client, url)
|
||||
|
||||
cancel()
|
||||
|
||||
if err == nil && body != nil {
|
||||
err = json.Unmarshal(body, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// create a new ticker for retrying the request
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
log.Info("Retrying again in 5 seconds to fetch data from Heimdall", "path", url.Path, "attempt", attempt)
|
||||
attempt++
|
||||
select {
|
||||
case <-closeCh:
|
||||
log.Debug("Shutdown detected, terminating request")
|
||||
|
||||
return nil, errShutdownDetected
|
||||
case <-ticker.C:
|
||||
ctx, cancel = context.WithTimeout(context.Background(), apiHeimdallTimeout)
|
||||
|
||||
body, err = internalFetch(ctx, client, url)
|
||||
|
||||
cancel()
|
||||
|
||||
if err == nil && body != nil {
|
||||
err = json.Unmarshal(body, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func spanURL(urlString string, spanID uint64) (*url.URL, error) {
|
||||
return makeURL(urlString, fmt.Sprintf(fetchSpanFormat, spanID), "")
|
||||
}
|
||||
|
||||
func stateSyncURL(urlString string, fromID uint64, to int64) (*url.URL, error) {
|
||||
queryParams := fmt.Sprintf(fetchStateSyncEventsFormat, fromID, to, stateFetchLimit)
|
||||
|
||||
return makeURL(urlString, fetchStateSyncEventsPath, queryParams)
|
||||
}
|
||||
|
||||
func makeURL(urlString, rawPath, rawQuery string) (*url.URL, error) {
|
||||
u, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u.Path = rawPath
|
||||
u.RawQuery = rawQuery
|
||||
|
||||
return u, err
|
||||
}
|
||||
|
||||
// internal fetch method
|
||||
func internalFetch(ctx context.Context, client http.Client, u *url.URL) ([]byte, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
// check status code
|
||||
if res.StatusCode != 200 && res.StatusCode != 204 {
|
||||
return nil, fmt.Errorf("Error while fetching data from Heimdall")
|
||||
}
|
||||
|
||||
// unmarshall data from buffer
|
||||
if res.StatusCode == 204 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// get response
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// Close sends a signal to stop the running process
|
||||
func (h *HeimdallClient) Close() {
|
||||
close(h.closeCh)
|
||||
h.client.CloseIdleConnections()
|
||||
}
|
||||
35
consensus/bor/heimdall/client_test.go
Normal file
35
consensus/bor/heimdall/client_test.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package heimdall
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSpanURL(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
url, err := spanURL("http://bor0", 1)
|
||||
if err != nil {
|
||||
t.Fatal("got an error", err)
|
||||
}
|
||||
|
||||
const expected = "http://bor0/bor/span/1"
|
||||
|
||||
if url.String() != expected {
|
||||
t.Fatalf("expected URL %q, got %q", url.String(), expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateSyncURL(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
url, err := stateSyncURL("http://bor0", 10, 100)
|
||||
if err != nil {
|
||||
t.Fatal("got an error", err)
|
||||
}
|
||||
|
||||
const expected = "http://bor0/clerk/event-record/list?from-id=10&to-time=100&limit=50"
|
||||
|
||||
if url.String() != expected {
|
||||
t.Fatalf("expected URL %q, got %q", url.String(), expected)
|
||||
}
|
||||
}
|
||||
20
consensus/bor/heimdall/span/span.go
Normal file
20
consensus/bor/heimdall/span/span.go
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package span
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
)
|
||||
|
||||
// Span Bor represents a current bor span
|
||||
type Span struct {
|
||||
ID uint64 `json:"span_id" yaml:"span_id"`
|
||||
StartBlock uint64 `json:"start_block" yaml:"start_block"`
|
||||
EndBlock uint64 `json:"end_block" yaml:"end_block"`
|
||||
}
|
||||
|
||||
// HeimdallSpan represents span from heimdall APIs
|
||||
type HeimdallSpan struct {
|
||||
Span
|
||||
ValidatorSet valset.ValidatorSet `json:"validator_set" yaml:"validator_set"`
|
||||
SelectedProducers []valset.Validator `json:"selected_producers" yaml:"selected_producers"`
|
||||
ChainID string `json:"bor_chain_id" yaml:"bor_chain_id"`
|
||||
}
|
||||
200
consensus/bor/heimdall/span/spanner.go
Normal file
200
consensus/bor/heimdall/span/spanner.go
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
package span
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/abi"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/api"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/statefull"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
type ChainSpanner struct {
|
||||
ethAPI api.Caller
|
||||
validatorSet abi.ABI
|
||||
chainConfig *params.ChainConfig
|
||||
validatorContractAddress common.Address
|
||||
}
|
||||
|
||||
func NewChainSpanner(ethAPI api.Caller, validatorSet abi.ABI, chainConfig *params.ChainConfig, validatorContractAddress common.Address) *ChainSpanner {
|
||||
return &ChainSpanner{
|
||||
ethAPI: ethAPI,
|
||||
validatorSet: validatorSet,
|
||||
chainConfig: chainConfig,
|
||||
validatorContractAddress: validatorContractAddress,
|
||||
}
|
||||
}
|
||||
|
||||
// GetCurrentSpan get current span from contract
|
||||
func (c *ChainSpanner) GetCurrentSpan(headerHash common.Hash) (*Span, error) {
|
||||
// block
|
||||
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||
|
||||
// method
|
||||
method := "getCurrentSpan"
|
||||
|
||||
data, err := c.validatorSet.Pack(method)
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for getCurrentSpan", "error", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgData := (hexutil.Bytes)(data)
|
||||
toAddress := c.validatorContractAddress
|
||||
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||
|
||||
// todo: would we like to have a timeout here?
|
||||
result, err := c.ethAPI.Call(context.Background(), ethapi.TransactionArgs{
|
||||
Gas: &gas,
|
||||
To: &toAddress,
|
||||
Data: &msgData,
|
||||
}, blockNr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// span result
|
||||
ret := new(struct {
|
||||
Number *big.Int
|
||||
StartBlock *big.Int
|
||||
EndBlock *big.Int
|
||||
})
|
||||
|
||||
if err := c.validatorSet.UnpackIntoInterface(ret, method, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create new span
|
||||
span := Span{
|
||||
ID: ret.Number.Uint64(),
|
||||
StartBlock: ret.StartBlock.Uint64(),
|
||||
EndBlock: ret.EndBlock.Uint64(),
|
||||
}
|
||||
|
||||
return &span, nil
|
||||
}
|
||||
|
||||
// GetCurrentValidators get current validators
|
||||
func (c *ChainSpanner) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// method
|
||||
const method = "getBorValidators"
|
||||
|
||||
data, err := c.validatorSet.Pack(method, big.NewInt(0).SetUint64(blockNumber))
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for getValidator", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// call
|
||||
msgData := (hexutil.Bytes)(data)
|
||||
toAddress := c.validatorContractAddress
|
||||
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||
|
||||
// block
|
||||
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||
|
||||
result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{
|
||||
Gas: &gas,
|
||||
To: &toAddress,
|
||||
Data: &msgData,
|
||||
}, blockNr, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var (
|
||||
ret0 = new([]common.Address)
|
||||
ret1 = new([]*big.Int)
|
||||
)
|
||||
|
||||
out := &[]interface{}{
|
||||
ret0,
|
||||
ret1,
|
||||
}
|
||||
|
||||
if err := c.validatorSet.UnpackIntoInterface(out, method, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
valz := make([]*valset.Validator, len(*ret0))
|
||||
for i, a := range *ret0 {
|
||||
valz[i] = &valset.Validator{
|
||||
Address: a,
|
||||
VotingPower: (*ret1)[i].Int64(),
|
||||
}
|
||||
}
|
||||
|
||||
return valz, nil
|
||||
}
|
||||
|
||||
const method = "commitSpan"
|
||||
|
||||
func (c *ChainSpanner) CommitSpan(heimdallSpan HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error {
|
||||
// get validators bytes
|
||||
validators := make([]valset.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
|
||||
producers := make([]valset.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
|
||||
}
|
||||
|
||||
log.Info("✅ Committing new span",
|
||||
"id", heimdallSpan.ID,
|
||||
"startBlock", heimdallSpan.StartBlock,
|
||||
"endBlock", heimdallSpan.EndBlock,
|
||||
"validatorBytes", hex.EncodeToString(validatorBytes),
|
||||
"producerBytes", hex.EncodeToString(producerBytes),
|
||||
)
|
||||
|
||||
data, err := c.validatorSet.Pack(method,
|
||||
big.NewInt(0).SetUint64(heimdallSpan.ID),
|
||||
big.NewInt(0).SetUint64(heimdallSpan.StartBlock),
|
||||
big.NewInt(0).SetUint64(heimdallSpan.EndBlock),
|
||||
validatorBytes,
|
||||
producerBytes,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for commitSpan", "error", err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// get system message
|
||||
msg := statefull.GetSystemMessage(c.validatorContractAddress, data)
|
||||
|
||||
// apply message
|
||||
_, err = statefull.ApplyMessage(msg, state, header, c.chainConfig, chainContext)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
package bor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
var (
|
||||
stateFetchLimit = 50
|
||||
)
|
||||
|
||||
// ResponseWithHeight defines a response object type that wraps an original
|
||||
// response with a height.
|
||||
type ResponseWithHeight struct {
|
||||
Height string `json:"height"`
|
||||
Result json.RawMessage `json:"result"`
|
||||
}
|
||||
|
||||
type IHeimdallClient interface {
|
||||
Fetch(path string, query string) (*ResponseWithHeight, error)
|
||||
FetchWithRetry(path string, query string) (*ResponseWithHeight, error)
|
||||
FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error)
|
||||
Close()
|
||||
}
|
||||
|
||||
type HeimdallClient struct {
|
||||
urlString string
|
||||
client http.Client
|
||||
closeCh chan struct{}
|
||||
}
|
||||
|
||||
func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
|
||||
h := &HeimdallClient{
|
||||
urlString: urlString,
|
||||
client: http.Client{
|
||||
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
|
||||
}
|
||||
|
||||
// Fetch fetches response from heimdall
|
||||
func (h *HeimdallClient) Fetch(rawPath string, rawQuery string) (*ResponseWithHeight, error) {
|
||||
u, err := url.Parse(h.urlString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u.Path = rawPath
|
||||
u.RawQuery = rawQuery
|
||||
|
||||
return h.internalFetch(u)
|
||||
}
|
||||
|
||||
// FetchWithRetry returns data from heimdall with retry
|
||||
func (h *HeimdallClient) FetchWithRetry(rawPath string, rawQuery string) (*ResponseWithHeight, error) {
|
||||
u, err := url.Parse(h.urlString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u.Path = rawPath
|
||||
u.RawQuery = rawQuery
|
||||
|
||||
// attempt counter
|
||||
attempt := 1
|
||||
|
||||
// request data once
|
||||
res, err := h.internalFetch(u)
|
||||
if err == nil && res != nil {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// create a new ticker for retrying the request
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
log.Info("Retrying again in 5 seconds to fetch data from Heimdall", "path", u.Path, "attempt", attempt)
|
||||
attempt++
|
||||
select {
|
||||
case <-h.closeCh:
|
||||
log.Debug("Shutdown detected, terminating request")
|
||||
return nil, errShutdownDetected
|
||||
case <-ticker.C:
|
||||
res, err := h.internalFetch(u)
|
||||
if err == nil && res != nil {
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// internal fetch method
|
||||
func (h *HeimdallClient) internalFetch(u *url.URL) (*ResponseWithHeight, error) {
|
||||
res, err := h.client.Get(u.String()) // nolint: noctx
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
// check status code
|
||||
if res.StatusCode != 200 && res.StatusCode != 204 {
|
||||
return nil, fmt.Errorf("Error while fetching data from Heimdall")
|
||||
}
|
||||
|
||||
// unmarshall data from buffer
|
||||
var response ResponseWithHeight
|
||||
if res.StatusCode == 204 {
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// get response
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// Close sends a signal to stop the running process
|
||||
func (h *HeimdallClient) Close() {
|
||||
close(h.closeCh)
|
||||
h.client.CloseIdleConnections()
|
||||
}
|
||||
|
|
@ -3,24 +3,24 @@ package bor
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// Snapshot is the state of the authorization voting at a given point in time.
|
||||
type Snapshot struct {
|
||||
config *params.BorConfig // Consensus engine parameters to fine tune behavior
|
||||
ethAPI *ethapi.PublicBlockChainAPI
|
||||
sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
|
||||
|
||||
Number uint64 `json:"number"` // Block number where the snapshot was created
|
||||
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
|
||||
ValidatorSet *ValidatorSet `json:"validatorSet"` // Validator set at this moment
|
||||
ValidatorSet *valset.ValidatorSet `json:"validatorSet"` // Validator set at this moment
|
||||
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
|
||||
}
|
||||
|
||||
|
|
@ -32,16 +32,14 @@ func newSnapshot(
|
|||
sigcache *lru.ARCCache,
|
||||
number uint64,
|
||||
hash common.Hash,
|
||||
validators []*Validator,
|
||||
ethAPI *ethapi.PublicBlockChainAPI,
|
||||
validators []*valset.Validator,
|
||||
) *Snapshot {
|
||||
snap := &Snapshot{
|
||||
config: config,
|
||||
ethAPI: ethAPI,
|
||||
sigcache: sigcache,
|
||||
Number: number,
|
||||
Hash: hash,
|
||||
ValidatorSet: NewValidatorSet(validators),
|
||||
ValidatorSet: valset.NewValidatorSet(validators),
|
||||
Recents: make(map[uint64]common.Address),
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +47,7 @@ func newSnapshot(
|
|||
}
|
||||
|
||||
// loadSnapshot loads an existing snapshot from the database.
|
||||
func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash, ethAPI *ethapi.PublicBlockChainAPI) (*Snapshot, error) {
|
||||
func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
|
||||
blob, err := db.Get(append([]byte("bor-"), hash[:]...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -63,10 +61,9 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat
|
|||
|
||||
snap.config = config
|
||||
snap.sigcache = sigcache
|
||||
snap.ethAPI = ethAPI
|
||||
|
||||
// update total voting power
|
||||
if err := snap.ValidatorSet.updateTotalVotingPower(); err != nil {
|
||||
if err := snap.ValidatorSet.UpdateTotalVotingPower(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +84,6 @@ func (s *Snapshot) store(db ethdb.Database) error {
|
|||
func (s *Snapshot) copy() *Snapshot {
|
||||
cpy := &Snapshot{
|
||||
config: s.config,
|
||||
ethAPI: s.ethAPI,
|
||||
sigcache: s.sigcache,
|
||||
Number: s.Number,
|
||||
Hash: s.Hash,
|
||||
|
|
@ -155,7 +151,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
|||
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
|
||||
|
||||
// get validators from headers and use that for new validator set
|
||||
newVals, _ := ParseValidators(validatorBytes)
|
||||
newVals, _ := valset.ParseValidators(validatorBytes)
|
||||
v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals)
|
||||
v.IncrementProposerPriority(1)
|
||||
snap.ValidatorSet = v
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"pgregory.net/rapid"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
unique "github.com/ethereum/go-ethereum/common/set"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -19,7 +22,7 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
validators := buildRandomValidatorSet(numVals)
|
||||
validatorSet := NewValidatorSet(validators)
|
||||
validatorSet := valset.NewValidatorSet(validators)
|
||||
snap := Snapshot{
|
||||
ValidatorSet: validatorSet,
|
||||
}
|
||||
|
|
@ -27,7 +30,6 @@ 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)
|
||||
}
|
||||
|
|
@ -41,20 +43,19 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
|||
validators := buildRandomValidatorSet(numVals)
|
||||
|
||||
// sort validators by address, which is what NewValidatorSet also does
|
||||
sort.Sort(ValidatorsByAddress(validators))
|
||||
sort.Sort(valset.ValidatorsByAddress(validators))
|
||||
|
||||
proposerIndex := 32
|
||||
signerIndex := 56
|
||||
// give highest ProposerPriority to a particular val, so that they become the proposer
|
||||
validators[proposerIndex].VotingPower = 200
|
||||
snap := Snapshot{
|
||||
ValidatorSet: NewValidatorSet(validators),
|
||||
ValidatorSet: valset.NewValidatorSet(validators),
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
|
@ -71,13 +72,12 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
|||
// give highest ProposerPriority to a particular val, so that they become the proposer
|
||||
validators[proposerIndex].VotingPower = 200
|
||||
snap := Snapshot{
|
||||
ValidatorSet: NewValidatorSet(validators),
|
||||
ValidatorSet: valset.NewValidatorSet(validators),
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
|
@ -90,14 +90,18 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
|||
|
||||
validators := buildRandomValidatorSet(numVals)
|
||||
snap := Snapshot{
|
||||
ValidatorSet: NewValidatorSet(validators),
|
||||
ValidatorSet: valset.NewValidatorSet(validators),
|
||||
}
|
||||
|
||||
dummyProposerAddress := randomAddress()
|
||||
snap.ValidatorSet.Proposer = &Validator{Address: dummyProposerAddress}
|
||||
snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress}
|
||||
|
||||
// choose any signer
|
||||
signer := snap.ValidatorSet.Validators[3].Address
|
||||
|
||||
_, err := snap.GetSignerSuccessionNumber(signer)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
e, ok := err.(*UnauthorizedProposerError)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
|
||||
|
|
@ -108,7 +112,7 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
|||
|
||||
validators := buildRandomValidatorSet(numVals)
|
||||
snap := Snapshot{
|
||||
ValidatorSet: NewValidatorSet(validators),
|
||||
ValidatorSet: valset.NewValidatorSet(validators),
|
||||
}
|
||||
dummySignerAddress := randomAddress()
|
||||
_, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
|
||||
|
|
@ -119,21 +123,22 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
|||
}
|
||||
|
||||
// nolint: unparam
|
||||
func buildRandomValidatorSet(numVals int) []*Validator {
|
||||
func buildRandomValidatorSet(numVals int) []*valset.Validator {
|
||||
rand.Seed(time.Now().Unix())
|
||||
|
||||
validators := make([]*Validator, numVals)
|
||||
validators := make([]*valset.Validator, numVals)
|
||||
valAddrs := randomAddresses(numVals)
|
||||
|
||||
for i := 0; i < numVals; i++ {
|
||||
validators[i] = &Validator{
|
||||
Address: randomAddress(),
|
||||
validators[i] = &valset.Validator{
|
||||
Address: valAddrs[i],
|
||||
// cannot process validators with voting power 0, hence +1
|
||||
VotingPower: int64(rand.Intn(99) + 1),
|
||||
}
|
||||
}
|
||||
|
||||
// sort validators by address, which is what NewValidatorSet also does
|
||||
sort.Sort(ValidatorsByAddress(validators))
|
||||
sort.Sort(valset.ValidatorsByAddress(validators))
|
||||
|
||||
return validators
|
||||
}
|
||||
|
|
@ -144,3 +149,51 @@ func randomAddress() common.Address {
|
|||
|
||||
return common.BytesToAddress(bytes)
|
||||
}
|
||||
|
||||
func randomAddresses(n int) []common.Address {
|
||||
if n <= 0 {
|
||||
return []common.Address{}
|
||||
}
|
||||
|
||||
addrs := make([]common.Address, 0, n)
|
||||
addrsSet := make(map[common.Address]struct{}, n)
|
||||
|
||||
var (
|
||||
addr common.Address
|
||||
exist bool
|
||||
)
|
||||
|
||||
bytes := make([]byte, 32)
|
||||
|
||||
for {
|
||||
rand.Read(bytes)
|
||||
|
||||
addr = common.BytesToAddress(bytes)
|
||||
|
||||
_, exist = addrsSet[addr]
|
||||
if !exist {
|
||||
addrs = append(addrs, addr)
|
||||
|
||||
addrsSet[addr] = struct{}{}
|
||||
}
|
||||
|
||||
if len(addrs) == n {
|
||||
return addrs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomAddresses(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rapid.Check(t, func(t *rapid.T) {
|
||||
length := rapid.IntMax(100).Draw(t, "length").(int)
|
||||
|
||||
addrs := randomAddresses(length)
|
||||
addressSet := unique.New(addrs)
|
||||
|
||||
if len(addrs) != len(addressSet) {
|
||||
t.Fatalf("length of unique addresses %d, expected %d", len(addressSet), len(addrs))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
package bor
|
||||
|
||||
// Span represents a current bor span
|
||||
type Span struct {
|
||||
ID uint64 `json:"span_id" yaml:"span_id"`
|
||||
StartBlock uint64 `json:"start_block" yaml:"start_block"`
|
||||
EndBlock uint64 `json:"end_block" yaml:"end_block"`
|
||||
}
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// HeimdallSpan represents span from heimdall APIs
|
||||
type HeimdallSpan struct {
|
||||
Span
|
||||
ValidatorSet ValidatorSet `json:"validator_set" yaml:"validator_set"`
|
||||
SelectedProducers []Validator `json:"selected_producers" yaml:"selected_producers"`
|
||||
ChainID string `json:"bor_chain_id" yaml:"bor_chain_id"`
|
||||
//go:generate mockgen -destination=./span_mock.go -package=bor . Spanner
|
||||
type Spanner interface {
|
||||
GetCurrentSpan(headerHash common.Hash) (*span.Span, error)
|
||||
GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error)
|
||||
CommitSpan(heimdallSpan span.HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error
|
||||
}
|
||||
|
|
|
|||
84
consensus/bor/span_mock.go
Normal file
84
consensus/bor/span_mock.go
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: Spanner)
|
||||
|
||||
// Package bor is a generated GoMock package.
|
||||
package bor
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
common "github.com/ethereum/go-ethereum/common"
|
||||
span "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
valset "github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
core "github.com/ethereum/go-ethereum/core"
|
||||
state "github.com/ethereum/go-ethereum/core/state"
|
||||
types "github.com/ethereum/go-ethereum/core/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockSpanner is a mock of Spanner interface.
|
||||
type MockSpanner struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSpannerMockRecorder
|
||||
}
|
||||
|
||||
// MockSpannerMockRecorder is the mock recorder for MockSpanner.
|
||||
type MockSpannerMockRecorder struct {
|
||||
mock *MockSpanner
|
||||
}
|
||||
|
||||
// NewMockSpanner creates a new mock instance.
|
||||
func NewMockSpanner(ctrl *gomock.Controller) *MockSpanner {
|
||||
mock := &MockSpanner{ctrl: ctrl}
|
||||
mock.recorder = &MockSpannerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSpanner) EXPECT() *MockSpannerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CommitSpan mocks base method.
|
||||
func (m *MockSpanner) CommitSpan(arg0 span.HeimdallSpan, arg1 *state.StateDB, arg2 *types.Header, arg3 core.ChainContext) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CommitSpan", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CommitSpan indicates an expected call of CommitSpan.
|
||||
func (mr *MockSpannerMockRecorder) CommitSpan(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// GetCurrentSpan mocks base method.
|
||||
func (m *MockSpanner) GetCurrentSpan(arg0 common.Hash) (*span.Span, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetCurrentSpan", arg0)
|
||||
ret0, _ := ret[0].(*span.Span)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetCurrentSpan indicates an expected call of GetCurrentSpan.
|
||||
func (mr *MockSpannerMockRecorder) GetCurrentSpan(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), arg0)
|
||||
}
|
||||
|
||||
// GetCurrentValidators mocks base method.
|
||||
func (m *MockSpanner) GetCurrentValidators(arg0 common.Hash, arg1 uint64) ([]*valset.Validator, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetCurrentValidators", arg0, arg1)
|
||||
ret0, _ := ret[0].([]*valset.Validator)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetCurrentValidators indicates an expected call of GetCurrentValidators.
|
||||
func (mr *MockSpannerMockRecorder) GetCurrentValidators(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidators", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidators), arg0, arg1)
|
||||
}
|
||||
93
consensus/bor/statefull/processor.go
Normal file
93
consensus/bor/statefull/processor.go
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
package statefull
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE")
|
||||
|
||||
type ChainContext struct {
|
||||
Chain consensus.ChainHeaderReader
|
||||
Bor consensus.Engine
|
||||
}
|
||||
|
||||
func (c ChainContext) Engine() consensus.Engine {
|
||||
return c.Bor
|
||||
}
|
||||
|
||||
func (c ChainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
|
||||
return c.Chain.GetHeader(hash, number)
|
||||
}
|
||||
|
||||
// callmsg implements core.Message to allow passing it as a transaction simulator.
|
||||
type callmsg struct {
|
||||
ethereum.CallMsg
|
||||
}
|
||||
|
||||
func (m callmsg) From() common.Address { return m.CallMsg.From }
|
||||
func (m callmsg) Nonce() uint64 { return 0 }
|
||||
func (m callmsg) CheckNonce() bool { return false }
|
||||
func (m callmsg) To() *common.Address { return m.CallMsg.To }
|
||||
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||
func (m callmsg) Gas() uint64 { return m.CallMsg.Gas }
|
||||
func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
|
||||
func (m callmsg) Data() []byte { return m.CallMsg.Data }
|
||||
|
||||
// get system message
|
||||
func GetSystemMessage(toAddress common.Address, data []byte) callmsg {
|
||||
return callmsg{
|
||||
ethereum.CallMsg{
|
||||
From: systemAddress,
|
||||
Gas: math.MaxUint64 / 2,
|
||||
GasPrice: big.NewInt(0),
|
||||
Value: big.NewInt(0),
|
||||
To: &toAddress,
|
||||
Data: data,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// apply message
|
||||
func ApplyMessage(
|
||||
msg callmsg,
|
||||
state *state.StateDB,
|
||||
header *types.Header,
|
||||
chainConfig *params.ChainConfig,
|
||||
chainContext core.ChainContext,
|
||||
) (uint64, error) {
|
||||
initialGas := msg.Gas()
|
||||
|
||||
// Create a new context to be used in the EVM environment
|
||||
blockContext := core.NewEVMBlockContext(header, chainContext, &header.Coinbase)
|
||||
|
||||
// Create a new environment which holds all relevant information
|
||||
// about the transaction and calling mechanisms.
|
||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, state, chainConfig, vm.Config{})
|
||||
|
||||
// Apply the transaction to the current state (included in the env)
|
||||
_, gasLeft, err := vmenv.Call(
|
||||
vm.AccountRef(msg.From()),
|
||||
*msg.To(),
|
||||
msg.Data(),
|
||||
msg.Gas(),
|
||||
msg.Value(),
|
||||
)
|
||||
// Update the state with pending changes
|
||||
if err != nil {
|
||||
state.Finalise(true)
|
||||
}
|
||||
|
||||
gasUsed := initialGas - gasLeft
|
||||
|
||||
return gasUsed, nil
|
||||
}
|
||||
11
consensus/bor/validators_getter.go
Normal file
11
consensus/bor/validators_getter.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package bor
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=./validators_getter_mock.go -package=bor . ValidatorsGetter
|
||||
type ValidatorsGetter interface {
|
||||
GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error)
|
||||
}
|
||||
51
consensus/bor/validators_getter_mock.go
Normal file
51
consensus/bor/validators_getter_mock.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: ValidatorsGetter)
|
||||
|
||||
// Package bor is a generated GoMock package.
|
||||
package bor
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
common "github.com/ethereum/go-ethereum/common"
|
||||
valset "github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockValidatorsGetter is a mock of ValidatorsGetter interface.
|
||||
type MockValidatorsGetter struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockValidatorsGetterMockRecorder
|
||||
}
|
||||
|
||||
// MockValidatorsGetterMockRecorder is the mock recorder for MockValidatorsGetter.
|
||||
type MockValidatorsGetterMockRecorder struct {
|
||||
mock *MockValidatorsGetter
|
||||
}
|
||||
|
||||
// NewMockValidatorsGetter creates a new mock instance.
|
||||
func NewMockValidatorsGetter(ctrl *gomock.Controller) *MockValidatorsGetter {
|
||||
mock := &MockValidatorsGetter{ctrl: ctrl}
|
||||
mock.recorder = &MockValidatorsGetterMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockValidatorsGetter) EXPECT() *MockValidatorsGetterMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetCurrentValidators mocks base method.
|
||||
func (m *MockValidatorsGetter) GetCurrentValidators(arg0 common.Hash, arg1 uint64) ([]*valset.Validator, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetCurrentValidators", arg0, arg1)
|
||||
ret0, _ := ret[0].([]*valset.Validator)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetCurrentValidators indicates an expected call of GetCurrentValidators.
|
||||
func (mr *MockValidatorsGetterMockRecorder) GetCurrentValidators(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidators", reflect.TypeOf((*MockValidatorsGetter)(nil).GetCurrentValidators), arg0, arg1)
|
||||
}
|
||||
32
consensus/bor/valset/error.go
Normal file
32
consensus/bor/valset/error.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package valset
|
||||
|
||||
import "fmt"
|
||||
|
||||
// TotalVotingPowerExceededError is returned when the maximum allowed total voting power is exceeded
|
||||
type TotalVotingPowerExceededError struct {
|
||||
Sum int64
|
||||
Validators []*Validator
|
||||
}
|
||||
|
||||
func (e *TotalVotingPowerExceededError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"Total voting power should be guarded to not exceed %v; got: %v; for validator set: %v",
|
||||
MaxTotalVotingPower,
|
||||
e.Sum,
|
||||
e.Validators,
|
||||
)
|
||||
}
|
||||
|
||||
type InvalidStartEndBlockError struct {
|
||||
Start uint64
|
||||
End uint64
|
||||
CurrentHeader uint64
|
||||
}
|
||||
|
||||
func (e *InvalidStartEndBlockError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"Invalid parameters start: %d and end block: %d params",
|
||||
e.Start,
|
||||
e.End,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
package bor
|
||||
package valset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
// "encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package bor
|
||||
package valset
|
||||
|
||||
// Tendermint leader selection algorithm
|
||||
|
||||
|
|
@ -55,8 +55,8 @@ type ValidatorSet struct {
|
|||
// function panics.
|
||||
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
||||
vals := &ValidatorSet{}
|
||||
err := vals.updateWithChangeSet(valz, false)
|
||||
|
||||
err := vals.updateWithChangeSet(valz, false)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("cannot create validator set: %s", err))
|
||||
}
|
||||
|
|
@ -281,7 +281,7 @@ func (vals *ValidatorSet) Size() int {
|
|||
}
|
||||
|
||||
// Force recalculation of the set's total voting power.
|
||||
func (vals *ValidatorSet) updateTotalVotingPower() error {
|
||||
func (vals *ValidatorSet) UpdateTotalVotingPower() error {
|
||||
sum := int64(0)
|
||||
for _, val := range vals.Validators {
|
||||
// mind overflow
|
||||
|
|
@ -302,7 +302,7 @@ func (vals *ValidatorSet) TotalVotingPower() int64 {
|
|||
if vals.totalVotingPower == 0 {
|
||||
log.Info("invoking updateTotalVotingPower before returning it")
|
||||
|
||||
if err := vals.updateTotalVotingPower(); err != nil {
|
||||
if err := vals.UpdateTotalVotingPower(); err != nil {
|
||||
// Can/should we do better?
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -602,7 +602,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
|
|||
vals.applyUpdates(updates)
|
||||
vals.applyRemovals(deletes)
|
||||
|
||||
if err := vals.updateTotalVotingPower(); err != nil {
|
||||
if err := vals.UpdateTotalVotingPower(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -45,12 +45,14 @@ type Merger struct {
|
|||
// NewMerger creates a new Merger which stores its transition status in the provided db.
|
||||
func NewMerger(db ethdb.KeyValueStore) *Merger {
|
||||
var status transitionStatus
|
||||
|
||||
blob := rawdb.ReadTransitionStatus(db)
|
||||
if len(blob) != 0 {
|
||||
if err := rlp.DecodeBytes(blob, &status); err != nil {
|
||||
log.Crit("Failed to decode the transition status", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &Merger{
|
||||
db: db,
|
||||
status: status,
|
||||
|
|
|
|||
|
|
@ -305,7 +305,8 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
|||
}
|
||||
makeChainForBench(db, full, count)
|
||||
db.Close()
|
||||
cacheConfig := *defaultCacheConfig
|
||||
|
||||
cacheConfig := *DefaultCacheConfig
|
||||
cacheConfig.TrieDirtyDisabled = true
|
||||
|
||||
b.ReportAllocs()
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
"github.com/ethereum/go-ethereum/common/prque"
|
||||
|
|
@ -43,7 +45,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -133,9 +134,9 @@ type CacheConfig struct {
|
|||
SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it
|
||||
}
|
||||
|
||||
// defaultCacheConfig are the default caching values if none are specified by the
|
||||
// DefaultCacheConfig are the default caching values if none are specified by the
|
||||
// user (also used during testing).
|
||||
var defaultCacheConfig = &CacheConfig{
|
||||
var DefaultCacheConfig = &CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
|
|
@ -222,7 +223,7 @@ type BlockChain struct {
|
|||
// and Processor.
|
||||
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) {
|
||||
if cacheConfig == nil {
|
||||
cacheConfig = defaultCacheConfig
|
||||
cacheConfig = DefaultCacheConfig
|
||||
}
|
||||
bodyCache, _ := lru.New(bodyCacheLimit)
|
||||
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
|
@ -397,10 +398,25 @@ func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscr
|
|||
return bc.scope.Track(bc.blockProcFeed.Subscribe(ch))
|
||||
}
|
||||
|
||||
// Snaps retrieves the snapshot tree.
|
||||
func (bc *BlockChain) Snaps() *snapshot.Tree {
|
||||
return bc.snaps
|
||||
}
|
||||
|
||||
// DB retrieves the blockchain database.
|
||||
func (bc *BlockChain) DB() ethdb.Database {
|
||||
return bc.db
|
||||
}
|
||||
|
||||
//
|
||||
// Bor related changes
|
||||
//
|
||||
|
||||
type BorStateSyncer interface {
|
||||
SetStateSync(stateData []*types.StateSyncData)
|
||||
SubscribeStateSyncEvent(ch chan<- StateSyncEvent) event.Subscription
|
||||
}
|
||||
|
||||
// SetStateSync set sync data in state_data
|
||||
func (bc *BlockChain) SetStateSync(stateData []*types.StateSyncData) {
|
||||
bc.stateSyncData = stateData
|
||||
|
|
|
|||
|
|
@ -920,7 +920,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
|||
archiveDb, delfn := makeDb()
|
||||
defer delfn()
|
||||
|
||||
archiveCaching := *defaultCacheConfig
|
||||
archiveCaching := *DefaultCacheConfig
|
||||
archiveCaching.TrieDirtyDisabled = true
|
||||
|
||||
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
|
|
@ -335,6 +336,9 @@ func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethd
|
|||
|
||||
type fakeChainReader struct {
|
||||
config *params.ChainConfig
|
||||
stateSyncData []*types.StateSyncData
|
||||
stateSyncFeed event.Feed
|
||||
scope event.SubscriptionScope
|
||||
}
|
||||
|
||||
// Config returns the chain configuration.
|
||||
|
|
@ -348,3 +352,13 @@ func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header
|
|||
func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil }
|
||||
func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil }
|
||||
func (cr *fakeChainReader) GetTd(hash common.Hash, number uint64) *big.Int { return nil }
|
||||
|
||||
// SetStateSync set sync data in state_data
|
||||
func (cr *fakeChainReader) SetStateSync(stateData []*types.StateSyncData) {
|
||||
cr.stateSyncData = stateData
|
||||
}
|
||||
|
||||
// SubscribeStateSyncEvent registers a subscription of StateSyncEvent.
|
||||
func (cr *fakeChainReader) SubscribeStateSyncEvent(ch chan<- StateSyncEvent) event.Subscription {
|
||||
return cr.scope.Track(cr.stateSyncFeed.Subscribe(ch))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import (
|
|||
"math/big"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
|
|
@ -32,7 +34,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// TestStateProcessorErrors tests the output from the 'core' errors
|
||||
|
|
@ -308,7 +309,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
|
|||
header := &types.Header{
|
||||
ParentHash: parent.Hash(),
|
||||
Coinbase: parent.Coinbase(),
|
||||
Difficulty: engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{
|
||||
Difficulty: engine.CalcDifficulty(&fakeChainReader{config: config}, parent.Time()+10, &types.Header{
|
||||
Number: parent.Number(),
|
||||
Time: parent.Time(),
|
||||
Difficulty: parent.Difficulty(),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
// the database in some strange state with gaps in the chain, nor with block data
|
||||
// dangling in the future.
|
||||
|
||||
package core
|
||||
package tests
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
|
@ -27,12 +27,22 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/api"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/miner"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||
)
|
||||
|
||||
// Tests a recovery for a short canonical chain where a recent block was already
|
||||
|
|
@ -1750,7 +1760,17 @@ func testLongReorgedSnapSyncingDeepRepair(t *testing.T, snapshots bool) {
|
|||
}, snapshots)
|
||||
}
|
||||
|
||||
var (
|
||||
testKey1, _ = crypto.GenerateKey()
|
||||
testAddress1 = crypto.PubkeyToAddress(testKey1.PublicKey)
|
||||
|
||||
testKey2, _ = crypto.GenerateKey()
|
||||
testAddress2 = crypto.PubkeyToAddress(testKey2.PublicKey) //nolint:unused,varcheck
|
||||
)
|
||||
|
||||
func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
t.Skip("need to add a proper signer for Bor consensus")
|
||||
|
||||
// It's hard to follow the test case, visualize the input
|
||||
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// fmt.Println(tt.dump(true))
|
||||
|
|
@ -1768,47 +1788,104 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
}
|
||||
defer db.Close() // Might double close, should be fine
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ethAPIMock := api.NewMockCaller(ctrl)
|
||||
ethAPIMock.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
spanner := bor.NewMockSpanner(ctrl)
|
||||
spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
{
|
||||
ID: 0,
|
||||
Address: common.Address{0x1},
|
||||
VotingPower: 100,
|
||||
ProposerPriority: 0,
|
||||
},
|
||||
}, nil).AnyTimes()
|
||||
|
||||
heimdallClientMock := mocks.NewMockIHeimdallClient(ctrl)
|
||||
heimdallClientMock.EXPECT().Close().Times(1)
|
||||
|
||||
contractMock := bor.NewMockGenesisContract(ctrl)
|
||||
|
||||
// Initialize a fresh chain
|
||||
var (
|
||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||
engine = ethash.NewFullFaker()
|
||||
config = &CacheConfig{
|
||||
gspec = &core.Genesis{
|
||||
Config: params.BorUnittestChainConfig,
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
config = &core.CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 0, // Disable snapshot by default
|
||||
}
|
||||
)
|
||||
|
||||
engine := miner.NewFakeBor(t, db, params.BorUnittestChainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock)
|
||||
defer engine.Close()
|
||||
|
||||
engineBorInternal, ok := engine.(*bor.Bor)
|
||||
if ok {
|
||||
gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength)
|
||||
copy(gspec.ExtraData[32:32+common.AddressLength], testAddress1.Bytes())
|
||||
|
||||
engineBorInternal.Authorize(testAddress1, func(account accounts.Account, s string, data []byte) ([]byte, error) {
|
||||
return crypto.Sign(crypto.Keccak256(data), testKey1)
|
||||
})
|
||||
}
|
||||
|
||||
genesis := gspec.MustCommit(db)
|
||||
|
||||
if snapshots {
|
||||
config.SnapshotLimit = 256
|
||||
config.SnapshotWait = true
|
||||
}
|
||||
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
|
||||
chain, err := core.NewBlockChain(db, config, params.BorUnittestChainConfig, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
|
||||
// If sidechain blocks are needed, make a light chain and import it
|
||||
var sideblocks types.Blocks
|
||||
if tt.sidechainBlocks > 0 {
|
||||
sideblocks, _ = GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{0x01})
|
||||
sideblocks, _ = core.GenerateChain(params.BorUnittestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *core.BlockGen) {
|
||||
b.SetCoinbase(testAddress1)
|
||||
|
||||
if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.Sprint) {
|
||||
b.SetExtra(gspec.ExtraData)
|
||||
} else {
|
||||
b.SetExtra(make([]byte, 32+crypto.SignatureLength))
|
||||
}
|
||||
})
|
||||
if _, err := chain.InsertChain(sideblocks); err != nil {
|
||||
t.Fatalf("Failed to import side chain: %v", err)
|
||||
}
|
||||
}
|
||||
canonblocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *BlockGen) {
|
||||
|
||||
canonblocks, _ := core.GenerateChain(params.BorUnittestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *core.BlockGen) {
|
||||
b.SetCoinbase(common.Address{0x02})
|
||||
b.SetDifficulty(big.NewInt(1000000))
|
||||
|
||||
if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.Sprint) {
|
||||
b.SetExtra(gspec.ExtraData)
|
||||
} else {
|
||||
b.SetExtra(make([]byte, 32+crypto.SignatureLength))
|
||||
}
|
||||
})
|
||||
if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
if tt.commitBlock > 0 {
|
||||
chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil)
|
||||
err = chain.StateCache().TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil)
|
||||
if err != nil {
|
||||
t.Fatal("on trieDB.Commit", err)
|
||||
}
|
||||
|
||||
if snapshots {
|
||||
if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
||||
if err := chain.Snaps().Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
||||
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -1837,7 +1914,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
}
|
||||
defer db.Close()
|
||||
|
||||
newChain, err := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
newChain, err := core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -1888,19 +1965,21 @@ func TestIssue23496(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create temporary datadir: %v", err)
|
||||
}
|
||||
|
||||
os.RemoveAll(datadir)
|
||||
|
||||
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
}
|
||||
|
||||
defer db.Close() // Might double close, should be fine
|
||||
|
||||
// Initialize a fresh chain
|
||||
var (
|
||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||
genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||
engine = ethash.NewFullFaker()
|
||||
config = &CacheConfig{
|
||||
config = &core.CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
|
|
@ -1908,11 +1987,13 @@ func TestIssue23496(t *testing.T) {
|
|||
SnapshotWait: true,
|
||||
}
|
||||
)
|
||||
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
|
||||
chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), 4, func(i int, b *BlockGen) {
|
||||
|
||||
blocks, _ := core.GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), 4, func(i int, b *core.BlockGen) {
|
||||
b.SetCoinbase(common.Address{0x02})
|
||||
b.SetDifficulty(big.NewInt(1000000))
|
||||
})
|
||||
|
|
@ -1921,13 +2002,18 @@ func TestIssue23496(t *testing.T) {
|
|||
if _, err := chain.InsertChain(blocks[:1]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
chain.stateCache.TrieDB().Commit(blocks[0].Root(), true, nil)
|
||||
|
||||
err = chain.StateCache().TrieDB().Commit(blocks[0].Root(), true, nil)
|
||||
if err != nil {
|
||||
t.Fatal("on trieDB.Commit", err)
|
||||
}
|
||||
|
||||
// Insert block B2 and commit the snapshot into disk
|
||||
if _, err := chain.InsertChain(blocks[1:2]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
if err := chain.snaps.Cap(blocks[1].Root(), 0); err != nil {
|
||||
|
||||
if err := chain.Snaps().Cap(blocks[1].Root(), 0); err != nil {
|
||||
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -1935,7 +2021,11 @@ func TestIssue23496(t *testing.T) {
|
|||
if _, err := chain.InsertChain(blocks[2:3]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
chain.stateCache.TrieDB().Commit(blocks[2].Root(), true, nil)
|
||||
|
||||
err = chain.StateCache().TrieDB().Commit(blocks[2].Root(), true, nil)
|
||||
if err != nil {
|
||||
t.Fatal("on trieDB.Commit", err)
|
||||
}
|
||||
|
||||
// Insert the remaining blocks
|
||||
if _, err := chain.InsertChain(blocks[3:]); err != nil {
|
||||
|
|
@ -1950,20 +2040,24 @@ func TestIssue23496(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
chain, err = NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
chain, err = core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
||||
defer chain.Stop()
|
||||
|
||||
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
||||
}
|
||||
|
||||
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
||||
}
|
||||
|
||||
if head := chain.CurrentBlock(); head.NumberU64() != uint64(1) {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(1))
|
||||
}
|
||||
|
|
@ -1972,15 +2066,19 @@ func TestIssue23496(t *testing.T) {
|
|||
if _, err := chain.InsertChain(blocks[1:]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
||||
}
|
||||
|
||||
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
||||
}
|
||||
|
||||
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
||||
}
|
||||
|
||||
if head := chain.CurrentBlock(); head.NumberU64() != uint64(4) {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
||||
}
|
||||
|
||||
if layer := chain.Snapshots().Snapshot(blocks[2].Root()); layer == nil {
|
||||
t.Error("Failed to regenerate the snapshot of known state")
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
// Tests that setting the chain head backwards doesn't leave the database in some
|
||||
// strange state with gaps in the chain, nor with block data dangling in the future.
|
||||
|
||||
package core
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -30,6 +30,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
|
|
@ -1959,79 +1960,98 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create temporary datadir: %v", err)
|
||||
}
|
||||
|
||||
os.RemoveAll(datadir)
|
||||
|
||||
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
// Initialize a fresh chain
|
||||
var (
|
||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||
genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||
engine = ethash.NewFullFaker()
|
||||
config = &CacheConfig{
|
||||
config = &core.CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 0, // Disable snapshot
|
||||
}
|
||||
)
|
||||
|
||||
if snapshots {
|
||||
config.SnapshotLimit = 256
|
||||
config.SnapshotWait = true
|
||||
}
|
||||
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
|
||||
chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
|
||||
// If sidechain blocks are needed, make a light chain and import it
|
||||
var sideblocks types.Blocks
|
||||
if tt.sidechainBlocks > 0 {
|
||||
sideblocks, _ = GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) {
|
||||
sideblocks, _ = core.GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *core.BlockGen) {
|
||||
b.SetCoinbase(common.Address{0x01})
|
||||
})
|
||||
|
||||
if _, err := chain.InsertChain(sideblocks); err != nil {
|
||||
t.Fatalf("Failed to import side chain: %v", err)
|
||||
}
|
||||
}
|
||||
canonblocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *BlockGen) {
|
||||
|
||||
canonblocks, _ := core.GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *core.BlockGen) {
|
||||
b.SetCoinbase(common.Address{0x02})
|
||||
b.SetDifficulty(big.NewInt(1000000))
|
||||
})
|
||||
|
||||
if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
|
||||
if tt.commitBlock > 0 {
|
||||
chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil)
|
||||
err = chain.StateCache().TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil)
|
||||
if err != nil {
|
||||
t.Fatal("on trieDB.Commit", err)
|
||||
}
|
||||
|
||||
if snapshots {
|
||||
if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
||||
if err := chain.Snaps().Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
||||
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
||||
}
|
||||
|
||||
// Manually dereference anything not committed to not have to work with 128+ tries
|
||||
for _, block := range sideblocks {
|
||||
chain.stateCache.TrieDB().Dereference(block.Root())
|
||||
chain.StateCache().TrieDB().Dereference(block.Root())
|
||||
}
|
||||
|
||||
for _, block := range canonblocks {
|
||||
chain.stateCache.TrieDB().Dereference(block.Root())
|
||||
chain.StateCache().TrieDB().Dereference(block.Root())
|
||||
}
|
||||
|
||||
// Force run a freeze cycle
|
||||
type freezer interface {
|
||||
Freeze(threshold uint64) error
|
||||
Ancients() (uint64, error)
|
||||
}
|
||||
|
||||
db.(freezer).Freeze(tt.freezeThreshold)
|
||||
|
||||
// Set the simulated pivot block
|
||||
if tt.pivotBlock != nil {
|
||||
rawdb.WriteLastPivotNumber(db, *tt.pivotBlock)
|
||||
}
|
||||
|
||||
// Set the head of the chain back to the requested number
|
||||
chain.SetHead(tt.setheadBlock)
|
||||
|
||||
|
|
@ -2044,12 +2064,15 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
if head := chain.CurrentHeader(); head.Number.Uint64() != tt.expHeadHeader {
|
||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader)
|
||||
}
|
||||
|
||||
if head := chain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadFastBlock)
|
||||
}
|
||||
|
||||
if head := chain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock)
|
||||
}
|
||||
|
||||
if frozen, err := db.(freezer).Ancients(); err != nil {
|
||||
t.Errorf("Failed to retrieve ancient count: %v\n", err)
|
||||
} else if int(frozen) != tt.expFrozen {
|
||||
|
|
@ -2059,7 +2082,8 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
|
||||
// verifyNoGaps checks that there are no gaps after the initial set of blocks in
|
||||
// the database and errors if found.
|
||||
func verifyNoGaps(t *testing.T, chain *BlockChain, canonical bool, inserted types.Blocks) {
|
||||
//nolint:gocognit
|
||||
func verifyNoGaps(t *testing.T, chain *core.BlockChain, canonical bool, inserted types.Blocks) {
|
||||
t.Helper()
|
||||
|
||||
var end uint64
|
||||
|
|
@ -2111,7 +2135,8 @@ func verifyNoGaps(t *testing.T, chain *BlockChain, canonical bool, inserted type
|
|||
|
||||
// verifyCutoff checks that there are no chain data available in the chain after
|
||||
// the specified limit, but that it is available before.
|
||||
func verifyCutoff(t *testing.T, chain *BlockChain, canonical bool, inserted types.Blocks, head int) {
|
||||
//nolint:gocognit
|
||||
func verifyCutoff(t *testing.T, chain *core.BlockChain, canonical bool, inserted types.Blocks, head int) {
|
||||
t.Helper()
|
||||
|
||||
for i := 1; i <= len(inserted); i++ {
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
// Tests that abnormal program termination (i.e.crash) and restart can recovery
|
||||
// the snapshot properly if the snapshot is enabled.
|
||||
|
||||
package core
|
||||
package tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
|
@ -31,6 +31,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
|
|
@ -57,7 +58,9 @@ type snapshotTestBasic struct {
|
|||
engine consensus.Engine
|
||||
}
|
||||
|
||||
func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) {
|
||||
func (basic *snapshotTestBasic) prepare(t *testing.T) (*core.BlockChain, []*types.Block) {
|
||||
t.Helper()
|
||||
|
||||
// Create a temporary persistent database
|
||||
datadir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
|
|
@ -71,20 +74,22 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
|||
}
|
||||
// Initialize a fresh chain
|
||||
var (
|
||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||
genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||
engine = ethash.NewFullFaker()
|
||||
gendb = rawdb.NewMemoryDatabase()
|
||||
|
||||
// Snapshot is enabled, the first snapshot is created from the Genesis.
|
||||
// The snapshot memory allowance is 256MB, it means no snapshot flush
|
||||
// will happen during the block insertion.
|
||||
cacheConfig = defaultCacheConfig
|
||||
cacheConfig = core.DefaultCacheConfig
|
||||
)
|
||||
chain, err := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
|
||||
chain, err := core.NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, gendb, basic.chainBlocks, func(i int, b *BlockGen) {})
|
||||
|
||||
blocks, _ := core.GenerateChain(params.TestChainConfig, genesis, engine, gendb, basic.chainBlocks, func(i int, b *core.BlockGen) {})
|
||||
|
||||
// Insert the blocks with configured settings.
|
||||
var breakpoints []uint64
|
||||
|
|
@ -93,27 +98,39 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
|||
} else {
|
||||
breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock)
|
||||
}
|
||||
|
||||
var startPoint uint64
|
||||
|
||||
for _, point := range breakpoints {
|
||||
if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
|
||||
startPoint = point
|
||||
|
||||
if basic.commitBlock > 0 && basic.commitBlock == point {
|
||||
chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), true, nil)
|
||||
err = chain.StateCache().TrieDB().Commit(blocks[point-1].Root(), true, nil)
|
||||
if err != nil {
|
||||
t.Fatal("on trieDB.Commit", err)
|
||||
}
|
||||
}
|
||||
|
||||
if basic.snapshotBlock > 0 && basic.snapshotBlock == point {
|
||||
// Flushing the entire snap tree into the disk, the
|
||||
// relevant (a) snapshot root and (b) snapshot generator
|
||||
// will be persisted atomically.
|
||||
chain.snaps.Cap(blocks[point-1].Root(), 0)
|
||||
diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root()
|
||||
err = chain.Snaps().Cap(blocks[point-1].Root(), 0)
|
||||
if err != nil {
|
||||
t.Fatal("on Snaps.Cap", err)
|
||||
}
|
||||
|
||||
diskRoot, blockRoot := chain.Snaps().DiskRoot(), blocks[point-1].Root()
|
||||
if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) {
|
||||
t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := chain.InsertChain(blocks[startPoint:]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
||||
}
|
||||
|
|
@ -123,10 +140,13 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
|||
basic.db = db
|
||||
basic.gendb = gendb
|
||||
basic.engine = engine
|
||||
|
||||
return chain, blocks
|
||||
}
|
||||
|
||||
func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks []*types.Block) {
|
||||
func (basic *snapshotTestBasic) verify(t *testing.T, chain *core.BlockChain, blocks []*types.Block) {
|
||||
t.Helper()
|
||||
|
||||
// Iterate over all the remaining blocks and ensure there are no gaps
|
||||
verifyNoGaps(t, chain, true, blocks)
|
||||
verifyCutoff(t, chain, true, blocks, basic.expCanonicalBlocks)
|
||||
|
|
@ -134,9 +154,11 @@ func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks [
|
|||
if head := chain.CurrentHeader(); head.Number.Uint64() != basic.expHeadHeader {
|
||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader)
|
||||
}
|
||||
|
||||
if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadFastBlock)
|
||||
}
|
||||
|
||||
if head := chain.CurrentBlock(); head.NumberU64() != basic.expHeadBlock {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadBlock)
|
||||
}
|
||||
|
|
@ -145,12 +167,12 @@ func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks [
|
|||
block := chain.GetBlockByNumber(basic.expSnapshotBottom)
|
||||
if block == nil {
|
||||
t.Errorf("The correspnding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom)
|
||||
} else if !bytes.Equal(chain.snaps.DiskRoot().Bytes(), block.Root().Bytes()) {
|
||||
t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.snaps.DiskRoot())
|
||||
} else if !bytes.Equal(chain.Snaps().DiskRoot().Bytes(), block.Root().Bytes()) {
|
||||
t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.Snaps().DiskRoot())
|
||||
}
|
||||
|
||||
// Check the snapshot, ensure it's integrated
|
||||
if err := chain.snaps.Verify(block.Root()); err != nil {
|
||||
if err := chain.Snaps().Verify(block.Root()); err != nil {
|
||||
t.Errorf("The disk layer is not integrated %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -223,10 +245,12 @@ func (snaptest *snapshotTest) test(t *testing.T) {
|
|||
|
||||
// Restart the chain normally
|
||||
chain.Stop()
|
||||
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
|
||||
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
||||
defer newchain.Stop()
|
||||
|
||||
snaptest.verify(t, newchain, blocks)
|
||||
|
|
@ -245,7 +269,7 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
|||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Pull the plug on the database, simulating a hard crash
|
||||
db := chain.db
|
||||
db := chain.DB()
|
||||
db.Close()
|
||||
|
||||
// Start a new blockchain back up and see where the repair leads us
|
||||
|
|
@ -259,13 +283,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
|||
// the crash, we do restart twice here: one after the crash and one
|
||||
// after the normal stop. It's used to ensure the broken snapshot
|
||||
// can be detected all the time.
|
||||
newchain, err := NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err := core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
newchain.Stop()
|
||||
|
||||
newchain, err = NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err = core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -292,27 +316,31 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
|||
|
||||
// Insert blocks without enabling snapshot if gapping is required.
|
||||
chain.Stop()
|
||||
gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.gapped, func(i int, b *BlockGen) {})
|
||||
|
||||
gappedBlocks, _ := core.GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.gapped, func(i int, b *core.BlockGen) {})
|
||||
|
||||
// Insert a few more blocks without enabling snapshot
|
||||
var cacheConfig = &CacheConfig{
|
||||
var cacheConfig = &core.CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 0,
|
||||
}
|
||||
newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
|
||||
newchain, err := core.NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
||||
newchain.InsertChain(gappedBlocks)
|
||||
newchain.Stop()
|
||||
|
||||
// Restart the chain with enabling the snapshot
|
||||
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
||||
defer newchain.Stop()
|
||||
|
||||
snaptest.verify(t, newchain, blocks)
|
||||
|
|
@ -337,7 +365,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
|
|||
chain.SetHead(snaptest.setHead)
|
||||
chain.Stop()
|
||||
|
||||
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -368,11 +396,12 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
|
|||
// and state committed.
|
||||
chain.Stop()
|
||||
|
||||
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {})
|
||||
|
||||
newBlocks, _ := core.GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *core.BlockGen) {})
|
||||
newchain.InsertChain(newBlocks)
|
||||
|
||||
// Commit the entire snapshot into the disk if requested. Note only
|
||||
|
|
@ -385,7 +414,7 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
|
|||
// journal and latest state will be committed
|
||||
|
||||
// Restart the chain after the crash
|
||||
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -414,38 +443,42 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
|||
// and state committed.
|
||||
chain.Stop()
|
||||
|
||||
config := &CacheConfig{
|
||||
config := &core.CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 0,
|
||||
}
|
||||
newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
|
||||
newchain, err := core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {})
|
||||
|
||||
newBlocks, _ := core.GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *core.BlockGen) {})
|
||||
newchain.InsertChain(newBlocks)
|
||||
newchain.Stop()
|
||||
|
||||
// Restart the chain, the wiper should starts working
|
||||
config = &CacheConfig{
|
||||
config = &core.CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 256,
|
||||
SnapshotWait: false, // Don't wait rebuild
|
||||
}
|
||||
newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
|
||||
_, err = core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
// Simulate the blockchain crash.
|
||||
|
||||
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
||||
snaptest.verify(t, newchain, blocks)
|
||||
}
|
||||
|
||||
|
|
@ -183,7 +183,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
// END: Bor changes
|
||||
|
||||
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
|
||||
var dbVer = "<nil>"
|
||||
dbVer := "<nil>"
|
||||
if bcVersion != nil {
|
||||
dbVer = fmt.Sprintf("%d", *bcVersion)
|
||||
}
|
||||
|
|
@ -471,8 +471,10 @@ func (s *Ethereum) StartMining(threads int) error {
|
|||
if threads == 0 {
|
||||
threads = -1 // Disable the miner from within
|
||||
}
|
||||
|
||||
th.SetThreads(threads)
|
||||
}
|
||||
|
||||
// If the miner was not running, initialize it
|
||||
if !s.IsMining() {
|
||||
// Propagate the initial price point to the transaction pool
|
||||
|
|
@ -485,6 +487,7 @@ func (s *Ethereum) StartMining(threads int) error {
|
|||
eb, err := s.Etherbase()
|
||||
if err != nil {
|
||||
log.Error("Cannot start mining without etherbase", "err", err)
|
||||
|
||||
return fmt.Errorf("etherbase missing: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -499,20 +502,26 @@ func (s *Ethereum) StartMining(threads int) error {
|
|||
cli = c
|
||||
}
|
||||
}
|
||||
|
||||
if cli != nil {
|
||||
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
||||
if wallet == nil || err != nil {
|
||||
log.Error("Etherbase account unavailable locally", "err", err)
|
||||
|
||||
return fmt.Errorf("signer missing: %v", err)
|
||||
}
|
||||
|
||||
cli.Authorize(eb, wallet.SignData)
|
||||
}
|
||||
|
||||
if bor, ok := s.engine.(*bor.Bor); ok {
|
||||
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
||||
if wallet == nil || err != nil {
|
||||
log.Error("Etherbase account unavailable locally", "err", err)
|
||||
|
||||
return fmt.Errorf("signer missing: %v", err)
|
||||
}
|
||||
|
||||
bor.Authorize(eb, wallet.SignData)
|
||||
}
|
||||
}
|
||||
|
|
@ -522,6 +531,7 @@ func (s *Ethereum) StartMining(threads int) error {
|
|||
|
||||
go s.miner.Start(eb)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -575,6 +585,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
|
|||
if s.config.SnapshotCache > 0 {
|
||||
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...)
|
||||
}
|
||||
|
||||
return protos
|
||||
}
|
||||
|
||||
|
|
@ -599,6 +610,7 @@ func (s *Ethereum) Start() error {
|
|||
}
|
||||
// Start the networking layer and the light server if requested
|
||||
s.handler.Start(maxPeers)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/contract"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
|
@ -237,7 +240,10 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, et
|
|||
// In order to pass the ethereum transaction tests, we need to set the burn contract which is in the bor config
|
||||
// Then, bor != nil will also be enabled for ethash and clique. Only enable Bor for real if there is a validator contract present.
|
||||
if chainConfig.Bor != nil && chainConfig.Bor.ValidatorContract != "" {
|
||||
return bor.New(chainConfig, db, blockchainAPI, ethConfig.HeimdallURL, ethConfig.WithoutHeimdall)
|
||||
genesisContractsClient := contract.NewGenesisContractsClient(chainConfig, chainConfig.Bor.ValidatorContract, chainConfig.Bor.StateReceiverContract, blockchainAPI)
|
||||
spanner := span.NewChainSpanner(blockchainAPI, contract.ValidatorSet(), chainConfig, common.HexToAddress(chainConfig.Bor.ValidatorContract))
|
||||
|
||||
return bor.New(chainConfig, db, blockchainAPI, spanner, heimdall.NewHeimdallClient(ethConfig.HeimdallURL), genesisContractsClient)
|
||||
} else {
|
||||
switch config.PowMode {
|
||||
case ethash.ModeFake:
|
||||
|
|
|
|||
|
|
@ -47,16 +47,19 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res.Block = blockFields
|
||||
|
||||
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reexec := defaultTraceReexec
|
||||
if config != nil && config.Reexec != nil {
|
||||
reexec = *config.Reexec
|
||||
}
|
||||
|
||||
// TODO: discuss consequences of setting preferDisk false.
|
||||
statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
|
||||
if err != nil {
|
||||
|
|
@ -96,6 +99,7 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T
|
|||
if len(execRes.Revert()) > 0 {
|
||||
returnVal = fmt.Sprintf("%x", execRes.Revert())
|
||||
}
|
||||
|
||||
result := ðapi.ExecutionResult{
|
||||
Gas: execRes.UsedGas,
|
||||
Failed: execRes.Failed(),
|
||||
|
|
@ -106,12 +110,14 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T
|
|||
Result: result,
|
||||
IntermediateHash: statedb.IntermediateRoot(deleteEmptyObjects),
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
for indx, tx := range txs {
|
||||
res.Transactions = append(res.Transactions, traceTxn(indx, tx))
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
|
@ -139,5 +145,6 @@ func (api *API) TraceBorBlock(req *TraceBlockRequest) (*BlockTraceResult, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api.traceBorBlock(ctx, block, req.Config)
|
||||
}
|
||||
|
|
|
|||
79
go.mod
79
go.mod
|
|
@ -1,10 +1,9 @@
|
|||
module github.com/ethereum/go-ethereum
|
||||
|
||||
go 1.16
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.2.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.1.1
|
||||
|
|
@ -16,20 +15,15 @@ require (
|
|||
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/deckarep/golang-set v1.8.0
|
||||
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48
|
||||
github.com/edsrzf/mmap-go v1.0.0
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
|
||||
github.com/go-critic/go-critic v0.6.3 // indirect
|
||||
github.com/go-kit/kit v0.9.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||
github.com/go-stack/stack v1.8.0
|
||||
github.com/go-toolsmith/astcopy v1.0.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa
|
||||
|
|
@ -45,25 +39,19 @@ require (
|
|||
github.com/imdario/mergo v0.3.11
|
||||
github.com/influxdata/influxdb v1.8.3
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2
|
||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
github.com/karalabe/usb v0.0.2
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/mitchellh/cli v1.1.2
|
||||
github.com/mitchellh/go-grpc-net-conn v0.0.0-20200427190222-eb030e4876f0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/naoina/go-stringutil v0.1.0 // indirect
|
||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
|
||||
github.com/polyfloyd/go-errorlint v0.0.0-20220510153142-36539f2bdac3 // indirect
|
||||
github.com/prometheus/tsdb v0.7.1
|
||||
github.com/quasilyte/gogrep v0.0.0-20220429205452-5e2753ee08f9 // indirect
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
|
||||
github.com/rjeczalik/notify v0.9.1
|
||||
github.com/rs/cors v1.7.0
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible
|
||||
|
|
@ -71,24 +59,81 @@ require (
|
|||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
||||
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
|
||||
github.com/xsleonard/go-merkle v1.1.0
|
||||
go.opentelemetry.io/otel v1.2.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0
|
||||
go.opentelemetry.io/otel/sdk v1.2.0
|
||||
go.uber.org/goleak v1.1.12 // indirect
|
||||
go.uber.org/goleak v1.1.12
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
golang.org/x/tools v0.1.10
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||
google.golang.org/grpc v1.42.0
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
|
||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
|
||||
gopkg.in/urfave/cli.v1 v1.20.0
|
||||
pgregory.net/rapid v0.4.7
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect
|
||||
github.com/Masterminds/goutils v1.1.0 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||
github.com/agext/levenshtein v1.2.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect
|
||||
github.com/aws/smithy-go v1.1.0 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect
|
||||
github.com/go-kit/kit v0.9.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/naoina/go-stringutil v0.1.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.1.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/posener/complete v1.1.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
||||
github.com/tklauser/numcpus v0.2.2 // indirect
|
||||
github.com/zclconf/go-cty v1.8.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.2.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.10.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gotest.tools v2.2.0+incompatible // indirect
|
||||
)
|
||||
|
|
|
|||
75
go.sum
75
go.sum
|
|
@ -49,7 +49,6 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo
|
|||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
|
||||
github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=
|
||||
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||
|
|
@ -82,14 +81,12 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2
|
|||
github.com/btcsuite/btcd/btcec/v2 v2.1.2 h1:YoYoC9J0jwfukodSBMzZYUVQ8PTiYg4BnOWiJVzTmLs=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0 h1:MSskdM4/xJYcFzy0altH/C/xHopifpWzHUi1JeVI34Q=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
|
|
@ -162,8 +159,6 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
|
|||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
github.com/go-critic/go-critic v0.6.3 h1:abibh5XYBTASawfTQ0rA7dVtQT+6KzpGqb/J+DxRDaw=
|
||||
github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
|
|
@ -184,25 +179,6 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g=
|
||||
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
|
||||
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
|
||||
github.com/go-toolsmith/astcopy v1.0.1 h1:l09oBhAPyV74kLJ3ZO31iBU8htZGTwr9LTjuMCyL8go=
|
||||
github.com/go-toolsmith/astcopy v1.0.1/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y=
|
||||
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
||||
github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw=
|
||||
github.com/go-toolsmith/astequal v1.0.2 h1:+XvaV8zNxua+9+Oa4AHmgmpo4RYAbwr/qjNppLfX2yM=
|
||||
github.com/go-toolsmith/astequal v1.0.2/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
|
||||
github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
|
||||
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
|
||||
github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg=
|
||||
github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
|
||||
github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 h1:eD9POs68PHkwrx7hAB78z1cb6PfGq/jyWn3wJywsH1o=
|
||||
github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM=
|
||||
github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
|
||||
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
|
||||
github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYwvlk=
|
||||
github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
|
|
@ -216,6 +192,8 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4er
|
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
|
@ -247,10 +225,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
|
|
@ -429,8 +405,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/polyfloyd/go-errorlint v0.0.0-20220510153142-36539f2bdac3 h1:GhmKVnwiethXkJVYqq/kdcw3+u2TIuhPwmHhB+ehpIQ=
|
||||
github.com/polyfloyd/go-errorlint v0.0.0-20220510153142-36539f2bdac3/go.mod h1:KZy4xxPJyy88/gldCe5OdW6OQRtNO3EZE7hXzmnebgA=
|
||||
github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
|
|
@ -445,21 +419,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
|
|||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30=
|
||||
github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a h1:sWFavxtIctGrVs5SYZ5Ml1CvrDAs8Kf5kx2PI3C41dA=
|
||||
github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a/go.mod h1:VMX+OnnSw4LicdiEGtRSD/1X8kW7GuEscjYNr4cOIT4=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.16/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
|
||||
github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc=
|
||||
github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50=
|
||||
github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM=
|
||||
github.com/quasilyte/gogrep v0.0.0-20220429205452-5e2753ee08f9 h1:mEQjyqtrQ6eB7oW9Qm+5po33faQIbhWp3qfhxGYuHKc=
|
||||
github.com/quasilyte/gogrep v0.0.0-20220429205452-5e2753ee08f9/go.mod h1:MsVMK2P94jAne/7vEaLCRmjmOL0aTGAkvVOVuT+UYww=
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU=
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
|
||||
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
|
||||
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
|
||||
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
||||
|
|
@ -488,7 +447,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
|
|||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
|
||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
|
|
@ -518,10 +476,8 @@ github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS
|
|||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/xsleonard/go-merkle v1.1.0 h1:fHe1fuhJjGH22ZzVTAH0jqHLhTGhOq3wQjJN+8P0jQg=
|
||||
github.com/xsleonard/go-merkle v1.1.0/go.mod h1:cW4z+UZ/4f2n9IJgIiyDCdYguchoDyDAPmpuOWGxdGg=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
||||
github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
|
||||
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
|
|
@ -557,9 +513,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
|
@ -571,10 +525,7 @@ golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxT
|
|||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299 h1:zQpM52jfKHG6II1ISZY1ZcpygvuSFZpLwfluuF89XOg=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171 h1:DZhP7zSquENyG3Yb6ZpGqNEtgE8dfXhcLcheIF9RQHY=
|
||||
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
|
|
@ -585,6 +536,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
|||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
|
|
@ -592,9 +544,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
|
|||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -615,7 +565,6 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
|
|
@ -625,10 +574,7 @@ golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
|
@ -642,7 +588,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -686,12 +631,6 @@ golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912 h1:uCLL3g5wH2xjxVREVuAbP9JM5PPKjRbXKRa6IBjkzmU=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
|
|
@ -737,18 +676,14 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
@ -847,5 +782,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
||||
pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g=
|
||||
pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ func NewFlagSet(name string) *Flagset {
|
|||
flags: []*FlagVar{},
|
||||
set: flag.NewFlagSet(name, flag.ContinueOnError),
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
|
|
@ -34,10 +35,12 @@ func (f *Flagset) addFlag(fl *FlagVar) {
|
|||
|
||||
func (f *Flagset) Help() string {
|
||||
str := "Options:\n\n"
|
||||
|
||||
items := []string{}
|
||||
for _, item := range f.flags {
|
||||
items = append(items, fmt.Sprintf(" -%s\n %s", item.Name, item.Usage))
|
||||
}
|
||||
|
||||
return str + strings.Join(items, "\n\n")
|
||||
}
|
||||
|
||||
|
|
@ -53,25 +56,30 @@ func (f *Flagset) MarkDown() string {
|
|||
groups[item.Group] = append(groups[item.Group], item)
|
||||
}
|
||||
|
||||
keys := make([]string, len(groups))
|
||||
i := 0
|
||||
keys := make([]string, len(groups))
|
||||
|
||||
for k := range groups {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
items := []string{}
|
||||
|
||||
for _, k := range keys {
|
||||
if k == "" {
|
||||
items = append(items, fmt.Sprintf("## Options"))
|
||||
items = append(items, "## Options")
|
||||
} else {
|
||||
items = append(items, fmt.Sprintf("### %s Options", k))
|
||||
}
|
||||
|
||||
for _, item := range groups[k] {
|
||||
items = append(items, fmt.Sprintf("- ```%s```: %s", item.Name, item.Usage))
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(items, "\n\n")
|
||||
}
|
||||
|
||||
|
|
@ -162,6 +170,7 @@ func (b *BigIntFlag) String() string {
|
|||
if b.Value == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return b.Value.String()
|
||||
}
|
||||
|
||||
|
|
@ -174,10 +183,12 @@ func (b *BigIntFlag) Set(value string) error {
|
|||
} else {
|
||||
num, ok = num.SetString(value, 10)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to set big int")
|
||||
}
|
||||
b.Value = num
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -201,11 +212,13 @@ func (i *SliceStringFlag) String() string {
|
|||
if i.Value == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.Join(*i.Value, ",")
|
||||
}
|
||||
|
||||
func (i *SliceStringFlag) Set(value string) error {
|
||||
*i.Value = append(*i.Value, strings.Split(value, ",")...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -246,10 +259,12 @@ func (m *MapStringFlag) String() string {
|
|||
if m.Value == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
ls := []string{}
|
||||
for k, v := range *m.Value {
|
||||
ls = append(ls, k+"="+v)
|
||||
}
|
||||
|
||||
return strings.Join(ls, ",")
|
||||
}
|
||||
|
||||
|
|
@ -257,6 +272,7 @@ func (m *MapStringFlag) Set(value string) error {
|
|||
if m.Value == nil {
|
||||
m.Value = &map[string]string{}
|
||||
}
|
||||
|
||||
for _, t := range strings.Split(value, ",") {
|
||||
if t != "" {
|
||||
kv := strings.Split(t, "=")
|
||||
|
|
@ -266,6 +282,7 @@ func (m *MapStringFlag) Set(value string) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,18 +26,23 @@ var chains = map[string]*Chain{
|
|||
}
|
||||
|
||||
func GetChain(name string) (*Chain, error) {
|
||||
var chain *Chain
|
||||
var err error
|
||||
var (
|
||||
chain *Chain
|
||||
err error
|
||||
)
|
||||
|
||||
if _, fileErr := os.Stat(name); fileErr == nil {
|
||||
if chain, err = ImportFromFile(name); err != nil {
|
||||
return nil, fmt.Errorf("error importing chain from file: %v", err)
|
||||
}
|
||||
|
||||
return chain, nil
|
||||
} else if errors.Is(fileErr, os.ErrNotExist) {
|
||||
var ok bool
|
||||
if chain, ok = chains[name]; !ok {
|
||||
return nil, fmt.Errorf("chain %s not found", name)
|
||||
}
|
||||
|
||||
return chain, nil
|
||||
} else {
|
||||
return nil, fileErr
|
||||
|
|
@ -62,10 +67,12 @@ func importChain(content []byte) (*Chain, error) {
|
|||
|
||||
if chain.Genesis == nil {
|
||||
log.Info("Try reading as legacy genesis")
|
||||
|
||||
var genesis core.Genesis
|
||||
if err := json.Unmarshal(content, &genesis); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if genesis.Config != nil {
|
||||
chain.Genesis = &genesis
|
||||
chain.NetworkId = genesis.Config.ChainID.Uint64()
|
||||
|
|
|
|||
|
|
@ -5,9 +5,12 @@ import (
|
|||
)
|
||||
|
||||
func TestChain_ImportFromFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
filename string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
|
|
@ -34,8 +37,13 @@ func TestChain_ImportFromFile(t *testing.T) {
|
|||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := ImportFromFile(tt.args.filename)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ImportFromFile() error = %v, wantErr %v", err, tt.wantErr)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ func (c *Command) MarkDown() string {
|
|||
"The ```bor server``` command runs the Bor client.",
|
||||
c.Flags().MarkDown(),
|
||||
}
|
||||
|
||||
return strings.Join(items, "\n\n")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ type Config struct {
|
|||
// GcMode selects the garbage collection mode for the trie
|
||||
GcMode string `hcl:"gc-mode,optional"`
|
||||
|
||||
// NoSnapshot disbales the snapshot database mode
|
||||
// NoSnapshot disables the snapshot database mode
|
||||
NoSnapshot bool `hcl:"no-snapshot,optional"`
|
||||
|
||||
// Ethstats is the address of the ethstats server to send telemetry
|
||||
|
|
@ -527,18 +527,22 @@ func (c *Config) fillBigInt() error {
|
|||
b := new(big.Int)
|
||||
|
||||
var ok bool
|
||||
|
||||
if strings.HasPrefix(*x.str, "0x") {
|
||||
b, ok = b.SetString((*x.str)[2:], 16)
|
||||
} else {
|
||||
b, ok = b.SetString(*x.str, 10)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("%s can't parse big int %s", x.path, *x.str)
|
||||
}
|
||||
|
||||
*x.str = ""
|
||||
*x.td = b
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -559,10 +563,12 @@ func (c *Config) fillTimeDurations() error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("%s can't parse time duration %s", x.path, *x.str)
|
||||
}
|
||||
|
||||
*x.str = ""
|
||||
*x.td = d
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -574,6 +580,7 @@ func readConfigFile(path string) (*Config, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return readLegacyConfig(data)
|
||||
}
|
||||
|
||||
|
|
@ -582,15 +589,19 @@ func readConfigFile(path string) (*Config, error) {
|
|||
Cache: &CacheConfig{},
|
||||
Sealer: &SealerConfig{},
|
||||
}
|
||||
|
||||
if err := hclsimple.DecodeFile(path, nil, config); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode config file '%s': %v", path, err)
|
||||
}
|
||||
|
||||
if err := config.fillBigInt(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := config.fillTimeDurations(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
|
|
@ -599,6 +610,7 @@ func (c *Config) loadChain() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.chain = chain
|
||||
|
||||
// preload some default values that depend on the chain file
|
||||
|
|
@ -612,14 +624,17 @@ func (c *Config) loadChain() error {
|
|||
} else {
|
||||
c.Cache.Cache = 1024
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:gocognit
|
||||
func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*ethconfig.Config, error) {
|
||||
dbHandles, err := makeDatabaseHandles()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n := ethconfig.Defaults
|
||||
|
||||
// only update for non-developer mode as we don't yet
|
||||
|
|
@ -663,6 +678,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
if !common.IsHexAddress(etherbase) {
|
||||
return nil, fmt.Errorf("etherbase is not an address: %s", etherbase)
|
||||
}
|
||||
|
||||
n.Miner.Etherbase = common.HexToAddress(etherbase)
|
||||
}
|
||||
}
|
||||
|
|
@ -672,17 +688,24 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() {
|
||||
return nil, fmt.Errorf("account unlock with HTTP access is forbidden")
|
||||
}
|
||||
|
||||
ks := accountManager.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
|
||||
|
||||
passwords, err := MakePasswordListFromFile(c.Accounts.PasswordFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(passwords) < len(c.Accounts.Unlock) {
|
||||
return nil, fmt.Errorf("number of passwords provided (%v) is less than number of accounts (%v) to unlock",
|
||||
len(passwords), len(c.Accounts.Unlock))
|
||||
}
|
||||
|
||||
for i, account := range c.Accounts.Unlock {
|
||||
ks.Unlock(accounts.Account{Address: common.HexToAddress(account)}, passwords[i])
|
||||
err = ks.Unlock(accounts.Account{Address: common.HexToAddress(account)}, passwords[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not unlock an account %q", account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -700,6 +723,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
passphrase string
|
||||
err error
|
||||
)
|
||||
|
||||
// etherbase has been set above, configuring the miner address from command line flags.
|
||||
if n.Miner.Etherbase != (common.Address{}) {
|
||||
developer = accounts.Account{Address: n.Miner.Etherbase}
|
||||
|
|
@ -714,6 +738,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
if err := ks.Unlock(developer, passphrase); err != nil {
|
||||
return nil, fmt.Errorf("failed to unlock developer account: %v", err)
|
||||
}
|
||||
|
||||
log.Info("Using developer account", "address", developer.Address)
|
||||
|
||||
// Set the Etherbase
|
||||
|
|
@ -753,10 +778,12 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid required block number %s: %v", k, err)
|
||||
}
|
||||
|
||||
var hash common.Hash
|
||||
if err = hash.UnmarshalText([]byte(v)); err != nil {
|
||||
return nil, fmt.Errorf("invalid required block hash %s: %v", v, err)
|
||||
}
|
||||
|
||||
n.PeerRequiredBlocks[number] = hash
|
||||
}
|
||||
}
|
||||
|
|
@ -775,6 +802,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
log.Warn("Lowering memory allowance on 32bit arch", "available", mem.Total/1024/1024, "addressable", 2*1024)
|
||||
mem.Total = 2 * 1024 * 1024 * 1024
|
||||
}
|
||||
|
||||
allowance := uint64(mem.Total / 1024 / 1024 / 3)
|
||||
if cache > allowance {
|
||||
log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance)
|
||||
|
|
@ -804,6 +832,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
} else {
|
||||
log.Info("Global gas cap disabled")
|
||||
}
|
||||
|
||||
n.RPCTxFeeCap = c.JsonRPC.TxFeeCap
|
||||
|
||||
// sync mode. It can either be "fast", "full" or "snap". We disable
|
||||
|
|
@ -843,6 +872,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
}
|
||||
|
||||
n.DatabaseHandles = dbHandles
|
||||
|
||||
return &n, nil
|
||||
}
|
||||
|
||||
|
|
@ -906,6 +936,7 @@ func (c *Config) buildNode() (*node.Config, error) {
|
|||
cfg.HTTPHost = c.JsonRPC.Http.Host
|
||||
cfg.HTTPPort = int(c.JsonRPC.Http.Port)
|
||||
}
|
||||
|
||||
if c.JsonRPC.Ws.Enabled {
|
||||
cfg.WSHost = c.JsonRPC.Ws.Host
|
||||
cfg.WSPort = int(c.JsonRPC.Ws.Port)
|
||||
|
|
@ -916,6 +947,7 @@ func (c *Config) buildNode() (*node.Config, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("wrong 'nat' flag: %v", err)
|
||||
}
|
||||
|
||||
cfg.P2P.NAT = natif
|
||||
|
||||
// only check for non-developer modes
|
||||
|
|
@ -926,21 +958,27 @@ func (c *Config) buildNode() (*node.Config, error) {
|
|||
if len(bootnodes) == 0 {
|
||||
bootnodes = c.chain.Bootnodes
|
||||
}
|
||||
|
||||
if cfg.P2P.BootstrapNodes, err = parseBootnodes(bootnodes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cfg.P2P.BootstrapNodesV5, err = parseBootnodes(c.P2P.Discovery.BootnodesV5); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cfg.P2P.StaticNodes, err = parseBootnodes(c.P2P.Discovery.StaticNodes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(cfg.P2P.StaticNodes) == 0 {
|
||||
cfg.P2P.StaticNodes = cfg.StaticNodes()
|
||||
}
|
||||
|
||||
if cfg.P2P.TrustedNodes, err = parseBootnodes(c.P2P.Discovery.TrustedNodes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(cfg.P2P.TrustedNodes) == 0 {
|
||||
cfg.P2P.TrustedNodes = cfg.TrustedNodes()
|
||||
}
|
||||
|
|
@ -951,6 +989,7 @@ func (c *Config) buildNode() (*node.Config, error) {
|
|||
cfg.P2P.MaxPeers = 0
|
||||
cfg.P2P.NoDiscovery = true
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
|
|
@ -960,6 +999,7 @@ func (c *Config) Merge(cc ...*Config) error {
|
|||
return fmt.Errorf("failed to merge configurations: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -968,10 +1008,12 @@ func makeDatabaseHandles() (int, error) {
|
|||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
raised, err := fdlimit.Raise(uint64(limit))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return int(raised / 2), nil
|
||||
}
|
||||
|
||||
|
|
@ -986,6 +1028,7 @@ func parseBootnodes(urls []string) ([]*enode.Node, error) {
|
|||
dst = append(dst, node)
|
||||
}
|
||||
}
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
|
|
@ -996,6 +1039,7 @@ func defaultDataDir() string {
|
|||
// we cannot guess a stable location
|
||||
return ""
|
||||
}
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
return filepath.Join(home, "Library", "Bor")
|
||||
|
|
@ -1005,6 +1049,7 @@ func defaultDataDir() string {
|
|||
// Windows XP and below don't have LocalAppData.
|
||||
panic("environment variable LocalAppData is undefined")
|
||||
}
|
||||
|
||||
return filepath.Join(appdata, "Bor")
|
||||
default:
|
||||
return filepath.Join(home, ".bor")
|
||||
|
|
@ -1016,6 +1061,7 @@ func Hostname() string {
|
|||
if err != nil {
|
||||
return "bor"
|
||||
}
|
||||
|
||||
return hostname
|
||||
}
|
||||
|
||||
|
|
@ -1024,10 +1070,13 @@ func MakePasswordListFromFile(path string) ([]string, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read password file: %v", err)
|
||||
}
|
||||
|
||||
lines := strings.Split(string(text), "\n")
|
||||
|
||||
// Sanitise DOS line endings.
|
||||
for i := range lines {
|
||||
lines[i] = strings.TrimRight(lines[i], "\r")
|
||||
}
|
||||
|
||||
return lines, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ func TestConfigMerge(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := &Config{
|
||||
Chain: "1",
|
||||
NoSnapshot: false,
|
||||
|
|
@ -69,11 +70,14 @@ func TestConfigMerge(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.NoError(t, c0.Merge(c1))
|
||||
assert.Equal(t, c0, expected)
|
||||
}
|
||||
|
||||
func TestDefaultDatatypeOverride(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// This test is specific to `maxpeers` flag (for now) to check
|
||||
// if default datatype value (0 in case of uint64) is overridden.
|
||||
c0 := &Config{
|
||||
|
|
@ -81,16 +85,19 @@ func TestDefaultDatatypeOverride(t *testing.T) {
|
|||
MaxPeers: 30,
|
||||
},
|
||||
}
|
||||
|
||||
c1 := &Config{
|
||||
P2P: &P2PConfig{
|
||||
MaxPeers: 0,
|
||||
},
|
||||
}
|
||||
|
||||
expected := &Config{
|
||||
P2P: &P2PConfig{
|
||||
MaxPeers: 0,
|
||||
},
|
||||
}
|
||||
|
||||
assert.NoError(t, c0.Merge(c1))
|
||||
assert.Equal(t, c0, expected)
|
||||
}
|
||||
|
|
@ -99,6 +106,7 @@ func TestConfigLoadFile(t *testing.T) {
|
|||
readFile := func(path string) {
|
||||
config, err := readConfigFile(path)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, config, &Config{
|
||||
DataDir: "./data",
|
||||
RequiredBlocks: map[string]string{
|
||||
|
|
@ -122,6 +130,7 @@ func TestConfigLoadFile(t *testing.T) {
|
|||
t.Run("hcl", func(t *testing.T) {
|
||||
readFile("./testdata/simple.hcl")
|
||||
})
|
||||
|
||||
// read file in json format
|
||||
t.Run("json", func(t *testing.T) {
|
||||
readFile("./testdata/simple.json")
|
||||
|
|
@ -152,7 +161,11 @@ func TestConfigBootnodesDefault(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMakePasswordListFromFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("ReadPasswordFile", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
result, _ := MakePasswordListFromFile("./testdata/password.txt")
|
||||
assert.Equal(t, []string{"test1", "test2"}, result)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -17,10 +17,13 @@ func findAvailablePort(from int32, count int32) (int32, error) {
|
|||
if count == maxPortCheck {
|
||||
return 0, fmt.Errorf("no available port found")
|
||||
}
|
||||
|
||||
port := atomic.AddInt32(&from, 1)
|
||||
addr := fmt.Sprintf("localhost:%d", port)
|
||||
lis, err := net.Listen("tcp", addr)
|
||||
|
||||
count++
|
||||
|
||||
lis, err := net.Listen("tcp", addr)
|
||||
if err == nil {
|
||||
lis.Close()
|
||||
return port, nil
|
||||
|
|
@ -36,8 +39,13 @@ func CreateMockServer(config *Config) (*Server, error) {
|
|||
|
||||
// find available port for grpc server
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var from int32 = 60000 // the min port to start checking from
|
||||
var to int32 = 61000 // the max port to start checking from
|
||||
|
||||
var (
|
||||
from int32 = 60000 // the min port to start checking from
|
||||
to int32 = 61000 // the max port to start checking from
|
||||
)
|
||||
|
||||
//nolint: gosec
|
||||
port, err := findAvailablePort(rand.Int31n(to-from+1)+from, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -53,10 +61,13 @@ func CreateMockServer(config *Config) (*Server, error) {
|
|||
// find available port for http server
|
||||
from = 8545
|
||||
to = 9545
|
||||
|
||||
//nolint: gosec
|
||||
port, err = findAvailablePort(rand.Int31n(to-from+1)+from, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.JsonRPC.Http.Port = uint64(port)
|
||||
|
||||
// start the server
|
||||
|
|
|
|||
|
|
@ -11,6 +11,16 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
|
|
@ -26,15 +36,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/metrics/influxdb"
|
||||
"github.com/ethereum/go-ethereum/metrics/prometheus"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
|
|
@ -71,6 +72,7 @@ func NewServer(config *Config) (*Server, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stack, err := node.New(nodeCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -82,6 +84,7 @@ func NewServer(config *Config) (*Server, error) {
|
|||
|
||||
// register backend to account manager with keystore for signing
|
||||
keydir := stack.KeyStoreDir()
|
||||
|
||||
n, p := keystore.StandardScryptN, keystore.StandardScryptP
|
||||
if config.Accounts.UseLightweightKDF {
|
||||
n, p = keystore.LightScryptN, keystore.LightScryptP
|
||||
|
|
@ -94,6 +97,7 @@ func NewServer(config *Config) (*Server, error) {
|
|||
authorized := false
|
||||
|
||||
// check if personal wallet endpoints are disabled or not
|
||||
// nolint:nestif
|
||||
if !config.Accounts.DisableBorWallet {
|
||||
// add keystore globally to the node's account manager if personal wallet is enabled
|
||||
stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p))
|
||||
|
|
@ -103,10 +107,12 @@ func NewServer(config *Config) (*Server, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
backend, err := eth.New(stack, ethCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
srv.backend = backend
|
||||
} else {
|
||||
// register the ethereum backend (with temporary created account manager)
|
||||
|
|
@ -114,10 +120,12 @@ func NewServer(config *Config) (*Server, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
backend, err := eth.New(stack, ethCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
srv.backend = backend
|
||||
|
||||
// authorize only if mining or in developer mode
|
||||
|
|
@ -126,6 +134,7 @@ func NewServer(config *Config) (*Server, error) {
|
|||
eb, err := srv.backend.Etherbase()
|
||||
if err != nil {
|
||||
log.Error("Cannot start mining without etherbase", "err", err)
|
||||
|
||||
return nil, fmt.Errorf("etherbase missing: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -142,8 +151,10 @@ func NewServer(config *Config) (*Server, error) {
|
|||
wallet, err := accountManager.Find(accounts.Account{Address: eb})
|
||||
if wallet == nil || err != nil {
|
||||
log.Error("Etherbase account unavailable locally", "err", err)
|
||||
|
||||
return nil, fmt.Errorf("signer missing: %v", err)
|
||||
}
|
||||
|
||||
cli.Authorize(eb, wallet.SignData)
|
||||
authorized = true
|
||||
}
|
||||
|
|
@ -155,6 +166,7 @@ func NewServer(config *Config) (*Server, error) {
|
|||
log.Error("Etherbase account unavailable locally", "err", err)
|
||||
return nil, fmt.Errorf("signer missing: %v", err)
|
||||
}
|
||||
|
||||
bor.Authorize(eb, wallet.SignData)
|
||||
authorized = true
|
||||
}
|
||||
|
|
@ -200,6 +212,7 @@ func NewServer(config *Config) (*Server, error) {
|
|||
if err := srv.node.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
|
|
@ -238,10 +251,12 @@ func (s *Server) setupMetrics(config *TelemetryConfig, serviceName string) error
|
|||
|
||||
if v1Enabled {
|
||||
log.Info("Enabling metrics export to InfluxDB (v1)")
|
||||
|
||||
go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, cfg.Database, cfg.Username, cfg.Password, "geth.", tags)
|
||||
}
|
||||
if v2Enabled {
|
||||
log.Info("Enabling metrics export to InfluxDB (v2)")
|
||||
|
||||
go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, cfg.Token, cfg.Bucket, cfg.Organization, "geth.", tags)
|
||||
}
|
||||
}
|
||||
|
|
@ -328,6 +343,7 @@ func (s *Server) setupGRPCServer(addr string) error {
|
|||
}()
|
||||
|
||||
log.Info("GRPC Server started", "addr", addr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -338,16 +354,20 @@ func (s *Server) withLoggingUnaryInterceptor() grpc.ServerOption {
|
|||
func (s *Server) loggingServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
start := time.Now()
|
||||
h, err := handler(ctx, req)
|
||||
|
||||
log.Trace("Request", "method", info.FullMethod, "duration", time.Since(start), "error", err)
|
||||
|
||||
return h, err
|
||||
}
|
||||
|
||||
func setupLogger(logLevel string) {
|
||||
output := io.Writer(os.Stderr)
|
||||
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
}
|
||||
|
||||
ostream := log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger := log.NewGlogHandler(ostream)
|
||||
|
||||
|
|
@ -358,6 +378,7 @@ func setupLogger(logLevel string) {
|
|||
} else {
|
||||
glogger.Verbosity(log.LvlInfo)
|
||||
}
|
||||
|
||||
log.Root().SetHandler(glogger)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
@ -18,9 +19,11 @@ func nextPort() uint64 {
|
|||
log.Info("Checking for new port", "current", initialPort)
|
||||
port := atomic.AddUint64(&initialPort, 1)
|
||||
addr := fmt.Sprintf("localhost:%d", port)
|
||||
|
||||
lis, err := net.Listen("tcp", addr)
|
||||
if err == nil {
|
||||
lis.Close()
|
||||
|
||||
return port
|
||||
} else {
|
||||
return nextPort()
|
||||
|
|
@ -28,6 +31,8 @@ func nextPort() uint64 {
|
|||
}
|
||||
|
||||
func TestServer_DeveloperMode(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// get the default config
|
||||
config := DefaultConfig()
|
||||
|
||||
|
|
@ -38,6 +43,7 @@ func TestServer_DeveloperMode(t *testing.T) {
|
|||
// start the mock server
|
||||
server, err := CreateMockServer(config)
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer CloseMockServer(server)
|
||||
|
||||
// record the initial block number
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
|
||||
gproto "github.com/golang/protobuf/proto" //nolint:staticcheck,typecheck
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
grpc_net_conn "github.com/mitchellh/go-grpc-net-conn"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
|
|
@ -16,9 +20,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
gproto "github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
grpc_net_conn "github.com/mitchellh/go-grpc-net-conn"
|
||||
)
|
||||
|
||||
const chunkSize = 1024 * 1024 * 1024
|
||||
|
|
@ -45,6 +46,7 @@ func sendStreamDebugFile(stream proto.Bor_DebugPprofServer, headers map[string]s
|
|||
Request: &proto.DebugFileResponse_Input{},
|
||||
Encode: grpc_net_conn.ChunkedEncoder(encoder, chunkSize),
|
||||
}
|
||||
|
||||
if _, err := conn.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -61,11 +63,14 @@ func sendStreamDebugFile(stream proto.Bor_DebugPprofServer, headers map[string]s
|
|||
}
|
||||
|
||||
func (s *Server) DebugPprof(req *proto.DebugPprofRequest, stream proto.Bor_DebugPprofServer) error {
|
||||
var payload []byte
|
||||
var headers map[string]string
|
||||
var err error
|
||||
var (
|
||||
payload []byte
|
||||
headers map[string]string
|
||||
err error
|
||||
)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
switch req.Type {
|
||||
case proto.DebugPprofRequest_CPU:
|
||||
payload, headers, err = pprof.CPUProfile(ctx, int(req.Seconds))
|
||||
|
|
@ -74,6 +79,7 @@ func (s *Server) DebugPprof(req *proto.DebugPprofRequest, stream proto.Bor_Debug
|
|||
case proto.DebugPprofRequest_LOOKUP:
|
||||
payload, headers, err = pprof.Profile(req.Profile, 0, 0)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -82,6 +88,7 @@ func (s *Server) DebugPprof(req *proto.DebugPprofRequest, stream proto.Bor_Debug
|
|||
if err := sendStreamDebugFile(stream, headers, payload); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -192,6 +199,7 @@ func (s *Server) DebugBlock(req *proto.DebugBlockRequest, stream proto.Bor_Debug
|
|||
},
|
||||
},
|
||||
}
|
||||
|
||||
res, err := s.tracerAPI.TraceBorBlock(traceReq)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -202,6 +210,7 @@ func (s *Server) DebugBlock(req *proto.DebugBlockRequest, stream proto.Bor_Debug
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sendStreamDebugFile(stream, map[string]string{}, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
233
miner/fake_miner.go
Normal file
233
miner/fake_miner.go
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
package miner
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/api"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
type DefaultBorMiner struct {
|
||||
Miner *Miner
|
||||
Mux *event.TypeMux //nolint:staticcheck
|
||||
Cleanup func(skipMiner bool)
|
||||
|
||||
Ctrl *gomock.Controller
|
||||
EthAPIMock api.Caller
|
||||
HeimdallClientMock bor.IHeimdallClient
|
||||
ContractMock bor.GenesisContract
|
||||
}
|
||||
|
||||
func NewBorDefaultMiner(t *testing.T) *DefaultBorMiner {
|
||||
t.Helper()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
ethAPI := api.NewMockCaller(ctrl)
|
||||
ethAPI.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
spanner := bor.NewMockSpanner(ctrl)
|
||||
spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
{
|
||||
ID: 0,
|
||||
Address: common.Address{0x1},
|
||||
VotingPower: 100,
|
||||
ProposerPriority: 0,
|
||||
},
|
||||
}, nil).AnyTimes()
|
||||
|
||||
heimdallClient := mocks.NewMockIHeimdallClient(ctrl)
|
||||
heimdallClient.EXPECT().Close().Times(1)
|
||||
|
||||
genesisContracts := bor.NewMockGenesisContract(ctrl)
|
||||
|
||||
miner, mux, cleanup := createBorMiner(t, ethAPI, spanner, heimdallClient, genesisContracts)
|
||||
|
||||
return &DefaultBorMiner{
|
||||
Miner: miner,
|
||||
Mux: mux,
|
||||
Cleanup: cleanup,
|
||||
Ctrl: ctrl,
|
||||
EthAPIMock: ethAPI,
|
||||
HeimdallClientMock: heimdallClient,
|
||||
ContractMock: genesisContracts,
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:staticcheck
|
||||
func createBorMiner(t *testing.T, ethAPIMock api.Caller, spanner bor.Spanner, heimdallClientMock bor.IHeimdallClient, contractMock bor.GenesisContract) (*Miner, *event.TypeMux, func(skipMiner bool)) {
|
||||
t.Helper()
|
||||
|
||||
// Create Ethash config
|
||||
chainDB, _, chainConfig := NewDBForFakes(t)
|
||||
|
||||
engine := NewFakeBor(t, chainDB, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock)
|
||||
|
||||
// Create Ethereum backend
|
||||
bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("can't create new chain %v", err)
|
||||
}
|
||||
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(chainDB), nil)
|
||||
blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)}
|
||||
|
||||
pool := core.NewTxPool(testTxPoolConfig, chainConfig, blockchain)
|
||||
backend := NewMockBackend(bc, pool)
|
||||
|
||||
// Create event Mux
|
||||
mux := new(event.TypeMux)
|
||||
|
||||
config := Config{
|
||||
Etherbase: common.HexToAddress("123456789"),
|
||||
}
|
||||
|
||||
// Create Miner
|
||||
miner := New(backend, &config, chainConfig, mux, engine, nil)
|
||||
|
||||
cleanup := func(skipMiner bool) {
|
||||
bc.Stop()
|
||||
engine.Close()
|
||||
pool.Stop()
|
||||
|
||||
if !skipMiner {
|
||||
miner.Close()
|
||||
}
|
||||
}
|
||||
|
||||
return miner, mux, cleanup
|
||||
}
|
||||
|
||||
func NewDBForFakes(t *testing.T) (ethdb.Database, *core.Genesis, *params.ChainConfig) {
|
||||
t.Helper()
|
||||
|
||||
memdb := memorydb.New()
|
||||
chainDB := rawdb.NewDatabase(memdb)
|
||||
genesis := core.DeveloperGenesisBlock(2, 11_500_000, common.HexToAddress("12345"))
|
||||
|
||||
chainConfig, _, err := core.SetupGenesisBlock(chainDB, genesis)
|
||||
if err != nil {
|
||||
t.Fatalf("can't create new chain config: %v", err)
|
||||
}
|
||||
|
||||
chainConfig.Bor.Period = map[string]uint64{
|
||||
"0": 1,
|
||||
}
|
||||
|
||||
return chainDB, genesis, chainConfig
|
||||
}
|
||||
|
||||
func NewFakeBor(t *testing.T, chainDB ethdb.Database, chainConfig *params.ChainConfig, ethAPIMock api.Caller, spanner bor.Spanner, heimdallClientMock bor.IHeimdallClient, contractMock bor.GenesisContract) consensus.Engine {
|
||||
t.Helper()
|
||||
|
||||
if chainConfig.Bor == nil {
|
||||
chainConfig.Bor = params.BorUnittestChainConfig.Bor
|
||||
}
|
||||
|
||||
return bor.New(chainConfig, chainDB, ethAPIMock, spanner, heimdallClientMock, contractMock)
|
||||
}
|
||||
|
||||
type mockBackend struct {
|
||||
bc *core.BlockChain
|
||||
txPool *core.TxPool
|
||||
}
|
||||
|
||||
func NewMockBackend(bc *core.BlockChain, txPool *core.TxPool) *mockBackend {
|
||||
return &mockBackend{
|
||||
bc: bc,
|
||||
txPool: txPool,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockBackend) BlockChain() *core.BlockChain {
|
||||
return m.bc
|
||||
}
|
||||
|
||||
func (m *mockBackend) TxPool() *core.TxPool {
|
||||
return m.txPool
|
||||
}
|
||||
|
||||
func (m *mockBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) {
|
||||
return nil, errors.New("not supported")
|
||||
}
|
||||
|
||||
type testBlockChain struct {
|
||||
statedb *state.StateDB
|
||||
gasLimit uint64
|
||||
chainHeadFeed *event.Feed
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) CurrentBlock() *types.Block {
|
||||
return types.NewBlock(&types.Header{
|
||||
GasLimit: bc.gasLimit,
|
||||
}, nil, nil, nil, trie.NewStackTrie(nil))
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
return bc.CurrentBlock()
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
|
||||
return bc.statedb, nil
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
||||
return bc.chainHeadFeed.Subscribe(ch)
|
||||
}
|
||||
|
||||
var (
|
||||
// Test chain configurations
|
||||
testTxPoolConfig core.TxPoolConfig
|
||||
ethashChainConfig *params.ChainConfig
|
||||
cliqueChainConfig *params.ChainConfig
|
||||
|
||||
// Test accounts
|
||||
testBankKey, _ = crypto.GenerateKey()
|
||||
testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey)
|
||||
testBankFunds = big.NewInt(1000000000000000000)
|
||||
|
||||
testUserKey, _ = crypto.GenerateKey()
|
||||
testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey)
|
||||
|
||||
// Test transactions
|
||||
pendingTxs []*types.Transaction
|
||||
newTxs []*types.Transaction
|
||||
|
||||
testConfig = &Config{
|
||||
Recommit: time.Second,
|
||||
GasCeil: params.GenesisGasLimit,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
testTxPoolConfig = core.DefaultTxPoolConfig
|
||||
testTxPoolConfig.Journal = ""
|
||||
ethashChainConfig = new(params.ChainConfig)
|
||||
*ethashChainConfig = *params.TestChainConfig
|
||||
cliqueChainConfig = new(params.ChainConfig)
|
||||
*cliqueChainConfig = *params.TestChainConfig
|
||||
cliqueChainConfig.Clique = ¶ms.CliqueConfig{
|
||||
Period: 10,
|
||||
Epoch: 30000,
|
||||
}
|
||||
}
|
||||
|
|
@ -18,80 +18,32 @@
|
|||
package miner
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
type mockBackend struct {
|
||||
bc *core.BlockChain
|
||||
txPool *core.TxPool
|
||||
}
|
||||
|
||||
func NewMockBackend(bc *core.BlockChain, txPool *core.TxPool) *mockBackend {
|
||||
return &mockBackend{
|
||||
bc: bc,
|
||||
txPool: txPool,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockBackend) BlockChain() *core.BlockChain {
|
||||
return m.bc
|
||||
}
|
||||
|
||||
func (m *mockBackend) TxPool() *core.TxPool {
|
||||
return m.txPool
|
||||
}
|
||||
|
||||
func (m *mockBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) {
|
||||
return nil, errors.New("not supported")
|
||||
}
|
||||
|
||||
type testBlockChain struct {
|
||||
statedb *state.StateDB
|
||||
gasLimit uint64
|
||||
chainHeadFeed *event.Feed
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) CurrentBlock() *types.Block {
|
||||
return types.NewBlock(&types.Header{
|
||||
GasLimit: bc.gasLimit,
|
||||
}, nil, nil, nil, trie.NewStackTrie(nil))
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
return bc.CurrentBlock()
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
|
||||
return bc.statedb, nil
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
||||
return bc.chainHeadFeed.Subscribe(ch)
|
||||
}
|
||||
|
||||
func TestMiner(t *testing.T) {
|
||||
miner, mux, cleanup := createMiner(t)
|
||||
defer cleanup(false)
|
||||
t.Parallel()
|
||||
|
||||
minerBor := NewBorDefaultMiner(t)
|
||||
defer func() {
|
||||
minerBor.Cleanup(false)
|
||||
minerBor.Ctrl.Finish()
|
||||
}()
|
||||
|
||||
miner := minerBor.Miner
|
||||
mux := minerBor.Mux
|
||||
|
||||
miner.Start(common.HexToAddress("0x12345"))
|
||||
waitForMiningState(t, miner, true)
|
||||
|
||||
// Start the downloader
|
||||
mux.Post(downloader.StartEvent{})
|
||||
waitForMiningState(t, miner, false)
|
||||
|
||||
// Stop the downloader and wait for the update loop to run
|
||||
mux.Post(downloader.DoneEvent{})
|
||||
waitForMiningState(t, miner, true)
|
||||
|
|
@ -113,10 +65,20 @@ func TestMiner(t *testing.T) {
|
|||
// An initial FailedEvent should allow mining to stop on a subsequent
|
||||
// downloader StartEvent.
|
||||
func TestMinerDownloaderFirstFails(t *testing.T) {
|
||||
miner, mux, cleanup := createMiner(t)
|
||||
defer cleanup(false)
|
||||
t.Parallel()
|
||||
|
||||
minerBor := NewBorDefaultMiner(t)
|
||||
defer func() {
|
||||
minerBor.Cleanup(false)
|
||||
minerBor.Ctrl.Finish()
|
||||
}()
|
||||
|
||||
miner := minerBor.Miner
|
||||
mux := minerBor.Mux
|
||||
|
||||
miner.Start(common.HexToAddress("0x12345"))
|
||||
waitForMiningState(t, miner, true)
|
||||
|
||||
// Start the downloader
|
||||
mux.Post(downloader.StartEvent{})
|
||||
waitForMiningState(t, miner, false)
|
||||
|
|
@ -145,10 +107,20 @@ func TestMinerDownloaderFirstFails(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMinerStartStopAfterDownloaderEvents(t *testing.T) {
|
||||
miner, mux, cleanup := createMiner(t)
|
||||
defer cleanup(false)
|
||||
t.Parallel()
|
||||
|
||||
minerBor := NewBorDefaultMiner(t)
|
||||
defer func() {
|
||||
minerBor.Cleanup(false)
|
||||
minerBor.Ctrl.Finish()
|
||||
}()
|
||||
|
||||
miner := minerBor.Miner
|
||||
mux := minerBor.Mux
|
||||
|
||||
miner.Start(common.HexToAddress("0x12345"))
|
||||
waitForMiningState(t, miner, true)
|
||||
|
||||
// Start the downloader
|
||||
mux.Post(downloader.StartEvent{})
|
||||
waitForMiningState(t, miner, false)
|
||||
|
|
@ -168,58 +140,104 @@ func TestMinerStartStopAfterDownloaderEvents(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStartWhileDownload(t *testing.T) {
|
||||
miner, mux, cleanup := createMiner(t)
|
||||
defer cleanup(false)
|
||||
t.Parallel()
|
||||
|
||||
minerBor := NewBorDefaultMiner(t)
|
||||
defer func() {
|
||||
minerBor.Cleanup(false)
|
||||
minerBor.Ctrl.Finish()
|
||||
}()
|
||||
|
||||
miner := minerBor.Miner
|
||||
mux := minerBor.Mux
|
||||
|
||||
waitForMiningState(t, miner, false)
|
||||
miner.Start(common.HexToAddress("0x12345"))
|
||||
waitForMiningState(t, miner, true)
|
||||
|
||||
// Stop the downloader and wait for the update loop to run
|
||||
mux.Post(downloader.StartEvent{})
|
||||
waitForMiningState(t, miner, false)
|
||||
|
||||
// Starting the miner after the downloader should not work
|
||||
miner.Start(common.HexToAddress("0x12345"))
|
||||
waitForMiningState(t, miner, false)
|
||||
}
|
||||
|
||||
func TestStartStopMiner(t *testing.T) {
|
||||
miner, _, cleanup := createMiner(t)
|
||||
defer cleanup(false)
|
||||
t.Parallel()
|
||||
|
||||
minerBor := NewBorDefaultMiner(t)
|
||||
defer func() {
|
||||
minerBor.Cleanup(false)
|
||||
minerBor.Ctrl.Finish()
|
||||
}()
|
||||
|
||||
miner := minerBor.Miner
|
||||
|
||||
waitForMiningState(t, miner, false)
|
||||
miner.Start(common.HexToAddress("0x12345"))
|
||||
waitForMiningState(t, miner, true)
|
||||
miner.Stop()
|
||||
waitForMiningState(t, miner, false)
|
||||
|
||||
waitForMiningState(t, miner, true)
|
||||
|
||||
miner.Stop()
|
||||
|
||||
waitForMiningState(t, miner, false)
|
||||
}
|
||||
|
||||
func TestCloseMiner(t *testing.T) {
|
||||
miner, _, cleanup := createMiner(t)
|
||||
defer cleanup(true)
|
||||
t.Parallel()
|
||||
|
||||
minerBor := NewBorDefaultMiner(t)
|
||||
defer func() {
|
||||
minerBor.Cleanup(true)
|
||||
minerBor.Ctrl.Finish()
|
||||
}()
|
||||
|
||||
miner := minerBor.Miner
|
||||
|
||||
waitForMiningState(t, miner, false)
|
||||
|
||||
miner.Start(common.HexToAddress("0x12345"))
|
||||
|
||||
waitForMiningState(t, miner, true)
|
||||
|
||||
// Terminate the miner and wait for the update loop to run
|
||||
miner.Close()
|
||||
|
||||
waitForMiningState(t, miner, false)
|
||||
}
|
||||
|
||||
// TestMinerSetEtherbase checks that etherbase becomes set even if mining isn't
|
||||
// possible at the moment
|
||||
func TestMinerSetEtherbase(t *testing.T) {
|
||||
miner, mux, cleanup := createMiner(t)
|
||||
defer cleanup(false)
|
||||
t.Parallel()
|
||||
|
||||
minerBor := NewBorDefaultMiner(t)
|
||||
defer func() {
|
||||
minerBor.Cleanup(false)
|
||||
minerBor.Ctrl.Finish()
|
||||
}()
|
||||
|
||||
miner := minerBor.Miner
|
||||
mux := minerBor.Mux
|
||||
|
||||
// Start with a 'bad' mining address
|
||||
miner.Start(common.HexToAddress("0xdead"))
|
||||
waitForMiningState(t, miner, true)
|
||||
|
||||
// Start the downloader
|
||||
mux.Post(downloader.StartEvent{})
|
||||
waitForMiningState(t, miner, false)
|
||||
|
||||
// Now user tries to configure proper mining address
|
||||
miner.Start(common.HexToAddress("0x1337"))
|
||||
|
||||
// Stop the downloader and wait for the update loop to run
|
||||
mux.Post(downloader.DoneEvent{})
|
||||
|
||||
waitForMiningState(t, miner, true)
|
||||
|
||||
// The miner should now be using the good address
|
||||
if got, exp := miner.coinbase, common.HexToAddress("0x1337"); got != exp {
|
||||
t.Fatalf("Wrong coinbase, got %x expected %x", got, exp)
|
||||
|
|
@ -239,46 +257,6 @@ func waitForMiningState(t *testing.T, m *Miner, mining bool) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatalf("Mining() == %t, want %t", state, mining)
|
||||
}
|
||||
|
||||
func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) {
|
||||
// Create Ethash config
|
||||
config := Config{
|
||||
Etherbase: common.HexToAddress("123456789"),
|
||||
}
|
||||
// Create chainConfig
|
||||
memdb := memorydb.New()
|
||||
chainDB := rawdb.NewDatabase(memdb)
|
||||
genesis := core.DeveloperGenesisBlock(15, 11_500_000, common.HexToAddress("12345"))
|
||||
chainConfig, _, err := core.SetupGenesisBlock(chainDB, genesis)
|
||||
if err != nil {
|
||||
t.Fatalf("can't create new chain config: %v", err)
|
||||
}
|
||||
// Create consensus engine
|
||||
engine := clique.New(chainConfig.Clique, chainDB)
|
||||
// Create Ethereum backend
|
||||
consensus.NewMerger(rawdb.NewMemoryDatabase())
|
||||
bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("can't create new chain %v", err)
|
||||
}
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(chainDB), nil)
|
||||
blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)}
|
||||
|
||||
pool := core.NewTxPool(testTxPoolConfig, chainConfig, blockchain)
|
||||
backend := NewMockBackend(bc, pool)
|
||||
// Create event Mux
|
||||
mux := new(event.TypeMux)
|
||||
// Create Miner
|
||||
miner := New(backend, &config, chainConfig, mux, engine, nil)
|
||||
cleanup := func(skipMiner bool) {
|
||||
bc.Stop()
|
||||
engine.Close()
|
||||
pool.Stop()
|
||||
if !skipMiner {
|
||||
miner.Close()
|
||||
}
|
||||
}
|
||||
return miner, mux, cleanup
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ func TestUnconfirmedInsertBounds(t *testing.T) {
|
|||
for i := 0; i < int(depth); i++ {
|
||||
pool.Insert(depth, [32]byte{byte(depth), byte(i)})
|
||||
}
|
||||
|
||||
// Validate that no blocks below the depth allowance are left in
|
||||
pool.blocks.Do(func(block interface{}) {
|
||||
if block := block.(*unconfirmedBlock); block.index+uint64(limit) <= depth {
|
||||
|
|
@ -64,23 +65,29 @@ func TestUnconfirmedShifts(t *testing.T) {
|
|||
for depth := start; depth < start+uint64(limit); depth++ {
|
||||
pool.Insert(depth, [32]byte{byte(depth)})
|
||||
}
|
||||
|
||||
// Try to shift below the limit and ensure no blocks are dropped
|
||||
pool.Shift(start + uint64(limit) - 1)
|
||||
if n := pool.blocks.Len(); n != int(limit) {
|
||||
t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit)
|
||||
}
|
||||
|
||||
// Try to shift half the blocks out and verify remainder
|
||||
pool.Shift(start + uint64(limit) - 1 + uint64(limit/2))
|
||||
if n := pool.blocks.Len(); n != int(limit)/2 {
|
||||
t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit/2)
|
||||
}
|
||||
|
||||
// Try to shift all the remaining blocks out and verify emptyness
|
||||
pool.Shift(start + 2*uint64(limit))
|
||||
|
||||
if n := pool.blocks.Len(); n != 0 {
|
||||
t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0)
|
||||
}
|
||||
|
||||
// Try to shift out from the empty set and make sure it doesn't break
|
||||
pool.Shift(start + 3*uint64(limit))
|
||||
|
||||
if n := pool.blocks.Len(); n != 0 {
|
||||
t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
|
|
@ -393,8 +394,10 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t
|
|||
prevF = float64(prev.Nanoseconds())
|
||||
next float64
|
||||
)
|
||||
|
||||
if inc {
|
||||
next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias)
|
||||
|
||||
max := float64(maxRecommitInterval.Nanoseconds())
|
||||
if next > max {
|
||||
next = max
|
||||
|
|
@ -406,6 +409,7 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t
|
|||
next = min
|
||||
}
|
||||
}
|
||||
|
||||
return time.Duration(int64(next))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,14 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/api"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
|
@ -38,6 +43,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -49,43 +55,9 @@ const (
|
|||
testGas = 144109
|
||||
)
|
||||
|
||||
var (
|
||||
// Test chain configurations
|
||||
testTxPoolConfig core.TxPoolConfig
|
||||
ethashChainConfig *params.ChainConfig
|
||||
cliqueChainConfig *params.ChainConfig
|
||||
|
||||
// Test accounts
|
||||
testBankKey, _ = crypto.GenerateKey()
|
||||
testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey)
|
||||
testBankFunds = big.NewInt(1000000000000000000)
|
||||
|
||||
testUserKey, _ = crypto.GenerateKey()
|
||||
testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey)
|
||||
|
||||
// Test transactions
|
||||
pendingTxs []*types.Transaction
|
||||
newTxs []*types.Transaction
|
||||
|
||||
testConfig = &Config{
|
||||
Recommit: time.Second,
|
||||
GasCeil: params.GenesisGasLimit,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
testTxPoolConfig = core.DefaultTxPoolConfig
|
||||
testTxPoolConfig.Journal = ""
|
||||
ethashChainConfig = new(params.ChainConfig)
|
||||
*ethashChainConfig = *params.TestChainConfig
|
||||
cliqueChainConfig = new(params.ChainConfig)
|
||||
*cliqueChainConfig = *params.TestChainConfig
|
||||
cliqueChainConfig.Clique = ¶ms.CliqueConfig{
|
||||
Period: 10,
|
||||
Epoch: 30000,
|
||||
}
|
||||
|
||||
signer := types.LatestSigner(params.TestChainConfig)
|
||||
|
||||
tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{
|
||||
ChainID: params.TestChainConfig.ChainID,
|
||||
Nonce: 0,
|
||||
|
|
@ -94,6 +66,7 @@ func init() {
|
|||
Gas: params.TxGas,
|
||||
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||
})
|
||||
|
||||
pendingTxs = append(pendingTxs, tx1)
|
||||
|
||||
tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{
|
||||
|
|
@ -103,6 +76,7 @@ func init() {
|
|||
Gas: params.TxGas,
|
||||
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||
})
|
||||
|
||||
newTxs = append(newTxs, tx2)
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
|
@ -125,6 +99,12 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
|
|||
}
|
||||
|
||||
switch e := engine.(type) {
|
||||
case *bor.Bor:
|
||||
gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength)
|
||||
copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes())
|
||||
e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) {
|
||||
return crypto.Sign(crypto.Keccak256(data), testBankKey)
|
||||
})
|
||||
case *clique.Clique:
|
||||
gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength)
|
||||
copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes())
|
||||
|
|
@ -135,6 +115,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
|
|||
default:
|
||||
t.Fatalf("unexpected consensus engine type: %T", engine)
|
||||
}
|
||||
|
||||
genesis := gspec.MustCommit(db)
|
||||
|
||||
chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil)
|
||||
|
|
@ -149,10 +130,12 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
|
|||
t.Fatalf("failed to insert origin chain: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
parent := genesis
|
||||
if n > 0 {
|
||||
parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash())
|
||||
}
|
||||
|
||||
blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) {
|
||||
gen.SetCoinbase(testUserAddress)
|
||||
})
|
||||
|
|
@ -174,28 +157,36 @@ func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base
|
|||
|
||||
func (b *testWorkerBackend) newRandomUncle() *types.Block {
|
||||
var parent *types.Block
|
||||
|
||||
cur := b.chain.CurrentBlock()
|
||||
|
||||
if cur.NumberU64() == 0 {
|
||||
parent = b.chain.Genesis()
|
||||
} else {
|
||||
parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash())
|
||||
}
|
||||
|
||||
blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) {
|
||||
var addr = make([]byte, common.AddressLength)
|
||||
|
||||
rand.Read(addr)
|
||||
gen.SetCoinbase(common.BytesToAddress(addr))
|
||||
})
|
||||
|
||||
return blocks[0]
|
||||
}
|
||||
|
||||
func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
|
||||
var tx *types.Transaction
|
||||
|
||||
gasPrice := big.NewInt(10 * params.InitialBaseFee)
|
||||
|
||||
if creation {
|
||||
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey)
|
||||
} else {
|
||||
tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey)
|
||||
}
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
|
|
@ -204,23 +195,64 @@ func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consens
|
|||
backend.txPool.AddLocals(pendingTxs)
|
||||
w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false)
|
||||
w.setEtherbase(testBankAddress)
|
||||
|
||||
return w, backend
|
||||
}
|
||||
|
||||
func TestGenerateBlockAndImportEthash(t *testing.T) {
|
||||
testGenerateBlockAndImport(t, false)
|
||||
t.Parallel()
|
||||
|
||||
testGenerateBlockAndImport(t, false, false)
|
||||
}
|
||||
|
||||
func TestGenerateBlockAndImportClique(t *testing.T) {
|
||||
testGenerateBlockAndImport(t, true)
|
||||
t.Parallel()
|
||||
|
||||
testGenerateBlockAndImport(t, true, false)
|
||||
}
|
||||
|
||||
func testGenerateBlockAndImport(t *testing.T, isClique bool) {
|
||||
func TestGenerateBlockAndImportBor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testGenerateBlockAndImport(t, false, true)
|
||||
}
|
||||
|
||||
//nolint:thelper
|
||||
func testGenerateBlockAndImport(t *testing.T, isClique bool, isBor bool) {
|
||||
var (
|
||||
engine consensus.Engine
|
||||
chainConfig *params.ChainConfig
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
)
|
||||
|
||||
if isBor {
|
||||
chainConfig = params.BorUnittestChainConfig
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ethAPIMock := api.NewMockCaller(ctrl)
|
||||
ethAPIMock.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
spanner := bor.NewMockSpanner(ctrl)
|
||||
spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
{
|
||||
ID: 0,
|
||||
Address: testBankAddress,
|
||||
VotingPower: 100,
|
||||
ProposerPriority: 0,
|
||||
},
|
||||
}, nil).AnyTimes()
|
||||
|
||||
heimdallClientMock := mocks.NewMockIHeimdallClient(ctrl)
|
||||
heimdallClientMock.EXPECT().Close().Times(1)
|
||||
|
||||
contractMock := bor.NewMockGenesisContract(ctrl)
|
||||
|
||||
db, _, _ = NewDBForFakes(t)
|
||||
|
||||
engine = NewFakeBor(t, db, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock)
|
||||
} else {
|
||||
if isClique {
|
||||
chainConfig = params.AllCliqueProtocolChanges
|
||||
chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000}
|
||||
|
|
@ -229,14 +261,19 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) {
|
|||
chainConfig = params.AllEthashProtocolChanges
|
||||
engine = ethash.NewFaker()
|
||||
}
|
||||
}
|
||||
|
||||
defer engine.Close()
|
||||
|
||||
chainConfig.LondonBlock = big.NewInt(0)
|
||||
|
||||
w, b := newTestWorker(t, chainConfig, engine, db, 0)
|
||||
defer w.close()
|
||||
|
||||
// This test chain imports the mined blocks.
|
||||
db2 := rawdb.NewMemoryDatabase()
|
||||
b.genesis.MustCommit(db2)
|
||||
|
||||
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil)
|
||||
defer chain.Stop()
|
||||
|
||||
|
|
@ -287,20 +324,25 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens
|
|||
taskIndex int
|
||||
taskCh = make(chan struct{}, 2)
|
||||
)
|
||||
|
||||
checkEqual := func(t *testing.T, task *task, index int) {
|
||||
// The first empty work without any txs included
|
||||
receiptLen, balance := 0, big.NewInt(0)
|
||||
|
||||
if index == 1 {
|
||||
// The second full work with 1 tx included
|
||||
receiptLen, balance = 1, big.NewInt(1000)
|
||||
}
|
||||
|
||||
if len(task.receipts) != receiptLen {
|
||||
t.Fatalf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen)
|
||||
}
|
||||
|
||||
if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 {
|
||||
t.Fatalf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance)
|
||||
}
|
||||
}
|
||||
|
||||
w.newTaskHook = func(task *task) {
|
||||
if task.block.NumberU64() == 1 {
|
||||
checkEqual(t, task, taskIndex)
|
||||
|
|
@ -308,11 +350,14 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens
|
|||
taskCh <- struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
w.skipSealHook = func(task *task) bool { return true }
|
||||
w.fullTaskHook = func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
w.start() // Start mining!
|
||||
|
||||
for i := 0; i < 2; i += 1 {
|
||||
select {
|
||||
case <-taskCh:
|
||||
|
|
@ -344,16 +389,20 @@ func TestStreamUncleBlock(t *testing.T) {
|
|||
t.Errorf("uncle hash mismatch: have %s, want %s", have.Hex(), want.Hex())
|
||||
}
|
||||
}
|
||||
|
||||
taskCh <- struct{}{}
|
||||
taskIndex += 1
|
||||
}
|
||||
}
|
||||
|
||||
w.skipSealHook = func(task *task) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
w.fullTaskHook = func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
w.start()
|
||||
|
||||
for i := 0; i < 2; i += 1 {
|
||||
|
|
@ -396,20 +445,25 @@ func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, en
|
|||
// one has 1 pending tx, the third one has 2 txs
|
||||
if taskIndex == 2 {
|
||||
receiptLen, balance := 2, big.NewInt(2000)
|
||||
|
||||
if len(task.receipts) != receiptLen {
|
||||
t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen)
|
||||
}
|
||||
|
||||
if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 {
|
||||
t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance)
|
||||
}
|
||||
}
|
||||
|
||||
taskCh <- struct{}{}
|
||||
taskIndex += 1
|
||||
}
|
||||
}
|
||||
|
||||
w.skipSealHook = func(task *task) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
w.fullTaskHook = func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
|
@ -423,6 +477,7 @@ func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, en
|
|||
t.Error("new task timeout")
|
||||
}
|
||||
}
|
||||
|
||||
b.txPool.AddLocals(newTxs)
|
||||
time.Sleep(time.Second)
|
||||
|
||||
|
|
@ -459,6 +514,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
index = 0
|
||||
start uint32
|
||||
)
|
||||
|
||||
w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) {
|
||||
// Short circuit if interval checking hasn't started.
|
||||
if atomic.LoadUint32(&start) == 0 {
|
||||
|
|
@ -489,16 +545,19 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
if recommitInterval != wantRecommitInterval {
|
||||
t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval)
|
||||
}
|
||||
|
||||
result = append(result, float64(recommitInterval.Nanoseconds()))
|
||||
index += 1
|
||||
progress <- struct{}{}
|
||||
}
|
||||
|
||||
w.start()
|
||||
|
||||
time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt
|
||||
atomic.StoreUint32(&start, 1)
|
||||
|
||||
w.setRecommitInterval(3 * time.Second)
|
||||
|
||||
select {
|
||||
case <-progress:
|
||||
case <-time.NewTimer(time.Second).C:
|
||||
|
|
@ -506,6 +565,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
}
|
||||
|
||||
w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8}
|
||||
|
||||
select {
|
||||
case <-progress:
|
||||
case <-time.NewTimer(time.Second).C:
|
||||
|
|
@ -513,6 +573,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
}
|
||||
|
||||
w.resubmitAdjustCh <- &intervalAdjust{inc: false}
|
||||
|
||||
select {
|
||||
case <-progress:
|
||||
case <-time.NewTimer(time.Second).C:
|
||||
|
|
@ -520,6 +581,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
}
|
||||
|
||||
w.setRecommitInterval(500 * time.Millisecond)
|
||||
|
||||
select {
|
||||
case <-progress:
|
||||
case <-time.NewTimer(time.Second).C:
|
||||
|
|
@ -554,9 +616,11 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
w.skipSealHook = func(task *task) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
w.fullTaskHook = func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
timestamp := uint64(time.Now().Unix())
|
||||
assertBlock := func(block *types.Block, number uint64, coinbase common.Address, random common.Hash) {
|
||||
if block.Time() != timestamp {
|
||||
|
|
@ -564,14 +628,17 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
// is even smaller than parent block's. It's OK.
|
||||
t.Logf("Invalid timestamp, want %d, get %d", timestamp, block.Time())
|
||||
}
|
||||
|
||||
if len(block.Uncles()) != 0 {
|
||||
t.Error("Unexpected uncle block")
|
||||
}
|
||||
|
||||
_, isClique := engine.(*clique.Clique)
|
||||
if !isClique {
|
||||
if len(block.Extra()) != 0 {
|
||||
t.Error("Unexpected extra field")
|
||||
}
|
||||
|
||||
if block.Coinbase() != coinbase {
|
||||
t.Errorf("Unexpected coinbase got %x want %x", block.Coinbase(), coinbase)
|
||||
}
|
||||
|
|
@ -580,18 +647,22 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
t.Error("Unexpected coinbase")
|
||||
}
|
||||
}
|
||||
|
||||
if !isClique {
|
||||
if block.MixDigest() != random {
|
||||
t.Error("Unexpected mix digest")
|
||||
}
|
||||
}
|
||||
|
||||
if block.Nonce() != 0 {
|
||||
t.Error("Unexpected block nonce")
|
||||
}
|
||||
|
||||
if block.NumberU64() != number {
|
||||
t.Errorf("Mismatched block number, want %d got %d", number, block.NumberU64())
|
||||
}
|
||||
}
|
||||
|
||||
var cases = []struct {
|
||||
parent common.Hash
|
||||
coinbase common.Address
|
||||
|
|
@ -639,6 +710,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
// This API should work even when the automatic sealing is not enabled
|
||||
for _, c := range cases {
|
||||
block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random)
|
||||
|
||||
if c.expectErr {
|
||||
if err == nil {
|
||||
t.Error("Expect error but get nil")
|
||||
|
|
@ -647,12 +719,14 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
assertBlock(block, c.expectNumber, c.coinbase, c.random)
|
||||
}
|
||||
}
|
||||
|
||||
// This API should work even when the automatic sealing is enabled
|
||||
w.start()
|
||||
|
||||
for _, c := range cases {
|
||||
block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random)
|
||||
if c.expectErr {
|
||||
|
|
@ -663,6 +737,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
assertBlock(block, c.expectNumber, c.coinbase, c.random)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ import (
|
|||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// Genesis hashes to enforce below configs on.
|
||||
|
|
@ -289,6 +290,38 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
BorUnittestChainConfig = &ChainConfig{
|
||||
ChainID: big.NewInt(80001),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: true,
|
||||
EIP150Hash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ConstantinopleBlock: big.NewInt(0),
|
||||
PetersburgBlock: big.NewInt(0),
|
||||
IstanbulBlock: big.NewInt(0),
|
||||
MuirGlacierBlock: big.NewInt(0),
|
||||
BerlinBlock: big.NewInt(0),
|
||||
LondonBlock: big.NewInt(0),
|
||||
Bor: &BorConfig{
|
||||
Period: map[string]uint64{
|
||||
"0": 1,
|
||||
},
|
||||
ProducerDelay: 3,
|
||||
Sprint: 32,
|
||||
BackupMultiplier: map[string]uint64{
|
||||
"0": 2,
|
||||
},
|
||||
ValidatorContract: "0x0000000000000000000000000000000000001000",
|
||||
StateReceiverContract: "0x0000000000000000000000000000000000001001",
|
||||
BurntContract: map[string]string{
|
||||
"0": "0x00000000000000000000000000000000000000000",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// MumbaiChainConfig contains the chain parameters to run a node on the Mumbai test network.
|
||||
MumbaiChainConfig = &ChainConfig{
|
||||
|
|
@ -550,7 +583,9 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin
|
|||
for k := range field {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for i := 0; i < len(keys)-1; i++ {
|
||||
valUint, _ := strconv.ParseUint(keys[i], 10, 64)
|
||||
valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64)
|
||||
|
|
@ -558,6 +593,7 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin
|
|||
return field[keys[i]]
|
||||
}
|
||||
}
|
||||
|
||||
return field[keys[len(keys)-1]]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@ package bor
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
|
|
@ -22,12 +25,12 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
var (
|
||||
const (
|
||||
spanPath = "bor/span/1"
|
||||
clerkPath = "clerk/event-record/list"
|
||||
clerkQueryParams = "from-time=%d&to-time=%d&page=%d&limit=50"
|
||||
|
|
@ -38,7 +41,10 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
|||
chain := init.ethereum.BlockChain()
|
||||
engine := init.ethereum.Engine()
|
||||
_bor := engine.(*bor.Bor)
|
||||
h, heimdallSpan := getMockedHeimdallClient(t)
|
||||
|
||||
h, heimdallSpan, ctrl := getMockedHeimdallClient(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
_bor.SetHeimdallClient(h)
|
||||
|
||||
db := init.ethereum.ChainDb()
|
||||
|
|
@ -51,7 +57,6 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
|||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
||||
assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
|
||||
validators, err := _bor.GetCurrentValidators(block.Hash(), spanSize) // check validator set at the first block of new span
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
|
|
@ -82,8 +87,12 @@ func TestFetchStateSyncEvents(t *testing.T) {
|
|||
// B. Before inserting 1st block of the next sprint, mock heimdall deps
|
||||
// B.1 Mock /bor/span/1
|
||||
res, _ := loadSpanFromFile(t)
|
||||
h := &mocks.IHeimdallClient{}
|
||||
h.On("FetchWithRetry", spanPath, "").Return(res, nil)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||
h.EXPECT().Span(uint64(1)).Return(&res.Result, nil).AnyTimes()
|
||||
|
||||
// B.2 Mock State Sync events
|
||||
fromID := uint64(1)
|
||||
|
|
@ -94,14 +103,12 @@ func TestFetchStateSyncEvents(t *testing.T) {
|
|||
sample := getSampleEventRecord(t)
|
||||
sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to
|
||||
eventRecords := generateFakeStateSyncEvents(sample, eventCount)
|
||||
h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
|
||||
|
||||
h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes()
|
||||
_bor.SetHeimdallClient(h)
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||
insertNewBlock(t, chain, block)
|
||||
|
||||
assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
|
||||
assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
|
||||
}
|
||||
|
||||
func TestFetchStateSyncEvents_2(t *testing.T) {
|
||||
|
|
@ -112,8 +119,12 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
|
||||
// Mock /bor/span/1
|
||||
res, _ := loadSpanFromFile(t)
|
||||
h := &mocks.IHeimdallClient{}
|
||||
h.On("FetchWithRetry", spanPath, "").Return(res, nil)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||
h.EXPECT().Span(uint64(1)).Return(&res.Result, nil).AnyTimes()
|
||||
|
||||
// Mock State Sync events
|
||||
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
||||
|
|
@ -123,7 +134,7 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
|
||||
// First query will be from [id=1, (block-sprint).Time]
|
||||
// Insert 5 events in this time range
|
||||
eventRecords := []*bor.EventRecordWithTime{
|
||||
eventRecords := []*clerk.EventRecordWithTime{
|
||||
buildStateEvent(sample, 1, 3), // id = 1, time = 1
|
||||
buildStateEvent(sample, 2, 1), // id = 2, time = 3
|
||||
buildStateEvent(sample, 3, 2), // id = 3, time = 2
|
||||
|
|
@ -131,7 +142,8 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
buildStateEvent(sample, 4, 5), // id = 4, time = 5
|
||||
buildStateEvent(sample, 6, 4), // id = 6, time = 4
|
||||
}
|
||||
h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
|
||||
|
||||
h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes()
|
||||
_bor.SetHeimdallClient(h)
|
||||
|
||||
// Insert blocks for 0th sprint
|
||||
|
|
@ -141,25 +153,27 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
|
||||
assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
|
||||
|
||||
lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize)
|
||||
|
||||
// state 6 was not written
|
||||
assert.Equal(t, uint64(4), lastStateID.Uint64())
|
||||
|
||||
//
|
||||
fromID = uint64(5)
|
||||
to = int64(chain.GetHeaderByNumber(sprintSize).Time)
|
||||
eventRecords = []*bor.EventRecordWithTime{
|
||||
|
||||
eventRecords = []*clerk.EventRecordWithTime{
|
||||
buildStateEvent(sample, 5, 7),
|
||||
buildStateEvent(sample, 6, 4),
|
||||
}
|
||||
h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
|
||||
h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes()
|
||||
|
||||
for i := sprintSize + 1; i <= spanSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
|
||||
|
||||
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
|
||||
assert.Equal(t, uint64(6), lastStateID.Uint64())
|
||||
}
|
||||
|
|
@ -169,7 +183,10 @@ func TestOutOfTurnSigning(t *testing.T) {
|
|||
chain := init.ethereum.BlockChain()
|
||||
engine := init.ethereum.Engine()
|
||||
_bor := engine.(*bor.Bor)
|
||||
h, _ := getMockedHeimdallClient(t)
|
||||
|
||||
h, _, ctrl := getMockedHeimdallClient(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
_bor.SetHeimdallClient(h)
|
||||
|
||||
db := init.ethereum.ChainDb()
|
||||
|
|
@ -217,7 +234,10 @@ func TestSignerNotFound(t *testing.T) {
|
|||
chain := init.ethereum.BlockChain()
|
||||
engine := init.ethereum.Engine()
|
||||
_bor := engine.(*bor.Bor)
|
||||
h, _ := getMockedHeimdallClient(t)
|
||||
|
||||
h, _, ctrl := getMockedHeimdallClient(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
_bor.SetHeimdallClient(h)
|
||||
|
||||
db := init.ethereum.ChainDb()
|
||||
|
|
@ -236,47 +256,46 @@ func TestSignerNotFound(t *testing.T) {
|
|||
bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()})
|
||||
}
|
||||
|
||||
func getMockedHeimdallClient(t *testing.T) (*mocks.IHeimdallClient, *bor.HeimdallSpan) {
|
||||
res, heimdallSpan := loadSpanFromFile(t)
|
||||
h := &mocks.IHeimdallClient{}
|
||||
h.On("FetchWithRetry", "bor/span/1", "").Return(res, nil)
|
||||
h.On(
|
||||
"FetchStateSyncEvents",
|
||||
mock.AnythingOfType("uint64"),
|
||||
mock.AnythingOfType("int64")).Return([]*bor.EventRecordWithTime{getSampleEventRecord(t)}, nil)
|
||||
return h, heimdallSpan
|
||||
func getMockedHeimdallClient(t *testing.T) (*mocks.MockIHeimdallClient, *span.HeimdallSpan, *gomock.Controller) {
|
||||
ctrl := gomock.NewController(t)
|
||||
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||
|
||||
_, heimdallSpan := loadSpanFromFile(t)
|
||||
|
||||
h.EXPECT().Span(uint64(1)).Return(heimdallSpan, nil).AnyTimes()
|
||||
|
||||
h.EXPECT().StateSyncEvents(gomock.Any(), gomock.Any()).
|
||||
Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes()
|
||||
|
||||
return h, heimdallSpan, ctrl
|
||||
}
|
||||
|
||||
func generateFakeStateSyncEvents(sample *bor.EventRecordWithTime, count int) []*bor.EventRecordWithTime {
|
||||
events := make([]*bor.EventRecordWithTime, count)
|
||||
func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime {
|
||||
events := make([]*clerk.EventRecordWithTime, count)
|
||||
event := *sample
|
||||
event.ID = 1
|
||||
events[0] = &bor.EventRecordWithTime{}
|
||||
events[0] = &clerk.EventRecordWithTime{}
|
||||
*events[0] = event
|
||||
for i := 1; i < count; i++ {
|
||||
event.ID = uint64(i)
|
||||
event.Time = event.Time.Add(1 * time.Second)
|
||||
events[i] = &bor.EventRecordWithTime{}
|
||||
events[i] = &clerk.EventRecordWithTime{}
|
||||
*events[i] = event
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
func buildStateEvent(sample *bor.EventRecordWithTime, id uint64, timeStamp int64) *bor.EventRecordWithTime {
|
||||
func buildStateEvent(sample *clerk.EventRecordWithTime, id uint64, timeStamp int64) *clerk.EventRecordWithTime {
|
||||
event := *sample
|
||||
event.ID = id
|
||||
event.Time = time.Unix(timeStamp, 0)
|
||||
return &event
|
||||
}
|
||||
|
||||
func getSampleEventRecord(t *testing.T) *bor.EventRecordWithTime {
|
||||
res := stateSyncEventsPayload(t)
|
||||
var _eventRecords []*bor.EventRecordWithTime
|
||||
if err := json.Unmarshal(res.Result, &_eventRecords); err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
_eventRecords[0].Time = time.Unix(1, 0)
|
||||
return _eventRecords[0]
|
||||
func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime {
|
||||
eventRecords := stateSyncEventsPayload(t)
|
||||
eventRecords.Result[0].Time = time.Unix(1, 0)
|
||||
return eventRecords.Result[0]
|
||||
}
|
||||
|
||||
// TestEIP1559Transition tests the following:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ import (
|
|||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -46,17 +49,23 @@ type initializeData struct {
|
|||
}
|
||||
|
||||
func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
||||
t.Helper()
|
||||
|
||||
genesisData, err := ioutil.ReadFile("./testdata/genesis.json")
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
gen := &core.Genesis{}
|
||||
|
||||
if err := json.Unmarshal(genesisData, gen); err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
ethConf := ð.Config{
|
||||
Genesis: gen,
|
||||
}
|
||||
|
||||
ethConf.Genesis.MustCommit(db)
|
||||
|
||||
ethereum := utils.CreateBorEthereum(ethConf)
|
||||
|
|
@ -65,6 +74,7 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
|||
}
|
||||
|
||||
ethConf.Genesis.MustCommit(ethereum.ChainDb())
|
||||
|
||||
return &initializeData{
|
||||
genesis: gen,
|
||||
ethereum: ethereum,
|
||||
|
|
@ -72,12 +82,16 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
|||
}
|
||||
|
||||
func insertNewBlock(t *testing.T, chain *core.BlockChain, block *types.Block) {
|
||||
t.Helper()
|
||||
|
||||
if _, err := chain.InsertChain([]*types.Block{block}); err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *types.Block, signer []byte, borConfig *params.BorConfig) *types.Block {
|
||||
t.Helper()
|
||||
|
||||
header := block.Header()
|
||||
header.Number.Add(header.Number, big.NewInt(1))
|
||||
number := header.Number.Uint64()
|
||||
|
|
@ -90,11 +104,12 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *
|
|||
header.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig)
|
||||
header.Extra = make([]byte, 32+65) // vanity + extraSeal
|
||||
|
||||
currentValidators := []*bor.Validator{bor.NewValidator(addr, 10)}
|
||||
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
|
||||
isSpanEnd := (number+1)%spanSize == 0
|
||||
isSpanStart := number%spanSize == 0
|
||||
isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0
|
||||
|
||||
if isSpanEnd {
|
||||
_, heimdallSpan := loadSpanFromFile(t)
|
||||
// this is to stash the validator bytes in the header
|
||||
|
|
@ -102,18 +117,23 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *
|
|||
} else if isSpanStart {
|
||||
header.Difficulty = new(big.Int).SetInt64(3)
|
||||
}
|
||||
|
||||
if isSprintEnd {
|
||||
sort.Sort(bor.ValidatorsByAddress(currentValidators))
|
||||
sort.Sort(valset.ValidatorsByAddress(currentValidators))
|
||||
|
||||
validatorBytes := make([]byte, len(currentValidators)*validatorHeaderBytesLength)
|
||||
header.Extra = make([]byte, 32+len(validatorBytes)+65) // vanity + validatorBytes + extraSeal
|
||||
|
||||
for i, val := range currentValidators {
|
||||
copy(validatorBytes[i*validatorHeaderBytesLength:], val.HeaderBytes())
|
||||
}
|
||||
|
||||
copy(header.Extra[32:], validatorBytes)
|
||||
}
|
||||
|
||||
if chain.Config().IsLondon(header.Number) {
|
||||
header.BaseFee = misc.CalcBaseFee(chain.Config(), block.Header())
|
||||
|
||||
if !chain.Config().IsLondon(block.Number()) {
|
||||
parentGasLimit := block.GasLimit() * params.ElasticityMultiplier
|
||||
header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit)
|
||||
|
|
@ -124,58 +144,73 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *
|
|||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
_, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
sign(t, header, signer, borConfig)
|
||||
|
||||
return types.NewBlockWithHeader(header)
|
||||
}
|
||||
|
||||
func sign(t *testing.T, header *types.Header, signer []byte, c *params.BorConfig) {
|
||||
t.Helper()
|
||||
|
||||
sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header, c)), signer)
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
copy(header.Extra[len(header.Extra)-extraSeal:], sig)
|
||||
}
|
||||
|
||||
func stateSyncEventsPayload(t *testing.T) *bor.ResponseWithHeight {
|
||||
//nolint:unused,deadcode
|
||||
func stateSyncEventsPayload(t *testing.T) *heimdall.StateSyncEventsResponse {
|
||||
t.Helper()
|
||||
|
||||
stateData, err := ioutil.ReadFile("./testdata/states.json")
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
res := &bor.ResponseWithHeight{}
|
||||
|
||||
res := &heimdall.StateSyncEventsResponse{}
|
||||
if err := json.Unmarshal(stateData, res); err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func loadSpanFromFile(t *testing.T) (*bor.ResponseWithHeight, *bor.HeimdallSpan) {
|
||||
//nolint:unused,deadcode
|
||||
func loadSpanFromFile(t *testing.T) (*heimdall.SpanResponse, *span.HeimdallSpan) {
|
||||
t.Helper()
|
||||
|
||||
spanData, err := ioutil.ReadFile("./testdata/span.json")
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
res := &bor.ResponseWithHeight{}
|
||||
|
||||
res := &heimdall.SpanResponse{}
|
||||
|
||||
if err := json.Unmarshal(spanData, res); err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
heimdallSpan := &bor.HeimdallSpan{}
|
||||
if err := json.Unmarshal(res.Result, heimdallSpan); err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
return res, heimdallSpan
|
||||
return res, &res.Result
|
||||
}
|
||||
|
||||
func getSignerKey(number uint64) []byte {
|
||||
signerKey := privKey
|
||||
|
||||
isSpanStart := number%spanSize == 0
|
||||
if isSpanStart {
|
||||
// validator set in the new span has changed
|
||||
signerKey = privKey2
|
||||
}
|
||||
|
||||
_key, _ := hex.DecodeString(signerKey)
|
||||
|
||||
return _key
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,87 +1,78 @@
|
|||
// Code generated by mockery v2.10.0. DO NOT EDIT.
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: IHeimdallClient)
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
bor "github.com/ethereum/go-ethereum/consensus/bor"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
reflect "reflect"
|
||||
|
||||
clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
span "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// IHeimdallClient is an autogenerated mock type for the IHeimdallClient type
|
||||
type IHeimdallClient struct {
|
||||
mock.Mock
|
||||
// MockIHeimdallClient is a mock of IHeimdallClient interface.
|
||||
type MockIHeimdallClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockIHeimdallClientMockRecorder
|
||||
}
|
||||
|
||||
// Close provides a mock function with given fields:
|
||||
func (_m *IHeimdallClient) Close() {
|
||||
_m.Called()
|
||||
// MockIHeimdallClientMockRecorder is the mock recorder for MockIHeimdallClient.
|
||||
type MockIHeimdallClientMockRecorder struct {
|
||||
mock *MockIHeimdallClient
|
||||
}
|
||||
|
||||
// Fetch provides a mock function with given fields: path, query
|
||||
func (_m *IHeimdallClient) Fetch(path string, query string) (*bor.ResponseWithHeight, error) {
|
||||
ret := _m.Called(path, query)
|
||||
|
||||
var r0 *bor.ResponseWithHeight
|
||||
if rf, ok := ret.Get(0).(func(string, string) *bor.ResponseWithHeight); ok {
|
||||
r0 = rf(path, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*bor.ResponseWithHeight)
|
||||
}
|
||||
// NewMockIHeimdallClient creates a new mock instance.
|
||||
func NewMockIHeimdallClient(ctrl *gomock.Controller) *MockIHeimdallClient {
|
||||
mock := &MockIHeimdallClient{ctrl: ctrl}
|
||||
mock.recorder = &MockIHeimdallClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||
r1 = rf(path, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockIHeimdallClient) EXPECT() *MockIHeimdallClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
// Close mocks base method.
|
||||
func (m *MockIHeimdallClient) Close() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Close")
|
||||
}
|
||||
|
||||
// FetchStateSyncEvents provides a mock function with given fields: fromID, to
|
||||
func (_m *IHeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*bor.EventRecordWithTime, error) {
|
||||
ret := _m.Called(fromID, to)
|
||||
|
||||
var r0 []*bor.EventRecordWithTime
|
||||
if rf, ok := ret.Get(0).(func(uint64, int64) []*bor.EventRecordWithTime); ok {
|
||||
r0 = rf(fromID, to)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*bor.EventRecordWithTime)
|
||||
}
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockIHeimdallClientMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIHeimdallClient)(nil).Close))
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(uint64, int64) error); ok {
|
||||
r1 = rf(fromID, to)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
// Span mocks base method.
|
||||
func (m *MockIHeimdallClient) Span(arg0 uint64) (*span.HeimdallSpan, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Span", arg0)
|
||||
ret0, _ := ret[0].(*span.HeimdallSpan)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
// Span indicates an expected call of Span.
|
||||
func (mr *MockIHeimdallClientMockRecorder) Span(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Span", reflect.TypeOf((*MockIHeimdallClient)(nil).Span), arg0)
|
||||
}
|
||||
|
||||
// FetchWithRetry provides a mock function with given fields: path, query
|
||||
func (_m *IHeimdallClient) FetchWithRetry(path string, query string) (*bor.ResponseWithHeight, error) {
|
||||
ret := _m.Called(path, query)
|
||||
|
||||
var r0 *bor.ResponseWithHeight
|
||||
if rf, ok := ret.Get(0).(func(string, string) *bor.ResponseWithHeight); ok {
|
||||
r0 = rf(path, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*bor.ResponseWithHeight)
|
||||
}
|
||||
// StateSyncEvents mocks base method.
|
||||
func (m *MockIHeimdallClient) StateSyncEvents(arg0 uint64, arg1 int64) ([]*clerk.EventRecordWithTime, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StateSyncEvents", arg0, arg1)
|
||||
ret0, _ := ret[0].([]*clerk.EventRecordWithTime)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||
r1 = rf(path, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
// StateSyncEvents indicates an expected call of StateSyncEvents.
|
||||
func (mr *MockIHeimdallClientMockRecorder) StateSyncEvents(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateSyncEvents", reflect.TypeOf((*MockIHeimdallClient)(nil).StateSyncEvents), arg0, arg1)
|
||||
}
|
||||
|
|
|
|||
7
tests/deps/fake.go
Normal file
7
tests/deps/fake.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package deps
|
||||
|
||||
// it is a fake file to lock deps
|
||||
//nolint:typecheck
|
||||
import (
|
||||
_ "github.com/golang/mock/mockgen/model"
|
||||
)
|
||||
|
|
@ -19,9 +19,10 @@ package trie
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// hasher is a type used for the trie Hash operation. A hasher has some
|
||||
|
|
|
|||
Loading…
Reference in a new issue