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.
|
# This file configures github.com/golangci/golangci-lint.
|
||||||
|
|
||||||
run:
|
run:
|
||||||
|
go: '1.18'
|
||||||
timeout: 20m
|
timeout: 20m
|
||||||
tests: true
|
tests: true
|
||||||
# default is true. Enables skipping of directories:
|
# default is true. Enables skipping of directories:
|
||||||
|
|
@ -183,4 +184,4 @@ issues:
|
||||||
max-issues-per-linter: 0
|
max-issues-per-linter: 0
|
||||||
max-same-issues: 0
|
max-same-issues: 0
|
||||||
#new: true
|
#new: true
|
||||||
# new-from-rev: origin/master
|
new-from-rev: origin/master
|
||||||
20
Makefile
20
Makefile
|
|
@ -65,9 +65,7 @@ escape:
|
||||||
cd $(path) && go test -gcflags "-m -m" -run none -bench=BenchmarkJumpdest* -benchmem -memprofile mem.out
|
cd $(path) && go test -gcflags "-m -m" -run none -bench=BenchmarkJumpdest* -benchmem -memprofile mem.out
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
@./build/bin/golangci-lint run --config ./.golangci.yml \
|
@./build/bin/golangci-lint run --config ./.golangci.yml
|
||||||
internal/cli \
|
|
||||||
consensus/bor
|
|
||||||
|
|
||||||
lintci-deps:
|
lintci-deps:
|
||||||
rm -f ./build/bin/golangci-lint
|
rm -f ./build/bin/golangci-lint
|
||||||
|
|
@ -87,16 +85,20 @@ clean:
|
||||||
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
||||||
|
|
||||||
devtools:
|
devtools:
|
||||||
env GOBIN= go install golang.org/x/tools/cmd/stringer@latest
|
# Notice! If you adding new binary - add it also to tests/deps/fake.go file
|
||||||
env GOBIN= go install github.com/kevinburke/go-bindata/go-bindata@latest
|
$(GOBUILD) -o $(GOBIN)/stringer github.com/golang.org/x/tools/cmd/stringer
|
||||||
env GOBIN= go install github.com/fjl/gencodec@latest
|
$(GOBUILD) -o $(GOBIN)/go-bindata github.com/kevinburke/go-bindata/go-bindata
|
||||||
env GOBIN= go install github.com/golang/protobuf/protoc-gen-go@latest
|
$(GOBUILD) -o $(GOBIN)/codecgen github.com/ugorji/go/codec/codecgen
|
||||||
env GOBIN= go install ./cmd/abigen
|
$(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 "solc" 2> /dev/null || echo 'Please install solc'
|
||||||
@type "protoc" 2> /dev/null || echo 'Please install protoc'
|
@type "protoc" 2> /dev/null || echo 'Please install protoc'
|
||||||
|
|
||||||
# Cross Compilation Targets (xgo)
|
# Cross Compilation Targets (xgo)
|
||||||
|
|
||||||
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
|
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
|
||||||
@echo "Full cross compilation done:"
|
@echo "Full cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/geth-*
|
@ls -ld $(GOBIN)/geth-*
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
commands := cli.Commands()
|
commands := cli.Commands()
|
||||||
|
|
||||||
dest := flag.String("d", DefaultDir, "Destination directory where the docs will be generated")
|
dest := flag.String("d", DefaultDir, "Destination directory where the docs will be generated")
|
||||||
|
|
@ -35,10 +34,12 @@ func main() {
|
||||||
|
|
||||||
keys := make([]string, len(commands))
|
keys := make([]string, len(commands))
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
for k := range commands {
|
for k := range commands {
|
||||||
keys[i] = k
|
keys[i] = k
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
for _, name := range keys {
|
for _, name := range keys {
|
||||||
|
|
@ -60,12 +61,17 @@ func main() {
|
||||||
|
|
||||||
func overwriteFile(filePath string, text string) {
|
func overwriteFile(filePath string, text string) {
|
||||||
log.Printf("Writing to page: %s\n", filePath)
|
log.Printf("Writing to page: %s\n", filePath)
|
||||||
|
|
||||||
f, err := os.Create(filePath)
|
f, err := os.Create(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
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)
|
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/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"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/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
@ -206,10 +207,10 @@ func (api *API) GetCurrentProposer() (common.Address, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentValidators gets the current validators
|
// GetCurrentValidators gets the current validators
|
||||||
func (api *API) GetCurrentValidators() ([]*Validator, error) {
|
func (api *API) GetCurrentValidators() ([]*valset.Validator, error) {
|
||||||
snap, err := api.GetSnapshot(nil)
|
snap, err := api.GetSnapshot(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return make([]*Validator, 0), err
|
return make([]*valset.Validator, 0), err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.ValidatorSet.Validators, nil
|
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()
|
currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
|
||||||
|
|
||||||
if start > end || end > currentHeaderNumber {
|
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)
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
||||||
ethereum "github.com/ethereum/go-ethereum"
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"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"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"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/consensus/misc"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"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.
|
uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
|
||||||
|
|
||||||
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
|
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
|
||||||
systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Various error messages to mark blocks invalid. These should be private to
|
// 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
|
// errOutOfRangeChain is returned if an authorization list is attempted to
|
||||||
// be modified via out-of-range or non-contiguous headers.
|
// be modified via out-of-range or non-contiguous headers.
|
||||||
errOutOfRangeChain = errors.New("out of range or non-contiguous chain")
|
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
|
// 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
|
signFn SignerFn // Signer function to authorize hashes with
|
||||||
lock sync.RWMutex // Protects the signer fields
|
lock sync.RWMutex // Protects the signer fields
|
||||||
|
|
||||||
ethAPI *ethapi.PublicBlockChainAPI
|
ethAPI api.Caller
|
||||||
GenesisContractsClient *GenesisContractsClient
|
spanner Spanner
|
||||||
validatorSetABI abi.ABI
|
GenesisContractsClient GenesisContract
|
||||||
stateReceiverABI abi.ABI
|
|
||||||
HeimdallClient IHeimdallClient
|
HeimdallClient IHeimdallClient
|
||||||
WithoutHeimdall bool
|
|
||||||
|
|
||||||
// The fields below are for testing only
|
// The fields below are for testing only
|
||||||
fakeDiff bool // Skip difficulty verifications
|
fakeDiff bool // Skip difficulty verifications
|
||||||
|
|
||||||
|
closeOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a Matic Bor consensus engine.
|
// New creates a Matic Bor consensus engine.
|
||||||
func New(
|
func New(
|
||||||
chainConfig *params.ChainConfig,
|
chainConfig *params.ChainConfig,
|
||||||
db ethdb.Database,
|
db ethdb.Database,
|
||||||
ethAPI *ethapi.PublicBlockChainAPI,
|
ethAPI api.Caller,
|
||||||
heimdallURL string,
|
spanner Spanner,
|
||||||
withoutHeimdall bool,
|
heimdallClient IHeimdallClient,
|
||||||
|
genesisContracts GenesisContract,
|
||||||
) *Bor {
|
) *Bor {
|
||||||
// get bor config
|
// get bor config
|
||||||
borConfig := chainConfig.Bor
|
borConfig := chainConfig.Bor
|
||||||
|
|
@ -246,14 +240,10 @@ func New(
|
||||||
if borConfig != nil && borConfig.Sprint == 0 {
|
if borConfig != nil && borConfig.Sprint == 0 {
|
||||||
borConfig.Sprint = defaultSprintLength
|
borConfig.Sprint = defaultSprintLength
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the snapshot caches and create the engine
|
// Allocate the snapshot caches and create the engine
|
||||||
recents, _ := lru.NewARC(inmemorySnapshots)
|
recents, _ := lru.NewARC(inmemorySnapshots)
|
||||||
signatures, _ := lru.NewARC(inmemorySignatures)
|
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{
|
c := &Bor{
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
config: borConfig,
|
config: borConfig,
|
||||||
|
|
@ -261,11 +251,9 @@ func New(
|
||||||
ethAPI: ethAPI,
|
ethAPI: ethAPI,
|
||||||
recents: recents,
|
recents: recents,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
validatorSetABI: vABI,
|
spanner: spanner,
|
||||||
stateReceiverABI: sABI,
|
GenesisContractsClient: genesisContracts,
|
||||||
GenesisContractsClient: genesisContractsClient,
|
|
||||||
HeimdallClient: heimdallClient,
|
HeimdallClient: heimdallClient,
|
||||||
WithoutHeimdall: withoutHeimdall,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure we can decode all the GenesisAlloc in the BorConfig.
|
// 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
|
// 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
|
// Ensure that the extra-data contains a signer list on checkpoint, but none otherwise
|
||||||
signersBytes := len(header.Extra) - extraVanity - extraSeal
|
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
|
// Retrieve the snapshot needed to verify this header and cache it
|
||||||
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
|
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify the validator list in the last sprint block
|
// 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]
|
parentValidatorBytes := parent.Extra[extraVanity : len(parent.Extra)-extraSeal]
|
||||||
validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength)
|
validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength)
|
||||||
|
|
||||||
currentValidators := snap.ValidatorSet.Copy().Validators
|
currentValidators := snap.ValidatorSet.Copy().Validators
|
||||||
// sort validator by address
|
// sort validator by address
|
||||||
sort.Sort(ValidatorsByAddress(currentValidators))
|
sort.Sort(valset.ValidatorsByAddress(currentValidators))
|
||||||
|
|
||||||
for i, validator := range currentValidators {
|
for i, validator := range currentValidators {
|
||||||
copy(validatorsBytes[i*validatorHeaderBytesLength:], validator.HeaderBytes())
|
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 an on-disk checkpoint snapshot can be found, use that
|
||||||
if number%checkpointInterval == 0 {
|
if number%checkpointInterval == 0 {
|
||||||
if s, err := loadSnapshot(c.config, c.signatures, c.db, hash, c.ethAPI); err == nil {
|
if s, err := loadSnapshot(c.config, c.signatures, c.db, hash); err == nil {
|
||||||
log.Trace("Loaded snapshot from disk", "number", number, "hash", hash)
|
log.Trace("Loaded snapshot from disk", "number", number, "hash", hash)
|
||||||
|
|
||||||
snap = s
|
snap = s
|
||||||
|
|
@ -509,13 +496,13 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
||||||
hash := checkpoint.Hash()
|
hash := checkpoint.Hash()
|
||||||
|
|
||||||
// get validators and current span
|
// get validators and current span
|
||||||
validators, err := c.GetCurrentValidators(hash, number+1)
|
validators, err := c.spanner.GetCurrentValidators(hash, number+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// new snap shot
|
// 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 {
|
if err := snap.store(c.db); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -674,14 +661,14 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
|
||||||
header.Extra = header.Extra[:extraVanity]
|
header.Extra = header.Extra[:extraVanity]
|
||||||
|
|
||||||
// get validator set if number
|
// get validator set if number
|
||||||
if (number+1)%c.config.Sprint == 0 {
|
if IsSprintStart(number+1, c.config.Sprint) {
|
||||||
newValidators, err := c.GetCurrentValidators(header.ParentHash, number+1)
|
newValidators, err := c.spanner.GetCurrentValidators(header.ParentHash, number+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("unknown validators")
|
return errors.New("unknown validators")
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort validator by address
|
// sort validator by address
|
||||||
sort.Sort(ValidatorsByAddress(newValidators))
|
sort.Sort(valset.ValidatorsByAddress(newValidators))
|
||||||
|
|
||||||
for _, validator := range newValidators {
|
for _, validator := range newValidators {
|
||||||
header.Extra = append(header.Extra, validator.HeaderBytes()...)
|
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()
|
headerNumber := header.Number.Uint64()
|
||||||
|
|
||||||
if headerNumber%c.config.Sprint == 0 {
|
if headerNumber%c.config.Sprint == 0 {
|
||||||
cx := chainContext{Chain: chain, Bor: c}
|
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
||||||
// check and commit span
|
// check and commit span
|
||||||
if err := c.checkAndCommitSpan(state, header, cx); err != nil {
|
if err := c.checkAndCommitSpan(state, header, cx); err != nil {
|
||||||
log.Error("Error while committing span", "error", err)
|
log.Error("Error while committing span", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.WithoutHeimdall {
|
if c.HeimdallClient != nil {
|
||||||
// commit statees
|
// commit statees
|
||||||
stateSyncData, err = c.CommitStates(state, header, cx)
|
stateSyncData, err = c.CommitStates(state, header, cx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -762,7 +749,6 @@ func decodeGenesisAlloc(i interface{}) (core.GenesisAlloc, error) {
|
||||||
var alloc core.GenesisAlloc
|
var alloc core.GenesisAlloc
|
||||||
|
|
||||||
b, err := json.Marshal(i)
|
b, err := json.Marshal(i)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -800,7 +786,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
|
||||||
headerNumber := header.Number.Uint64()
|
headerNumber := header.Number.Uint64()
|
||||||
|
|
||||||
if headerNumber%c.config.Sprint == 0 {
|
if headerNumber%c.config.Sprint == 0 {
|
||||||
cx := chainContext{Chain: chain, Bor: c}
|
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
||||||
|
|
||||||
// check and commit span
|
// check and commit span
|
||||||
err := c.checkAndCommitSpan(state, header, cx)
|
err := c.checkAndCommitSpan(state, header, cx)
|
||||||
|
|
@ -809,7 +795,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.WithoutHeimdall {
|
if c.HeimdallClient != nil {
|
||||||
// commit states
|
// commit states
|
||||||
stateSyncData, err = c.CommitStates(state, header, cx)
|
stateSyncData, err = c.CommitStates(state, header, cx)
|
||||||
if err != nil {
|
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))
|
block := types.NewBlock(header, txs, nil, receipts, new(trie.Trie))
|
||||||
|
|
||||||
// set state sync
|
// set state sync
|
||||||
bc := chain.(*core.BlockChain)
|
bc := chain.(core.BorStateSyncer)
|
||||||
bc.SetStateSync(stateSyncData)
|
bc.SetStateSync(stateSyncData)
|
||||||
|
|
||||||
// return the final block for sealing
|
// 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
|
wiggle := time.Duration(successionNumber) * time.Duration(c.config.CalculateBackupMultiplier(number)) * time.Second
|
||||||
|
|
||||||
// Sign all the things!
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
|
|
||||||
|
|
||||||
// Wait until sealing is terminated or delay timeout.
|
// Wait until sealing is terminated or delay timeout.
|
||||||
log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay))
|
log.Info("Waiting for slot to sign and propagate", "number", number, "hash", header.Hash, "delay-in-sec", uint(delay), "delay", common.PrettyDuration(delay))
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
|
|
@ -910,6 +894,8 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
||||||
log.Info(
|
log.Info(
|
||||||
"Sealing out-of-turn",
|
"Sealing out-of-turn",
|
||||||
"number", number,
|
"number", number,
|
||||||
|
"hash", header.Hash,
|
||||||
|
"wiggle-in-sec", uint(wiggle),
|
||||||
"wiggle", common.PrettyDuration(wiggle),
|
"wiggle", common.PrettyDuration(wiggle),
|
||||||
"in-turn-signer", snap.ValidatorSet.GetProposer().Address.Hex(),
|
"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
|
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
|
// 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
|
// that a new block should have based on the previous blocks in the chain and the
|
||||||
// current signer.
|
// 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.
|
// Close implements consensus.Engine. It's a noop for bor as there are no background threads.
|
||||||
func (c *Bor) Close() error {
|
func (c *Bor) Close() error {
|
||||||
c.HeimdallClient.Close()
|
c.closeOnce.Do(func() {
|
||||||
return nil
|
c.HeimdallClient.Close()
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
return nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Bor) checkAndCommitSpan(
|
func (c *Bor) checkAndCommitSpan(
|
||||||
|
|
@ -1078,21 +972,20 @@ func (c *Bor) checkAndCommitSpan(
|
||||||
chain core.ChainContext,
|
chain core.ChainContext,
|
||||||
) error {
|
) error {
|
||||||
headerNumber := header.Number.Uint64()
|
headerNumber := header.Number.Uint64()
|
||||||
span, err := c.GetCurrentSpan(header.ParentHash)
|
|
||||||
|
|
||||||
|
span, err := c.spanner.GetCurrentSpan(header.ParentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.needToCommitSpan(span, headerNumber) {
|
if c.needToCommitSpan(span, headerNumber) {
|
||||||
err := c.fetchAndCommitSpan(span.ID+1, state, header, chain)
|
return c.FetchAndCommitSpan(span.ID+1, state, header, chain)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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 is nil
|
||||||
if span == nil {
|
if span == nil {
|
||||||
return false
|
return false
|
||||||
|
|
@ -1111,15 +1004,16 @@ func (c *Bor) needToCommitSpan(span *Span, headerNumber uint64) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Bor) fetchAndCommitSpan(
|
func (c *Bor) FetchAndCommitSpan(
|
||||||
newSpanID uint64,
|
newSpanID uint64,
|
||||||
state *state.StateDB,
|
state *state.StateDB,
|
||||||
header *types.Header,
|
header *types.Header,
|
||||||
chain core.ChainContext,
|
chain core.ChainContext,
|
||||||
) error {
|
) 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)
|
s, err := c.getNextHeimdallSpanForTest(newSpanID, header, chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -1127,105 +1021,51 @@ func (c *Bor) fetchAndCommitSpan(
|
||||||
|
|
||||||
heimdallSpan = *s
|
heimdallSpan = *s
|
||||||
} else {
|
} else {
|
||||||
response, err := c.HeimdallClient.FetchWithRetry(fmt.Sprintf("bor/span/%d", newSpanID), "")
|
response, err := c.HeimdallClient.Span(newSpanID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(response.Result, &heimdallSpan); err != nil {
|
heimdallSpan = *response
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if chain id matches with heimdall span
|
// check if chain id matches with Heimdall span
|
||||||
if heimdallSpan.ChainID != c.chainConfig.ChainID.String() {
|
if heimdallSpan.ChainID != c.chainConfig.ChainID.String() {
|
||||||
return fmt.Errorf(
|
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,
|
heimdallSpan.ChainID,
|
||||||
c.chainConfig.ChainID,
|
c.chainConfig.ChainID,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get validators bytes
|
return c.spanner.CommitSpan(heimdallSpan, state, header, chain)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitStates commit states
|
// CommitStates commit states
|
||||||
func (c *Bor) CommitStates(
|
func (c *Bor) CommitStates(
|
||||||
state *state.StateDB,
|
state *state.StateDB,
|
||||||
header *types.Header,
|
header *types.Header,
|
||||||
chain chainContext,
|
chain statefull.ChainContext,
|
||||||
) ([]*types.StateSyncData, error) {
|
) ([]*types.StateSyncData, error) {
|
||||||
stateSyncs := make([]*types.StateSyncData, 0)
|
stateSyncs := make([]*types.StateSyncData, 0)
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
|
|
||||||
|
|
||||||
|
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.Sprint).Time), 0)
|
to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.Sprint).Time), 0)
|
||||||
lastStateID := _lastStateID.Uint64()
|
lastStateID := _lastStateID.Uint64()
|
||||||
|
|
||||||
log.Info(
|
log.Info(
|
||||||
"Fetching state updates from Heimdall",
|
"Fetching state updates from Heimdall",
|
||||||
"fromID", lastStateID+1,
|
"fromID", lastStateID+1,
|
||||||
"to", to.Format(time.RFC3339))
|
"to", to.Format(time.RFC3339))
|
||||||
|
|
||||||
eventRecords, err := c.HeimdallClient.FetchStateSyncEvents(lastStateID+1, to.Unix())
|
eventRecords, err := c.HeimdallClient.StateSyncEvents(lastStateID+1, to.Unix())
|
||||||
|
|
||||||
if err != nil {
|
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 {
|
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()
|
chainID := c.chainConfig.ChainID.String()
|
||||||
|
|
||||||
for _, eventRecord := range eventRecords {
|
for _, eventRecord := range eventRecords {
|
||||||
|
|
@ -1242,7 +1084,7 @@ func (c *Bor) CommitStates(
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
|
if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
|
||||||
log.Error(err.Error())
|
log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1252,18 +1094,23 @@ func (c *Bor) CommitStates(
|
||||||
Data: hex.EncodeToString(eventRecord.Data),
|
Data: hex.EncodeToString(eventRecord.Data),
|
||||||
TxHash: eventRecord.TxHash,
|
TxHash: eventRecord.TxHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
stateSyncs = append(stateSyncs, &stateData)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalGas += int(gasUsed)
|
||||||
|
|
||||||
lastStateID++
|
lastStateID++
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateSyncs, nil
|
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)
|
// 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) {
|
if lastStateID+1 != eventRecord.ID || eventRecord.ChainID != chainID || !eventRecord.Time.Before(to) {
|
||||||
return &InvalidStateReceivedError{number, lastStateID, &to, eventRecord}
|
return &InvalidStateReceivedError{number, lastStateID, &to, eventRecord}
|
||||||
|
|
@ -1276,6 +1123,10 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) {
|
||||||
c.HeimdallClient = h
|
c.HeimdallClient = h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Bor) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||||
|
return c.spanner.GetCurrentValidators(headerHash, blockNumber)
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Private methods
|
// Private methods
|
||||||
//
|
//
|
||||||
|
|
@ -1284,16 +1135,16 @@ func (c *Bor) getNextHeimdallSpanForTest(
|
||||||
newSpanID uint64,
|
newSpanID uint64,
|
||||||
header *types.Header,
|
header *types.Header,
|
||||||
chain core.ChainContext,
|
chain core.ChainContext,
|
||||||
) (*HeimdallSpan, error) {
|
) (*span.HeimdallSpan, error) {
|
||||||
headerNumber := header.Number.Uint64()
|
headerNumber := header.Number.Uint64()
|
||||||
span, err := c.GetCurrentSpan(header.ParentHash)
|
|
||||||
|
|
||||||
|
spanBor, err := c.spanner.GetCurrentSpan(header.ParentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// get local chain context object
|
// get local chain context object
|
||||||
localContext := chain.(chainContext)
|
localContext := chain.(statefull.ChainContext)
|
||||||
// Retrieve the snapshot needed to verify this header and cache it
|
// Retrieve the snapshot needed to verify this header and cache it
|
||||||
snap, err := c.snapshot(localContext.Chain, headerNumber-1, header.ParentHash, nil)
|
snap, err := c.snapshot(localContext.Chain, headerNumber-1, header.ParentHash, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1301,22 +1152,22 @@ func (c *Bor) getNextHeimdallSpanForTest(
|
||||||
}
|
}
|
||||||
|
|
||||||
// new span
|
// new span
|
||||||
span.ID = newSpanID
|
spanBor.ID = newSpanID
|
||||||
if span.EndBlock == 0 {
|
if spanBor.EndBlock == 0 {
|
||||||
span.StartBlock = 256
|
spanBor.StartBlock = 256
|
||||||
} else {
|
} 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 {
|
for i, v := range snap.ValidatorSet.Validators {
|
||||||
selectedProducers[i] = *v
|
selectedProducers[i] = *v
|
||||||
}
|
}
|
||||||
|
|
||||||
heimdallSpan := &HeimdallSpan{
|
heimdallSpan := &span.HeimdallSpan{
|
||||||
Span: *span,
|
Span: *spanBor,
|
||||||
ValidatorSet: *snap.ValidatorSet,
|
ValidatorSet: *snap.ValidatorSet,
|
||||||
SelectedProducers: selectedProducers,
|
SelectedProducers: selectedProducers,
|
||||||
ChainID: c.chainConfig.ChainID.String(),
|
ChainID: c.chainConfig.ChainID.String(),
|
||||||
|
|
@ -1325,82 +1176,7 @@ func (c *Bor) getNextHeimdallSpanForTest(
|
||||||
return heimdallSpan, nil
|
return heimdallSpan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
func validatorContains(a []*valset.Validator, x *valset.Validator) (*valset.Validator, bool) {
|
||||||
// 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) {
|
|
||||||
for _, n := range a {
|
for _, n := range a {
|
||||||
if n.Address == x.Address {
|
if n.Address == x.Address {
|
||||||
return n, true
|
return n, true
|
||||||
|
|
@ -1410,11 +1186,11 @@ func validatorContains(a []*Validator, x *Validator) (*Validator, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator) *ValidatorSet {
|
func getUpdatedValidatorSet(oldValidatorSet *valset.ValidatorSet, newVals []*valset.Validator) *valset.ValidatorSet {
|
||||||
v := oldValidatorSet
|
v := oldValidatorSet
|
||||||
oldVals := v.Validators
|
oldVals := v.Validators
|
||||||
|
|
||||||
changes := make([]*Validator, 0, len(oldVals))
|
changes := make([]*valset.Validator, 0, len(oldVals))
|
||||||
|
|
||||||
for _, ov := range oldVals {
|
for _, ov := range oldVals {
|
||||||
if f, ok := validatorContains(newVals, ov); ok {
|
if f, ok := validatorContains(newVals, ov); ok {
|
||||||
|
|
@ -1433,12 +1209,12 @@ func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := v.UpdateWithChangeSet(changes); err != nil {
|
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
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSprintStart(number, sprint uint64) bool {
|
func IsSprintStart(number, sprint uint64) bool {
|
||||||
return number%sprint == 0
|
return number%sprint == 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package bor
|
package clerk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -23,10 +23,10 @@ type EventRecordWithTime struct {
|
||||||
Time time.Time `json:"record_time" yaml:"record_time"`
|
Time time.Time `json:"record_time" yaml:"record_time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representations of span
|
// String returns the string representation of EventRecord
|
||||||
func (e *EventRecordWithTime) String() string {
|
func (e *EventRecordWithTime) String(gasUsed uint64) string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"id %v, contract %v, data: %v, txHash: %v, logIndex: %v, chainId: %v, time %s",
|
"id %v, contract %v, data: %v, txHash: %v, logIndex: %v, chainId: %v, time %s, gasUsed %d",
|
||||||
e.ID,
|
e.ID,
|
||||||
e.Contract.String(),
|
e.Contract.String(),
|
||||||
e.Data.String(),
|
e.Data.String(),
|
||||||
|
|
@ -34,6 +34,7 @@ func (e *EventRecordWithTime) String() string {
|
||||||
e.LogIndex,
|
e.LogIndex,
|
||||||
e.ChainID,
|
e.ChainID,
|
||||||
e.Time.Format(time.RFC3339),
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"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 {
|
type MaxCheckpointLengthExceededError struct {
|
||||||
Start uint64
|
Start uint64
|
||||||
End uint64
|
End uint64
|
||||||
|
|
@ -129,12 +102,12 @@ type InvalidStateReceivedError struct {
|
||||||
Number uint64
|
Number uint64
|
||||||
LastStateID uint64
|
LastStateID uint64
|
||||||
To *time.Time
|
To *time.Time
|
||||||
Event *EventRecordWithTime
|
Event *clerk.EventRecordWithTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *InvalidStateReceivedError) Error() string {
|
func (e *InvalidStateReceivedError) Error() string {
|
||||||
return fmt.Sprintf(
|
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.Event,
|
||||||
e.Number,
|
e.Number,
|
||||||
e.To.Format(time.RFC3339),
|
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 (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Snapshot is the state of the authorization voting at a given point in time.
|
// Snapshot is the state of the authorization voting at a given point in time.
|
||||||
type Snapshot struct {
|
type Snapshot struct {
|
||||||
config *params.BorConfig // Consensus engine parameters to fine tune behavior
|
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
|
||||||
sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
|
|
||||||
|
|
||||||
Number uint64 `json:"number"` // Block number where the snapshot was created
|
Number uint64 `json:"number"` // Block number where the snapshot was created
|
||||||
Hash common.Hash `json:"hash"` // Block hash 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
|
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,16 +32,14 @@ func newSnapshot(
|
||||||
sigcache *lru.ARCCache,
|
sigcache *lru.ARCCache,
|
||||||
number uint64,
|
number uint64,
|
||||||
hash common.Hash,
|
hash common.Hash,
|
||||||
validators []*Validator,
|
validators []*valset.Validator,
|
||||||
ethAPI *ethapi.PublicBlockChainAPI,
|
|
||||||
) *Snapshot {
|
) *Snapshot {
|
||||||
snap := &Snapshot{
|
snap := &Snapshot{
|
||||||
config: config,
|
config: config,
|
||||||
ethAPI: ethAPI,
|
|
||||||
sigcache: sigcache,
|
sigcache: sigcache,
|
||||||
Number: number,
|
Number: number,
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
Recents: make(map[uint64]common.Address),
|
Recents: make(map[uint64]common.Address),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,7 +47,7 @@ func newSnapshot(
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadSnapshot loads an existing snapshot from the database.
|
// 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[:]...))
|
blob, err := db.Get(append([]byte("bor-"), hash[:]...))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -63,10 +61,9 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat
|
||||||
|
|
||||||
snap.config = config
|
snap.config = config
|
||||||
snap.sigcache = sigcache
|
snap.sigcache = sigcache
|
||||||
snap.ethAPI = ethAPI
|
|
||||||
|
|
||||||
// update total voting power
|
// update total voting power
|
||||||
if err := snap.ValidatorSet.updateTotalVotingPower(); err != nil {
|
if err := snap.ValidatorSet.UpdateTotalVotingPower(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,7 +84,6 @@ func (s *Snapshot) store(db ethdb.Database) error {
|
||||||
func (s *Snapshot) copy() *Snapshot {
|
func (s *Snapshot) copy() *Snapshot {
|
||||||
cpy := &Snapshot{
|
cpy := &Snapshot{
|
||||||
config: s.config,
|
config: s.config,
|
||||||
ethAPI: s.ethAPI,
|
|
||||||
sigcache: s.sigcache,
|
sigcache: s.sigcache,
|
||||||
Number: s.Number,
|
Number: s.Number,
|
||||||
Hash: s.Hash,
|
Hash: s.Hash,
|
||||||
|
|
@ -155,7 +151,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
|
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
|
||||||
|
|
||||||
// get validators from headers and use that for new validator set
|
// get validators from headers and use that for new validator set
|
||||||
newVals, _ := ParseValidators(validatorBytes)
|
newVals, _ := valset.ParseValidators(validatorBytes)
|
||||||
v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals)
|
v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals)
|
||||||
v.IncrementProposerPriority(1)
|
v.IncrementProposerPriority(1)
|
||||||
snap.ValidatorSet = v
|
snap.ValidatorSet = v
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"pgregory.net/rapid"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
unique "github.com/ethereum/go-ethereum/common/set"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -19,7 +22,7 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
validatorSet := NewValidatorSet(validators)
|
validatorSet := valset.NewValidatorSet(validators)
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: validatorSet,
|
ValidatorSet: validatorSet,
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +30,6 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
||||||
// proposer is signer
|
// proposer is signer
|
||||||
signer := validatorSet.Proposer.Address
|
signer := validatorSet.Proposer.Address
|
||||||
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -41,20 +43,19 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
|
|
||||||
// sort validators by address, which is what NewValidatorSet also does
|
// sort validators by address, which is what NewValidatorSet also does
|
||||||
sort.Sort(ValidatorsByAddress(validators))
|
sort.Sort(valset.ValidatorsByAddress(validators))
|
||||||
|
|
||||||
proposerIndex := 32
|
proposerIndex := 32
|
||||||
signerIndex := 56
|
signerIndex := 56
|
||||||
// give highest ProposerPriority to a particular val, so that they become the proposer
|
// give highest ProposerPriority to a particular val, so that they become the proposer
|
||||||
validators[proposerIndex].VotingPower = 200
|
validators[proposerIndex].VotingPower = 200
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
}
|
}
|
||||||
|
|
||||||
// choose a signer at an index greater than proposer index
|
// choose a signer at an index greater than proposer index
|
||||||
signer := snap.ValidatorSet.Validators[signerIndex].Address
|
signer := snap.ValidatorSet.Validators[signerIndex].Address
|
||||||
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -71,13 +72,12 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
||||||
// give highest ProposerPriority to a particular val, so that they become the proposer
|
// give highest ProposerPriority to a particular val, so that they become the proposer
|
||||||
validators[proposerIndex].VotingPower = 200
|
validators[proposerIndex].VotingPower = 200
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
}
|
}
|
||||||
|
|
||||||
// choose a signer at an index greater than proposer index
|
// choose a signer at an index greater than proposer index
|
||||||
signer := snap.ValidatorSet.Validators[signerIndex].Address
|
signer := snap.ValidatorSet.Validators[signerIndex].Address
|
||||||
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
successionNumber, err := snap.GetSignerSuccessionNumber(signer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -90,14 +90,18 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
}
|
}
|
||||||
|
|
||||||
dummyProposerAddress := randomAddress()
|
dummyProposerAddress := randomAddress()
|
||||||
snap.ValidatorSet.Proposer = &Validator{Address: dummyProposerAddress}
|
snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress}
|
||||||
|
|
||||||
// choose any signer
|
// choose any signer
|
||||||
signer := snap.ValidatorSet.Validators[3].Address
|
signer := snap.ValidatorSet.Validators[3].Address
|
||||||
|
|
||||||
_, err := snap.GetSignerSuccessionNumber(signer)
|
_, err := snap.GetSignerSuccessionNumber(signer)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
e, ok := err.(*UnauthorizedProposerError)
|
e, ok := err.(*UnauthorizedProposerError)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
|
assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
|
||||||
|
|
@ -108,7 +112,7 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
}
|
}
|
||||||
dummySignerAddress := randomAddress()
|
dummySignerAddress := randomAddress()
|
||||||
_, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
|
_, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
|
||||||
|
|
@ -119,21 +123,22 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint: unparam
|
// nolint: unparam
|
||||||
func buildRandomValidatorSet(numVals int) []*Validator {
|
func buildRandomValidatorSet(numVals int) []*valset.Validator {
|
||||||
rand.Seed(time.Now().Unix())
|
rand.Seed(time.Now().Unix())
|
||||||
|
|
||||||
validators := make([]*Validator, numVals)
|
validators := make([]*valset.Validator, numVals)
|
||||||
|
valAddrs := randomAddresses(numVals)
|
||||||
|
|
||||||
for i := 0; i < numVals; i++ {
|
for i := 0; i < numVals; i++ {
|
||||||
validators[i] = &Validator{
|
validators[i] = &valset.Validator{
|
||||||
Address: randomAddress(),
|
Address: valAddrs[i],
|
||||||
// cannot process validators with voting power 0, hence +1
|
// cannot process validators with voting power 0, hence +1
|
||||||
VotingPower: int64(rand.Intn(99) + 1),
|
VotingPower: int64(rand.Intn(99) + 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort validators by address, which is what NewValidatorSet also does
|
// sort validators by address, which is what NewValidatorSet also does
|
||||||
sort.Sort(ValidatorsByAddress(validators))
|
sort.Sort(valset.ValidatorsByAddress(validators))
|
||||||
|
|
||||||
return validators
|
return validators
|
||||||
}
|
}
|
||||||
|
|
@ -144,3 +149,51 @@ func randomAddress() common.Address {
|
||||||
|
|
||||||
return common.BytesToAddress(bytes)
|
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
|
package bor
|
||||||
|
|
||||||
// Span represents a current bor span
|
import (
|
||||||
type Span struct {
|
"github.com/ethereum/go-ethereum/common"
|
||||||
ID uint64 `json:"span_id" yaml:"span_id"`
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
StartBlock uint64 `json:"start_block" yaml:"start_block"`
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
EndBlock uint64 `json:"end_block" yaml:"end_block"`
|
"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
|
//go:generate mockgen -destination=./span_mock.go -package=bor . Spanner
|
||||||
type HeimdallSpan struct {
|
type Spanner interface {
|
||||||
Span
|
GetCurrentSpan(headerHash common.Hash) (*span.Span, error)
|
||||||
ValidatorSet ValidatorSet `json:"validator_set" yaml:"validator_set"`
|
GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error)
|
||||||
SelectedProducers []Validator `json:"selected_producers" yaml:"selected_producers"`
|
CommitSpan(heimdallSpan span.HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error
|
||||||
ChainID string `json:"bor_chain_id" yaml:"bor_chain_id"`
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
// "encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package bor
|
package valset
|
||||||
|
|
||||||
// Tendermint leader selection algorithm
|
// Tendermint leader selection algorithm
|
||||||
|
|
||||||
|
|
@ -55,8 +55,8 @@ type ValidatorSet struct {
|
||||||
// function panics.
|
// function panics.
|
||||||
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
||||||
vals := &ValidatorSet{}
|
vals := &ValidatorSet{}
|
||||||
err := vals.updateWithChangeSet(valz, false)
|
|
||||||
|
|
||||||
|
err := vals.updateWithChangeSet(valz, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("cannot create validator set: %s", err))
|
panic(fmt.Sprintf("cannot create validator set: %s", err))
|
||||||
}
|
}
|
||||||
|
|
@ -281,7 +281,7 @@ func (vals *ValidatorSet) Size() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force recalculation of the set's total voting power.
|
// Force recalculation of the set's total voting power.
|
||||||
func (vals *ValidatorSet) updateTotalVotingPower() error {
|
func (vals *ValidatorSet) UpdateTotalVotingPower() error {
|
||||||
sum := int64(0)
|
sum := int64(0)
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
// mind overflow
|
// mind overflow
|
||||||
|
|
@ -302,7 +302,7 @@ func (vals *ValidatorSet) TotalVotingPower() int64 {
|
||||||
if vals.totalVotingPower == 0 {
|
if vals.totalVotingPower == 0 {
|
||||||
log.Info("invoking updateTotalVotingPower before returning it")
|
log.Info("invoking updateTotalVotingPower before returning it")
|
||||||
|
|
||||||
if err := vals.updateTotalVotingPower(); err != nil {
|
if err := vals.UpdateTotalVotingPower(); err != nil {
|
||||||
// Can/should we do better?
|
// Can/should we do better?
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -602,7 +602,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
|
||||||
vals.applyUpdates(updates)
|
vals.applyUpdates(updates)
|
||||||
vals.applyRemovals(deletes)
|
vals.applyRemovals(deletes)
|
||||||
|
|
||||||
if err := vals.updateTotalVotingPower(); err != nil {
|
if err := vals.UpdateTotalVotingPower(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,12 +45,14 @@ type Merger struct {
|
||||||
// NewMerger creates a new Merger which stores its transition status in the provided db.
|
// NewMerger creates a new Merger which stores its transition status in the provided db.
|
||||||
func NewMerger(db ethdb.KeyValueStore) *Merger {
|
func NewMerger(db ethdb.KeyValueStore) *Merger {
|
||||||
var status transitionStatus
|
var status transitionStatus
|
||||||
|
|
||||||
blob := rawdb.ReadTransitionStatus(db)
|
blob := rawdb.ReadTransitionStatus(db)
|
||||||
if len(blob) != 0 {
|
if len(blob) != 0 {
|
||||||
if err := rlp.DecodeBytes(blob, &status); err != nil {
|
if err := rlp.DecodeBytes(blob, &status); err != nil {
|
||||||
log.Crit("Failed to decode the transition status", "err", err)
|
log.Crit("Failed to decode the transition status", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Merger{
|
return &Merger{
|
||||||
db: db,
|
db: db,
|
||||||
status: status,
|
status: status,
|
||||||
|
|
|
||||||
|
|
@ -305,7 +305,8 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
}
|
}
|
||||||
makeChainForBench(db, full, count)
|
makeChainForBench(db, full, count)
|
||||||
db.Close()
|
db.Close()
|
||||||
cacheConfig := *defaultCacheConfig
|
|
||||||
|
cacheConfig := *DefaultCacheConfig
|
||||||
cacheConfig.TrieDirtyDisabled = true
|
cacheConfig.TrieDirtyDisabled = true
|
||||||
|
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
"github.com/ethereum/go-ethereum/common/prque"
|
||||||
|
|
@ -43,7 +45,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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
|
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).
|
// user (also used during testing).
|
||||||
var defaultCacheConfig = &CacheConfig{
|
var DefaultCacheConfig = &CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
|
|
@ -222,7 +223,7 @@ type BlockChain struct {
|
||||||
// and Processor.
|
// 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) {
|
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 {
|
if cacheConfig == nil {
|
||||||
cacheConfig = defaultCacheConfig
|
cacheConfig = DefaultCacheConfig
|
||||||
}
|
}
|
||||||
bodyCache, _ := lru.New(bodyCacheLimit)
|
bodyCache, _ := lru.New(bodyCacheLimit)
|
||||||
bodyRLPCache, _ := 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/state/snapshot"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"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))
|
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
|
// Bor related changes
|
||||||
//
|
//
|
||||||
|
|
||||||
|
type BorStateSyncer interface {
|
||||||
|
SetStateSync(stateData []*types.StateSyncData)
|
||||||
|
SubscribeStateSyncEvent(ch chan<- StateSyncEvent) event.Subscription
|
||||||
|
}
|
||||||
|
|
||||||
// SetStateSync set sync data in state_data
|
// SetStateSync set sync data in state_data
|
||||||
func (bc *BlockChain) SetStateSync(stateData []*types.StateSyncData) {
|
func (bc *BlockChain) SetStateSync(stateData []*types.StateSyncData) {
|
||||||
bc.stateSyncData = stateData
|
bc.stateSyncData = stateData
|
||||||
|
|
|
||||||
|
|
@ -920,7 +920,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
archiveDb, delfn := makeDb()
|
archiveDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
|
|
||||||
archiveCaching := *defaultCacheConfig
|
archiveCaching := *DefaultCacheConfig
|
||||||
archiveCaching.TrieDirtyDisabled = true
|
archiveCaching.TrieDirtyDisabled = true
|
||||||
|
|
||||||
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -334,7 +335,10 @@ func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethd
|
||||||
}
|
}
|
||||||
|
|
||||||
type fakeChainReader struct {
|
type fakeChainReader struct {
|
||||||
config *params.ChainConfig
|
config *params.ChainConfig
|
||||||
|
stateSyncData []*types.StateSyncData
|
||||||
|
stateSyncFeed event.Feed
|
||||||
|
scope event.SubscriptionScope
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config returns the chain configuration.
|
// 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) 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) GetBlock(hash common.Hash, number uint64) *types.Block { return nil }
|
||||||
func (cr *fakeChainReader) GetTd(hash common.Hash, number uint64) *big.Int { 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"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
|
@ -32,7 +34,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestStateProcessorErrors tests the output from the 'core' errors
|
// 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{
|
header := &types.Header{
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
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(),
|
Number: parent.Number(),
|
||||||
Time: parent.Time(),
|
Time: parent.Time(),
|
||||||
Difficulty: parent.Difficulty(),
|
Difficulty: parent.Difficulty(),
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
// the database in some strange state with gaps in the chain, nor with block data
|
// the database in some strange state with gaps in the chain, nor with block data
|
||||||
// dangling in the future.
|
// dangling in the future.
|
||||||
|
|
||||||
package core
|
package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
@ -27,12 +27,22 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/consensus/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"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
|
// 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)
|
}, 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) {
|
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
|
// 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))))
|
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||||
// fmt.Println(tt.dump(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
|
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
|
// Initialize a fresh chain
|
||||||
var (
|
var (
|
||||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
gspec = &core.Genesis{
|
||||||
engine = ethash.NewFullFaker()
|
Config: params.BorUnittestChainConfig,
|
||||||
config = &CacheConfig{
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
|
}
|
||||||
|
config = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0, // Disable snapshot by default
|
SnapshotLimit: 0, // Disable snapshot by default
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
engine := miner.NewFakeBor(t, db, params.BorUnittestChainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock)
|
||||||
defer engine.Close()
|
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 {
|
if snapshots {
|
||||||
config.SnapshotLimit = 256
|
config.SnapshotLimit = 256
|
||||||
config.SnapshotWait = true
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If sidechain blocks are needed, make a light chain and import it
|
// If sidechain blocks are needed, make a light chain and import it
|
||||||
var sideblocks types.Blocks
|
var sideblocks types.Blocks
|
||||||
if tt.sidechainBlocks > 0 {
|
if tt.sidechainBlocks > 0 {
|
||||||
sideblocks, _ = GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) {
|
sideblocks, _ = core.GenerateChain(params.BorUnittestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *core.BlockGen) {
|
||||||
b.SetCoinbase(common.Address{0x01})
|
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 {
|
if _, err := chain.InsertChain(sideblocks); err != nil {
|
||||||
t.Fatalf("Failed to import side chain: %v", err)
|
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.SetCoinbase(common.Address{0x02})
|
||||||
b.SetDifficulty(big.NewInt(1000000))
|
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 {
|
if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||||
}
|
}
|
||||||
if tt.commitBlock > 0 {
|
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 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)
|
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1837,7 +1914,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
}
|
}
|
||||||
defer db.Close()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1888,19 +1965,21 @@ func TestIssue23496(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create temporary datadir: %v", err)
|
t.Fatalf("Failed to create temporary datadir: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
os.RemoveAll(datadir)
|
os.RemoveAll(datadir)
|
||||||
|
|
||||||
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create persistent database: %v", err)
|
t.Fatalf("Failed to create persistent database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer db.Close() // Might double close, should be fine
|
defer db.Close() // Might double close, should be fine
|
||||||
|
|
||||||
// Initialize a fresh chain
|
// Initialize a fresh chain
|
||||||
var (
|
var (
|
||||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||||
engine = ethash.NewFullFaker()
|
engine = ethash.NewFullFaker()
|
||||||
config = &CacheConfig{
|
config = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
|
|
@ -1908,11 +1987,13 @@ func TestIssue23496(t *testing.T) {
|
||||||
SnapshotWait: true,
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
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.SetCoinbase(common.Address{0x02})
|
||||||
b.SetDifficulty(big.NewInt(1000000))
|
b.SetDifficulty(big.NewInt(1000000))
|
||||||
})
|
})
|
||||||
|
|
@ -1921,13 +2002,18 @@ func TestIssue23496(t *testing.T) {
|
||||||
if _, err := chain.InsertChain(blocks[:1]); err != nil {
|
if _, err := chain.InsertChain(blocks[:1]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
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
|
// Insert block B2 and commit the snapshot into disk
|
||||||
if _, err := chain.InsertChain(blocks[1:2]); err != nil {
|
if _, err := chain.InsertChain(blocks[1:2]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
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)
|
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 {
|
if _, err := chain.InsertChain(blocks[2:3]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
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
|
// Insert the remaining blocks
|
||||||
if _, err := chain.InsertChain(blocks[3:]); err != nil {
|
if _, err := chain.InsertChain(blocks[3:]); err != nil {
|
||||||
|
|
@ -1950,20 +2040,24 @@ func TestIssue23496(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer db.Close()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
||||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
||||||
t.Errorf("Head fast block mismatch: have %d, want %d", 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) {
|
if head := chain.CurrentBlock(); head.NumberU64() != uint64(1) {
|
||||||
t.Errorf("Head block mismatch: have %d, want %d", 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 {
|
if _, err := chain.InsertChain(blocks[1:]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
||||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
||||||
t.Errorf("Head fast block mismatch: have %d, want %d", 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) {
|
if head := chain.CurrentBlock(); head.NumberU64() != uint64(4) {
|
||||||
t.Errorf("Head block mismatch: have %d, want %d", 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 {
|
if layer := chain.Snapshots().Snapshot(blocks[2].Root()); layer == nil {
|
||||||
t.Error("Failed to regenerate the snapshot of known state")
|
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
|
// 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.
|
// strange state with gaps in the chain, nor with block data dangling in the future.
|
||||||
|
|
||||||
package core
|
package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"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/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
@ -1959,79 +1960,98 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create temporary datadir: %v", err)
|
t.Fatalf("Failed to create temporary datadir: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
os.RemoveAll(datadir)
|
os.RemoveAll(datadir)
|
||||||
|
|
||||||
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create persistent database: %v", err)
|
t.Fatalf("Failed to create persistent database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// Initialize a fresh chain
|
// Initialize a fresh chain
|
||||||
var (
|
var (
|
||||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||||
engine = ethash.NewFullFaker()
|
engine = ethash.NewFullFaker()
|
||||||
config = &CacheConfig{
|
config = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0, // Disable snapshot
|
SnapshotLimit: 0, // Disable snapshot
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if snapshots {
|
if snapshots {
|
||||||
config.SnapshotLimit = 256
|
config.SnapshotLimit = 256
|
||||||
config.SnapshotWait = true
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If sidechain blocks are needed, make a light chain and import it
|
// If sidechain blocks are needed, make a light chain and import it
|
||||||
var sideblocks types.Blocks
|
var sideblocks types.Blocks
|
||||||
if tt.sidechainBlocks > 0 {
|
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})
|
b.SetCoinbase(common.Address{0x01})
|
||||||
})
|
})
|
||||||
|
|
||||||
if _, err := chain.InsertChain(sideblocks); err != nil {
|
if _, err := chain.InsertChain(sideblocks); err != nil {
|
||||||
t.Fatalf("Failed to import side chain: %v", err)
|
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.SetCoinbase(common.Address{0x02})
|
||||||
b.SetDifficulty(big.NewInt(1000000))
|
b.SetDifficulty(big.NewInt(1000000))
|
||||||
})
|
})
|
||||||
|
|
||||||
if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil {
|
if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.commitBlock > 0 {
|
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 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)
|
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil {
|
if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manually dereference anything not committed to not have to work with 128+ tries
|
// Manually dereference anything not committed to not have to work with 128+ tries
|
||||||
for _, block := range sideblocks {
|
for _, block := range sideblocks {
|
||||||
chain.stateCache.TrieDB().Dereference(block.Root())
|
chain.StateCache().TrieDB().Dereference(block.Root())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, block := range canonblocks {
|
for _, block := range canonblocks {
|
||||||
chain.stateCache.TrieDB().Dereference(block.Root())
|
chain.StateCache().TrieDB().Dereference(block.Root())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force run a freeze cycle
|
// Force run a freeze cycle
|
||||||
type freezer interface {
|
type freezer interface {
|
||||||
Freeze(threshold uint64) error
|
Freeze(threshold uint64) error
|
||||||
Ancients() (uint64, error)
|
Ancients() (uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
db.(freezer).Freeze(tt.freezeThreshold)
|
db.(freezer).Freeze(tt.freezeThreshold)
|
||||||
|
|
||||||
// Set the simulated pivot block
|
// Set the simulated pivot block
|
||||||
if tt.pivotBlock != nil {
|
if tt.pivotBlock != nil {
|
||||||
rawdb.WriteLastPivotNumber(db, *tt.pivotBlock)
|
rawdb.WriteLastPivotNumber(db, *tt.pivotBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the head of the chain back to the requested number
|
// Set the head of the chain back to the requested number
|
||||||
chain.SetHead(tt.setheadBlock)
|
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 {
|
if head := chain.CurrentHeader(); head.Number.Uint64() != tt.expHeadHeader {
|
||||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader)
|
t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock {
|
if head := chain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock {
|
||||||
t.Errorf("Head fast block mismatch: have %d, want %d", 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 {
|
if head := chain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock {
|
||||||
t.Errorf("Head block mismatch: have %d, want %d", 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 {
|
if frozen, err := db.(freezer).Ancients(); err != nil {
|
||||||
t.Errorf("Failed to retrieve ancient count: %v\n", err)
|
t.Errorf("Failed to retrieve ancient count: %v\n", err)
|
||||||
} else if int(frozen) != tt.expFrozen {
|
} 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
|
// verifyNoGaps checks that there are no gaps after the initial set of blocks in
|
||||||
// the database and errors if found.
|
// 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()
|
t.Helper()
|
||||||
|
|
||||||
var end uint64
|
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
|
// verifyCutoff checks that there are no chain data available in the chain after
|
||||||
// the specified limit, but that it is available before.
|
// 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()
|
t.Helper()
|
||||||
|
|
||||||
for i := 1; i <= len(inserted); i++ {
|
for i := 1; i <= len(inserted); i++ {
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// Tests that abnormal program termination (i.e.crash) and restart can recovery
|
// Tests that abnormal program termination (i.e.crash) and restart can recovery
|
||||||
// the snapshot properly if the snapshot is enabled.
|
// the snapshot properly if the snapshot is enabled.
|
||||||
|
|
||||||
package core
|
package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"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/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
@ -57,7 +58,9 @@ type snapshotTestBasic struct {
|
||||||
engine consensus.Engine
|
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
|
// Create a temporary persistent database
|
||||||
datadir, err := ioutil.TempDir("", "")
|
datadir, err := ioutil.TempDir("", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -71,20 +74,22 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||||
}
|
}
|
||||||
// Initialize a fresh chain
|
// Initialize a fresh chain
|
||||||
var (
|
var (
|
||||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||||
engine = ethash.NewFullFaker()
|
engine = ethash.NewFullFaker()
|
||||||
gendb = rawdb.NewMemoryDatabase()
|
gendb = rawdb.NewMemoryDatabase()
|
||||||
|
|
||||||
// Snapshot is enabled, the first snapshot is created from the Genesis.
|
// Snapshot is enabled, the first snapshot is created from the Genesis.
|
||||||
// The snapshot memory allowance is 256MB, it means no snapshot flush
|
// The snapshot memory allowance is 256MB, it means no snapshot flush
|
||||||
// will happen during the block insertion.
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
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.
|
// Insert the blocks with configured settings.
|
||||||
var breakpoints []uint64
|
var breakpoints []uint64
|
||||||
|
|
@ -93,27 +98,39 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||||
} else {
|
} else {
|
||||||
breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock)
|
breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
var startPoint uint64
|
var startPoint uint64
|
||||||
|
|
||||||
for _, point := range breakpoints {
|
for _, point := range breakpoints {
|
||||||
if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil {
|
if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
startPoint = point
|
startPoint = point
|
||||||
|
|
||||||
if basic.commitBlock > 0 && basic.commitBlock == 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 {
|
if basic.snapshotBlock > 0 && basic.snapshotBlock == point {
|
||||||
// Flushing the entire snap tree into the disk, the
|
// Flushing the entire snap tree into the disk, the
|
||||||
// relevant (a) snapshot root and (b) snapshot generator
|
// relevant (a) snapshot root and (b) snapshot generator
|
||||||
// will be persisted atomically.
|
// will be persisted atomically.
|
||||||
chain.snaps.Cap(blocks[point-1].Root(), 0)
|
err = chain.Snaps().Cap(blocks[point-1].Root(), 0)
|
||||||
diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root()
|
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()) {
|
if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) {
|
||||||
t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot)
|
t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[startPoint:]); err != nil {
|
if _, err := chain.InsertChain(blocks[startPoint:]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
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.db = db
|
||||||
basic.gendb = gendb
|
basic.gendb = gendb
|
||||||
basic.engine = engine
|
basic.engine = engine
|
||||||
|
|
||||||
return chain, blocks
|
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
|
// Iterate over all the remaining blocks and ensure there are no gaps
|
||||||
verifyNoGaps(t, chain, true, blocks)
|
verifyNoGaps(t, chain, true, blocks)
|
||||||
verifyCutoff(t, chain, true, blocks, basic.expCanonicalBlocks)
|
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 {
|
if head := chain.CurrentHeader(); head.Number.Uint64() != basic.expHeadHeader {
|
||||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader)
|
t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock {
|
if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock {
|
||||||
t.Errorf("Head fast block mismatch: have %d, want %d", 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 {
|
if head := chain.CurrentBlock(); head.NumberU64() != basic.expHeadBlock {
|
||||||
t.Errorf("Head block mismatch: have %d, want %d", 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)
|
block := chain.GetBlockByNumber(basic.expSnapshotBottom)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
t.Errorf("The correspnding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom)
|
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()) {
|
} 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())
|
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
|
// 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)
|
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
|
// Restart the chain normally
|
||||||
chain.Stop()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer newchain.Stop()
|
defer newchain.Stop()
|
||||||
|
|
||||||
snaptest.verify(t, newchain, blocks)
|
snaptest.verify(t, newchain, blocks)
|
||||||
|
|
@ -245,7 +269,7 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||||
chain, blocks := snaptest.prepare(t)
|
chain, blocks := snaptest.prepare(t)
|
||||||
|
|
||||||
// Pull the plug on the database, simulating a hard crash
|
// Pull the plug on the database, simulating a hard crash
|
||||||
db := chain.db
|
db := chain.DB()
|
||||||
db.Close()
|
db.Close()
|
||||||
|
|
||||||
// Start a new blockchain back up and see where the repair leads us
|
// 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
|
// 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
|
// after the normal stop. It's used to ensure the broken snapshot
|
||||||
// can be detected all the time.
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
newchain.Stop()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
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.
|
// Insert blocks without enabling snapshot if gapping is required.
|
||||||
chain.Stop()
|
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
|
// Insert a few more blocks without enabling snapshot
|
||||||
var cacheConfig = &CacheConfig{
|
var cacheConfig = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0,
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newchain.InsertChain(gappedBlocks)
|
newchain.InsertChain(gappedBlocks)
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
// Restart the chain with enabling the snapshot
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer newchain.Stop()
|
defer newchain.Stop()
|
||||||
|
|
||||||
snaptest.verify(t, newchain, blocks)
|
snaptest.verify(t, newchain, blocks)
|
||||||
|
|
@ -337,7 +365,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
|
||||||
chain.SetHead(snaptest.setHead)
|
chain.SetHead(snaptest.setHead)
|
||||||
chain.Stop()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -368,11 +396,12 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
|
||||||
// and state committed.
|
// and state committed.
|
||||||
chain.Stop()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
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.InsertChain(newBlocks)
|
||||||
|
|
||||||
// Commit the entire snapshot into the disk if requested. Note only
|
// 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
|
// journal and latest state will be committed
|
||||||
|
|
||||||
// Restart the chain after the crash
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -414,38 +443,42 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||||
// and state committed.
|
// and state committed.
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
|
|
||||||
config := &CacheConfig{
|
config := &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0,
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
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.InsertChain(newBlocks)
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
// Restart the chain, the wiper should starts working
|
// Restart the chain, the wiper should starts working
|
||||||
config = &CacheConfig{
|
config = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 256,
|
SnapshotLimit: 256,
|
||||||
SnapshotWait: false, // Don't wait rebuild
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
// Simulate the blockchain crash.
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
snaptest.verify(t, newchain, blocks)
|
snaptest.verify(t, newchain, blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,7 +183,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
// END: Bor changes
|
// END: Bor changes
|
||||||
|
|
||||||
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
|
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
|
||||||
var dbVer = "<nil>"
|
dbVer := "<nil>"
|
||||||
if bcVersion != nil {
|
if bcVersion != nil {
|
||||||
dbVer = fmt.Sprintf("%d", *bcVersion)
|
dbVer = fmt.Sprintf("%d", *bcVersion)
|
||||||
}
|
}
|
||||||
|
|
@ -471,8 +471,10 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||||
if threads == 0 {
|
if threads == 0 {
|
||||||
threads = -1 // Disable the miner from within
|
threads = -1 // Disable the miner from within
|
||||||
}
|
}
|
||||||
|
|
||||||
th.SetThreads(threads)
|
th.SetThreads(threads)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the miner was not running, initialize it
|
// If the miner was not running, initialize it
|
||||||
if !s.IsMining() {
|
if !s.IsMining() {
|
||||||
// Propagate the initial price point to the transaction pool
|
// Propagate the initial price point to the transaction pool
|
||||||
|
|
@ -485,6 +487,7 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||||
eb, err := s.Etherbase()
|
eb, err := s.Etherbase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot start mining without etherbase", "err", err)
|
log.Error("Cannot start mining without etherbase", "err", err)
|
||||||
|
|
||||||
return fmt.Errorf("etherbase missing: %v", err)
|
return fmt.Errorf("etherbase missing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -499,20 +502,26 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||||
cli = c
|
cli = c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli != nil {
|
if cli != nil {
|
||||||
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
||||||
if wallet == nil || err != nil {
|
if wallet == nil || err != nil {
|
||||||
log.Error("Etherbase account unavailable locally", "err", err)
|
log.Error("Etherbase account unavailable locally", "err", err)
|
||||||
|
|
||||||
return fmt.Errorf("signer missing: %v", err)
|
return fmt.Errorf("signer missing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cli.Authorize(eb, wallet.SignData)
|
cli.Authorize(eb, wallet.SignData)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bor, ok := s.engine.(*bor.Bor); ok {
|
if bor, ok := s.engine.(*bor.Bor); ok {
|
||||||
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
||||||
if wallet == nil || err != nil {
|
if wallet == nil || err != nil {
|
||||||
log.Error("Etherbase account unavailable locally", "err", err)
|
log.Error("Etherbase account unavailable locally", "err", err)
|
||||||
|
|
||||||
return fmt.Errorf("signer missing: %v", err)
|
return fmt.Errorf("signer missing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bor.Authorize(eb, wallet.SignData)
|
bor.Authorize(eb, wallet.SignData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -522,6 +531,7 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||||
|
|
||||||
go s.miner.Start(eb)
|
go s.miner.Start(eb)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -575,6 +585,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
|
||||||
if s.config.SnapshotCache > 0 {
|
if s.config.SnapshotCache > 0 {
|
||||||
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...)
|
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return protos
|
return protos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -599,6 +610,7 @@ func (s *Ethereum) Start() error {
|
||||||
}
|
}
|
||||||
// Start the networking layer and the light server if requested
|
// Start the networking layer and the light server if requested
|
||||||
s.handler.Start(maxPeers)
|
s.handler.Start(maxPeers)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
"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/clique"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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
|
// 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.
|
// 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 != "" {
|
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 {
|
} else {
|
||||||
switch config.PowMode {
|
switch config.PowMode {
|
||||||
case ethash.ModeFake:
|
case ethash.ModeFake:
|
||||||
|
|
|
||||||
|
|
@ -47,16 +47,19 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Block = blockFields
|
res.Block = blockFields
|
||||||
|
|
||||||
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
|
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
reexec := defaultTraceReexec
|
reexec := defaultTraceReexec
|
||||||
if config != nil && config.Reexec != nil {
|
if config != nil && config.Reexec != nil {
|
||||||
reexec = *config.Reexec
|
reexec = *config.Reexec
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: discuss consequences of setting preferDisk false.
|
// TODO: discuss consequences of setting preferDisk false.
|
||||||
statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
|
statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -96,6 +99,7 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T
|
||||||
if len(execRes.Revert()) > 0 {
|
if len(execRes.Revert()) > 0 {
|
||||||
returnVal = fmt.Sprintf("%x", execRes.Revert())
|
returnVal = fmt.Sprintf("%x", execRes.Revert())
|
||||||
}
|
}
|
||||||
|
|
||||||
result := ðapi.ExecutionResult{
|
result := ðapi.ExecutionResult{
|
||||||
Gas: execRes.UsedGas,
|
Gas: execRes.UsedGas,
|
||||||
Failed: execRes.Failed(),
|
Failed: execRes.Failed(),
|
||||||
|
|
@ -106,12 +110,14 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T
|
||||||
Result: result,
|
Result: result,
|
||||||
IntermediateHash: statedb.IntermediateRoot(deleteEmptyObjects),
|
IntermediateHash: statedb.IntermediateRoot(deleteEmptyObjects),
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
for indx, tx := range txs {
|
for indx, tx := range txs {
|
||||||
res.Transactions = append(res.Transactions, traceTxn(indx, tx))
|
res.Transactions = append(res.Transactions, traceTxn(indx, tx))
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,5 +145,6 @@ func (api *API) TraceBorBlock(req *TraceBlockRequest) (*BlockTraceResult, error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.traceBorBlock(ctx, block, req.Config)
|
return api.traceBorBlock(ctx, block, req.Config)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
79
go.mod
79
go.mod
|
|
@ -1,10 +1,9 @@
|
||||||
module github.com/ethereum/go-ethereum
|
module github.com/ethereum/go-ethereum
|
||||||
|
|
||||||
go 1.16
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0
|
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/VictoriaMetrics/fastcache v1.6.0
|
||||||
github.com/aws/aws-sdk-go-v2 v1.2.0
|
github.com/aws/aws-sdk-go-v2 v1.2.0
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.1.1
|
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/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/deckarep/golang-set v1.8.0
|
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/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf
|
||||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48
|
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48
|
||||||
github.com/edsrzf/mmap-go v1.0.0
|
github.com/edsrzf/mmap-go v1.0.0
|
||||||
github.com/fatih/color v1.7.0
|
github.com/fatih/color v1.7.0
|
||||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
|
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
|
||||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
|
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-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-jwt/jwt/v4 v4.3.0
|
||||||
|
github.com/golang/mock v1.6.0
|
||||||
github.com/golang/protobuf v1.5.2
|
github.com/golang/protobuf v1.5.2
|
||||||
github.com/golang/snappy v0.0.4
|
github.com/golang/snappy v0.0.4
|
||||||
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa
|
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa
|
||||||
|
|
@ -45,25 +39,19 @@ require (
|
||||||
github.com/imdario/mergo v0.3.11
|
github.com/imdario/mergo v0.3.11
|
||||||
github.com/influxdata/influxdb v1.8.3
|
github.com/influxdata/influxdb v1.8.3
|
||||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
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/jackpal/go-nat-pmp v1.0.2
|
||||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
||||||
github.com/julienschmidt/httprouter v1.3.0
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
github.com/karalabe/usb v0.0.2
|
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-colorable v0.1.8
|
||||||
github.com/mattn/go-isatty v0.0.12
|
github.com/mattn/go-isatty v0.0.12
|
||||||
github.com/mitchellh/cli v1.1.2
|
github.com/mitchellh/cli v1.1.2
|
||||||
github.com/mitchellh/go-grpc-net-conn v0.0.0-20200427190222-eb030e4876f0
|
github.com/mitchellh/go-grpc-net-conn v0.0.0-20200427190222-eb030e4876f0
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
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/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
|
||||||
github.com/olekukonko/tablewriter v0.0.5
|
github.com/olekukonko/tablewriter v0.0.5
|
||||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
|
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/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/rjeczalik/notify v0.9.1
|
||||||
github.com/rs/cors v1.7.0
|
github.com/rs/cors v1.7.0
|
||||||
github.com/ryanuber/columnize v2.1.2+incompatible
|
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/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
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/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
|
||||||
github.com/xsleonard/go-merkle v1.1.0
|
github.com/xsleonard/go-merkle v1.1.0
|
||||||
go.opentelemetry.io/otel v1.2.0
|
go.opentelemetry.io/otel v1.2.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0
|
||||||
go.opentelemetry.io/otel/sdk 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/crypto v0.0.0-20220507011949-2cf3adece122
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6
|
||||||
golang.org/x/text v0.3.7
|
golang.org/x/text v0.3.7
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||||
golang.org/x/tools v0.1.10
|
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/grpc v1.42.0
|
||||||
google.golang.org/protobuf v1.27.1
|
google.golang.org/protobuf v1.27.1
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
|
||||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
|
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
|
||||||
gopkg.in/urfave/cli.v1 v1.20.0
|
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
|
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/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/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-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 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 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
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 h1:YoYoC9J0jwfukodSBMzZYUVQ8PTiYg4BnOWiJVzTmLs=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
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 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/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 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
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/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 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
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 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 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
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/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/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-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 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-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=
|
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-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 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
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/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.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
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.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.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.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.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.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/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.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.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.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.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.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.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 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
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=
|
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/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 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
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/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 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
|
||||||
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
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 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
|
||||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
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.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/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.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/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/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 h1:fHe1fuhJjGH22ZzVTAH0jqHLhTGhOq3wQjJN+8P0jQg=
|
||||||
github.com/xsleonard/go-merkle v1.1.0/go.mod h1:cW4z+UZ/4f2n9IJgIiyDCdYguchoDyDAPmpuOWGxdGg=
|
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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
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.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 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
|
||||||
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
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-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-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-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-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 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
|
||||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
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=
|
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-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-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-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 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-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-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
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-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-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-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/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-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
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.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.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.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.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 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
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=
|
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-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-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-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-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-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
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-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-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-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-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 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
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=
|
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-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-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-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-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 h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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-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-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-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 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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=
|
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-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-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-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.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.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 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
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-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-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-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-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 h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
||||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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.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.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
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/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ func NewFlagSet(name string) *Flagset {
|
||||||
flags: []*FlagVar{},
|
flags: []*FlagVar{},
|
||||||
set: flag.NewFlagSet(name, flag.ContinueOnError),
|
set: flag.NewFlagSet(name, flag.ContinueOnError),
|
||||||
}
|
}
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,10 +35,12 @@ func (f *Flagset) addFlag(fl *FlagVar) {
|
||||||
|
|
||||||
func (f *Flagset) Help() string {
|
func (f *Flagset) Help() string {
|
||||||
str := "Options:\n\n"
|
str := "Options:\n\n"
|
||||||
|
|
||||||
items := []string{}
|
items := []string{}
|
||||||
for _, item := range f.flags {
|
for _, item := range f.flags {
|
||||||
items = append(items, fmt.Sprintf(" -%s\n %s", item.Name, item.Usage))
|
items = append(items, fmt.Sprintf(" -%s\n %s", item.Name, item.Usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
return str + strings.Join(items, "\n\n")
|
return str + strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,25 +56,30 @@ func (f *Flagset) MarkDown() string {
|
||||||
groups[item.Group] = append(groups[item.Group], item)
|
groups[item.Group] = append(groups[item.Group], item)
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := make([]string, len(groups))
|
|
||||||
i := 0
|
i := 0
|
||||||
|
keys := make([]string, len(groups))
|
||||||
|
|
||||||
for k := range groups {
|
for k := range groups {
|
||||||
keys[i] = k
|
keys[i] = k
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
items := []string{}
|
items := []string{}
|
||||||
|
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if k == "" {
|
if k == "" {
|
||||||
items = append(items, fmt.Sprintf("## Options"))
|
items = append(items, "## Options")
|
||||||
} else {
|
} else {
|
||||||
items = append(items, fmt.Sprintf("### %s Options", k))
|
items = append(items, fmt.Sprintf("### %s Options", k))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range groups[k] {
|
for _, item := range groups[k] {
|
||||||
items = append(items, fmt.Sprintf("- ```%s```: %s", item.Name, item.Usage))
|
items = append(items, fmt.Sprintf("- ```%s```: %s", item.Name, item.Usage))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,6 +170,7 @@ func (b *BigIntFlag) String() string {
|
||||||
if b.Value == nil {
|
if b.Value == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.Value.String()
|
return b.Value.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,10 +183,12 @@ func (b *BigIntFlag) Set(value string) error {
|
||||||
} else {
|
} else {
|
||||||
num, ok = num.SetString(value, 10)
|
num, ok = num.SetString(value, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("failed to set big int")
|
return fmt.Errorf("failed to set big int")
|
||||||
}
|
}
|
||||||
b.Value = num
|
b.Value = num
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,11 +212,13 @@ func (i *SliceStringFlag) String() string {
|
||||||
if i.Value == nil {
|
if i.Value == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(*i.Value, ",")
|
return strings.Join(*i.Value, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *SliceStringFlag) Set(value string) error {
|
func (i *SliceStringFlag) Set(value string) error {
|
||||||
*i.Value = append(*i.Value, strings.Split(value, ",")...)
|
*i.Value = append(*i.Value, strings.Split(value, ",")...)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,10 +259,12 @@ func (m *MapStringFlag) String() string {
|
||||||
if m.Value == nil {
|
if m.Value == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
ls := []string{}
|
ls := []string{}
|
||||||
for k, v := range *m.Value {
|
for k, v := range *m.Value {
|
||||||
ls = append(ls, k+"="+v)
|
ls = append(ls, k+"="+v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(ls, ",")
|
return strings.Join(ls, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,6 +272,7 @@ func (m *MapStringFlag) Set(value string) error {
|
||||||
if m.Value == nil {
|
if m.Value == nil {
|
||||||
m.Value = &map[string]string{}
|
m.Value = &map[string]string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range strings.Split(value, ",") {
|
for _, t := range strings.Split(value, ",") {
|
||||||
if t != "" {
|
if t != "" {
|
||||||
kv := strings.Split(t, "=")
|
kv := strings.Split(t, "=")
|
||||||
|
|
@ -266,6 +282,7 @@ func (m *MapStringFlag) Set(value string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,18 +26,23 @@ var chains = map[string]*Chain{
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetChain(name string) (*Chain, error) {
|
func GetChain(name string) (*Chain, error) {
|
||||||
var chain *Chain
|
var (
|
||||||
var err error
|
chain *Chain
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
if _, fileErr := os.Stat(name); fileErr == nil {
|
if _, fileErr := os.Stat(name); fileErr == nil {
|
||||||
if chain, err = ImportFromFile(name); err != nil {
|
if chain, err = ImportFromFile(name); err != nil {
|
||||||
return nil, fmt.Errorf("error importing chain from file: %v", err)
|
return nil, fmt.Errorf("error importing chain from file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return chain, nil
|
return chain, nil
|
||||||
} else if errors.Is(fileErr, os.ErrNotExist) {
|
} else if errors.Is(fileErr, os.ErrNotExist) {
|
||||||
var ok bool
|
var ok bool
|
||||||
if chain, ok = chains[name]; !ok {
|
if chain, ok = chains[name]; !ok {
|
||||||
return nil, fmt.Errorf("chain %s not found", name)
|
return nil, fmt.Errorf("chain %s not found", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return chain, nil
|
return chain, nil
|
||||||
} else {
|
} else {
|
||||||
return nil, fileErr
|
return nil, fileErr
|
||||||
|
|
@ -62,10 +67,12 @@ func importChain(content []byte) (*Chain, error) {
|
||||||
|
|
||||||
if chain.Genesis == nil {
|
if chain.Genesis == nil {
|
||||||
log.Info("Try reading as legacy genesis")
|
log.Info("Try reading as legacy genesis")
|
||||||
|
|
||||||
var genesis core.Genesis
|
var genesis core.Genesis
|
||||||
if err := json.Unmarshal(content, &genesis); err != nil {
|
if err := json.Unmarshal(content, &genesis); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if genesis.Config != nil {
|
if genesis.Config != nil {
|
||||||
chain.Genesis = &genesis
|
chain.Genesis = &genesis
|
||||||
chain.NetworkId = genesis.Config.ChainID.Uint64()
|
chain.NetworkId = genesis.Config.ChainID.Uint64()
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChain_ImportFromFile(t *testing.T) {
|
func TestChain_ImportFromFile(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
filename string
|
filename string
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
|
|
@ -34,8 +37,13 @@ func TestChain_ImportFromFile(t *testing.T) {
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
_, err := ImportFromFile(tt.args.filename)
|
_, err := ImportFromFile(tt.args.filename)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("ImportFromFile() error = %v, wantErr %v", err, 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.",
|
"The ```bor server``` command runs the Bor client.",
|
||||||
c.Flags().MarkDown(),
|
c.Flags().MarkDown(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(items, "\n\n")
|
return strings.Join(items, "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ type Config struct {
|
||||||
// GcMode selects the garbage collection mode for the trie
|
// GcMode selects the garbage collection mode for the trie
|
||||||
GcMode string `hcl:"gc-mode,optional"`
|
GcMode string `hcl:"gc-mode,optional"`
|
||||||
|
|
||||||
// NoSnapshot disbales the snapshot database mode
|
// NoSnapshot disables the snapshot database mode
|
||||||
NoSnapshot bool `hcl:"no-snapshot,optional"`
|
NoSnapshot bool `hcl:"no-snapshot,optional"`
|
||||||
|
|
||||||
// Ethstats is the address of the ethstats server to send telemetry
|
// Ethstats is the address of the ethstats server to send telemetry
|
||||||
|
|
@ -527,18 +527,22 @@ func (c *Config) fillBigInt() error {
|
||||||
b := new(big.Int)
|
b := new(big.Int)
|
||||||
|
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if strings.HasPrefix(*x.str, "0x") {
|
if strings.HasPrefix(*x.str, "0x") {
|
||||||
b, ok = b.SetString((*x.str)[2:], 16)
|
b, ok = b.SetString((*x.str)[2:], 16)
|
||||||
} else {
|
} else {
|
||||||
b, ok = b.SetString(*x.str, 10)
|
b, ok = b.SetString(*x.str, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("%s can't parse big int %s", x.path, *x.str)
|
return fmt.Errorf("%s can't parse big int %s", x.path, *x.str)
|
||||||
}
|
}
|
||||||
|
|
||||||
*x.str = ""
|
*x.str = ""
|
||||||
*x.td = b
|
*x.td = b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -559,10 +563,12 @@ func (c *Config) fillTimeDurations() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s can't parse time duration %s", x.path, *x.str)
|
return fmt.Errorf("%s can't parse time duration %s", x.path, *x.str)
|
||||||
}
|
}
|
||||||
|
|
||||||
*x.str = ""
|
*x.str = ""
|
||||||
*x.td = d
|
*x.td = d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,6 +580,7 @@ func readConfigFile(path string) (*Config, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return readLegacyConfig(data)
|
return readLegacyConfig(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -582,15 +589,19 @@ func readConfigFile(path string) (*Config, error) {
|
||||||
Cache: &CacheConfig{},
|
Cache: &CacheConfig{},
|
||||||
Sealer: &SealerConfig{},
|
Sealer: &SealerConfig{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := hclsimple.DecodeFile(path, nil, config); err != nil {
|
if err := hclsimple.DecodeFile(path, nil, config); err != nil {
|
||||||
return nil, fmt.Errorf("failed to decode config file '%s': %v", path, err)
|
return nil, fmt.Errorf("failed to decode config file '%s': %v", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := config.fillBigInt(); err != nil {
|
if err := config.fillBigInt(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := config.fillTimeDurations(); err != nil {
|
if err := config.fillTimeDurations(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -599,6 +610,7 @@ func (c *Config) loadChain() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.chain = chain
|
c.chain = chain
|
||||||
|
|
||||||
// preload some default values that depend on the chain file
|
// preload some default values that depend on the chain file
|
||||||
|
|
@ -612,14 +624,17 @@ func (c *Config) loadChain() error {
|
||||||
} else {
|
} else {
|
||||||
c.Cache.Cache = 1024
|
c.Cache.Cache = 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:gocognit
|
||||||
func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*ethconfig.Config, error) {
|
func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*ethconfig.Config, error) {
|
||||||
dbHandles, err := makeDatabaseHandles()
|
dbHandles, err := makeDatabaseHandles()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n := ethconfig.Defaults
|
n := ethconfig.Defaults
|
||||||
|
|
||||||
// only update for non-developer mode as we don't yet
|
// 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) {
|
if !common.IsHexAddress(etherbase) {
|
||||||
return nil, fmt.Errorf("etherbase is not an address: %s", etherbase)
|
return nil, fmt.Errorf("etherbase is not an address: %s", etherbase)
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Miner.Etherbase = common.HexToAddress(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() {
|
if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() {
|
||||||
return nil, fmt.Errorf("account unlock with HTTP access is forbidden")
|
return nil, fmt.Errorf("account unlock with HTTP access is forbidden")
|
||||||
}
|
}
|
||||||
|
|
||||||
ks := accountManager.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
|
ks := accountManager.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
|
||||||
|
|
||||||
passwords, err := MakePasswordListFromFile(c.Accounts.PasswordFile)
|
passwords, err := MakePasswordListFromFile(c.Accounts.PasswordFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(passwords) < len(c.Accounts.Unlock) {
|
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",
|
return nil, fmt.Errorf("number of passwords provided (%v) is less than number of accounts (%v) to unlock",
|
||||||
len(passwords), len(c.Accounts.Unlock))
|
len(passwords), len(c.Accounts.Unlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, account := range 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
|
passphrase string
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
// etherbase has been set above, configuring the miner address from command line flags.
|
// etherbase has been set above, configuring the miner address from command line flags.
|
||||||
if n.Miner.Etherbase != (common.Address{}) {
|
if n.Miner.Etherbase != (common.Address{}) {
|
||||||
developer = accounts.Account{Address: n.Miner.Etherbase}
|
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 {
|
if err := ks.Unlock(developer, passphrase); err != nil {
|
||||||
return nil, fmt.Errorf("failed to unlock developer account: %v", err)
|
return nil, fmt.Errorf("failed to unlock developer account: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Using developer account", "address", developer.Address)
|
log.Info("Using developer account", "address", developer.Address)
|
||||||
|
|
||||||
// Set the Etherbase
|
// Set the Etherbase
|
||||||
|
|
@ -753,10 +778,12 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid required block number %s: %v", k, err)
|
return nil, fmt.Errorf("invalid required block number %s: %v", k, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var hash common.Hash
|
var hash common.Hash
|
||||||
if err = hash.UnmarshalText([]byte(v)); err != nil {
|
if err = hash.UnmarshalText([]byte(v)); err != nil {
|
||||||
return nil, fmt.Errorf("invalid required block hash %s: %v", v, err)
|
return nil, fmt.Errorf("invalid required block hash %s: %v", v, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
n.PeerRequiredBlocks[number] = hash
|
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)
|
log.Warn("Lowering memory allowance on 32bit arch", "available", mem.Total/1024/1024, "addressable", 2*1024)
|
||||||
mem.Total = 2 * 1024 * 1024 * 1024
|
mem.Total = 2 * 1024 * 1024 * 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
allowance := uint64(mem.Total / 1024 / 1024 / 3)
|
allowance := uint64(mem.Total / 1024 / 1024 / 3)
|
||||||
if cache > allowance {
|
if cache > allowance {
|
||||||
log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", 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 {
|
} else {
|
||||||
log.Info("Global gas cap disabled")
|
log.Info("Global gas cap disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
n.RPCTxFeeCap = c.JsonRPC.TxFeeCap
|
n.RPCTxFeeCap = c.JsonRPC.TxFeeCap
|
||||||
|
|
||||||
// sync mode. It can either be "fast", "full" or "snap". We disable
|
// 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
|
n.DatabaseHandles = dbHandles
|
||||||
|
|
||||||
return &n, nil
|
return &n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -906,6 +936,7 @@ func (c *Config) buildNode() (*node.Config, error) {
|
||||||
cfg.HTTPHost = c.JsonRPC.Http.Host
|
cfg.HTTPHost = c.JsonRPC.Http.Host
|
||||||
cfg.HTTPPort = int(c.JsonRPC.Http.Port)
|
cfg.HTTPPort = int(c.JsonRPC.Http.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.JsonRPC.Ws.Enabled {
|
if c.JsonRPC.Ws.Enabled {
|
||||||
cfg.WSHost = c.JsonRPC.Ws.Host
|
cfg.WSHost = c.JsonRPC.Ws.Host
|
||||||
cfg.WSPort = int(c.JsonRPC.Ws.Port)
|
cfg.WSPort = int(c.JsonRPC.Ws.Port)
|
||||||
|
|
@ -916,6 +947,7 @@ func (c *Config) buildNode() (*node.Config, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("wrong 'nat' flag: %v", err)
|
return nil, fmt.Errorf("wrong 'nat' flag: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.P2P.NAT = natif
|
cfg.P2P.NAT = natif
|
||||||
|
|
||||||
// only check for non-developer modes
|
// only check for non-developer modes
|
||||||
|
|
@ -926,21 +958,27 @@ func (c *Config) buildNode() (*node.Config, error) {
|
||||||
if len(bootnodes) == 0 {
|
if len(bootnodes) == 0 {
|
||||||
bootnodes = c.chain.Bootnodes
|
bootnodes = c.chain.Bootnodes
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.P2P.BootstrapNodes, err = parseBootnodes(bootnodes); err != nil {
|
if cfg.P2P.BootstrapNodes, err = parseBootnodes(bootnodes); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.P2P.BootstrapNodesV5, err = parseBootnodes(c.P2P.Discovery.BootnodesV5); err != nil {
|
if cfg.P2P.BootstrapNodesV5, err = parseBootnodes(c.P2P.Discovery.BootnodesV5); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.P2P.StaticNodes, err = parseBootnodes(c.P2P.Discovery.StaticNodes); err != nil {
|
if cfg.P2P.StaticNodes, err = parseBootnodes(c.P2P.Discovery.StaticNodes); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.P2P.StaticNodes) == 0 {
|
if len(cfg.P2P.StaticNodes) == 0 {
|
||||||
cfg.P2P.StaticNodes = cfg.StaticNodes()
|
cfg.P2P.StaticNodes = cfg.StaticNodes()
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.P2P.TrustedNodes, err = parseBootnodes(c.P2P.Discovery.TrustedNodes); err != nil {
|
if cfg.P2P.TrustedNodes, err = parseBootnodes(c.P2P.Discovery.TrustedNodes); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.P2P.TrustedNodes) == 0 {
|
if len(cfg.P2P.TrustedNodes) == 0 {
|
||||||
cfg.P2P.TrustedNodes = cfg.TrustedNodes()
|
cfg.P2P.TrustedNodes = cfg.TrustedNodes()
|
||||||
}
|
}
|
||||||
|
|
@ -951,6 +989,7 @@ func (c *Config) buildNode() (*node.Config, error) {
|
||||||
cfg.P2P.MaxPeers = 0
|
cfg.P2P.MaxPeers = 0
|
||||||
cfg.P2P.NoDiscovery = true
|
cfg.P2P.NoDiscovery = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -960,6 +999,7 @@ func (c *Config) Merge(cc ...*Config) error {
|
||||||
return fmt.Errorf("failed to merge configurations: %v", err)
|
return fmt.Errorf("failed to merge configurations: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -968,10 +1008,12 @@ func makeDatabaseHandles() (int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
raised, err := fdlimit.Raise(uint64(limit))
|
raised, err := fdlimit.Raise(uint64(limit))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return int(raised / 2), nil
|
return int(raised / 2), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -986,6 +1028,7 @@ func parseBootnodes(urls []string) ([]*enode.Node, error) {
|
||||||
dst = append(dst, node)
|
dst = append(dst, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dst, nil
|
return dst, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -996,6 +1039,7 @@ func defaultDataDir() string {
|
||||||
// we cannot guess a stable location
|
// we cannot guess a stable location
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "darwin":
|
case "darwin":
|
||||||
return filepath.Join(home, "Library", "Bor")
|
return filepath.Join(home, "Library", "Bor")
|
||||||
|
|
@ -1005,6 +1049,7 @@ func defaultDataDir() string {
|
||||||
// Windows XP and below don't have LocalAppData.
|
// Windows XP and below don't have LocalAppData.
|
||||||
panic("environment variable LocalAppData is undefined")
|
panic("environment variable LocalAppData is undefined")
|
||||||
}
|
}
|
||||||
|
|
||||||
return filepath.Join(appdata, "Bor")
|
return filepath.Join(appdata, "Bor")
|
||||||
default:
|
default:
|
||||||
return filepath.Join(home, ".bor")
|
return filepath.Join(home, ".bor")
|
||||||
|
|
@ -1016,6 +1061,7 @@ func Hostname() string {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "bor"
|
return "bor"
|
||||||
}
|
}
|
||||||
|
|
||||||
return hostname
|
return hostname
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1024,10 +1070,13 @@ func MakePasswordListFromFile(path string) ([]string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to read password file: %v", err)
|
return nil, fmt.Errorf("Failed to read password file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(string(text), "\n")
|
lines := strings.Split(string(text), "\n")
|
||||||
|
|
||||||
// Sanitise DOS line endings.
|
// Sanitise DOS line endings.
|
||||||
for i := range lines {
|
for i := range lines {
|
||||||
lines[i] = strings.TrimRight(lines[i], "\r")
|
lines[i] = strings.TrimRight(lines[i], "\r")
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines, nil
|
return lines, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ func TestConfigMerge(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := &Config{
|
expected := &Config{
|
||||||
Chain: "1",
|
Chain: "1",
|
||||||
NoSnapshot: false,
|
NoSnapshot: false,
|
||||||
|
|
@ -69,11 +70,14 @@ func TestConfigMerge(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NoError(t, c0.Merge(c1))
|
assert.NoError(t, c0.Merge(c1))
|
||||||
assert.Equal(t, c0, expected)
|
assert.Equal(t, c0, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultDatatypeOverride(t *testing.T) {
|
func TestDefaultDatatypeOverride(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
// This test is specific to `maxpeers` flag (for now) to check
|
// This test is specific to `maxpeers` flag (for now) to check
|
||||||
// if default datatype value (0 in case of uint64) is overridden.
|
// if default datatype value (0 in case of uint64) is overridden.
|
||||||
c0 := &Config{
|
c0 := &Config{
|
||||||
|
|
@ -81,16 +85,19 @@ func TestDefaultDatatypeOverride(t *testing.T) {
|
||||||
MaxPeers: 30,
|
MaxPeers: 30,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
c1 := &Config{
|
c1 := &Config{
|
||||||
P2P: &P2PConfig{
|
P2P: &P2PConfig{
|
||||||
MaxPeers: 0,
|
MaxPeers: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := &Config{
|
expected := &Config{
|
||||||
P2P: &P2PConfig{
|
P2P: &P2PConfig{
|
||||||
MaxPeers: 0,
|
MaxPeers: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NoError(t, c0.Merge(c1))
|
assert.NoError(t, c0.Merge(c1))
|
||||||
assert.Equal(t, c0, expected)
|
assert.Equal(t, c0, expected)
|
||||||
}
|
}
|
||||||
|
|
@ -99,6 +106,7 @@ func TestConfigLoadFile(t *testing.T) {
|
||||||
readFile := func(path string) {
|
readFile := func(path string) {
|
||||||
config, err := readConfigFile(path)
|
config, err := readConfigFile(path)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, config, &Config{
|
assert.Equal(t, config, &Config{
|
||||||
DataDir: "./data",
|
DataDir: "./data",
|
||||||
RequiredBlocks: map[string]string{
|
RequiredBlocks: map[string]string{
|
||||||
|
|
@ -122,6 +130,7 @@ func TestConfigLoadFile(t *testing.T) {
|
||||||
t.Run("hcl", func(t *testing.T) {
|
t.Run("hcl", func(t *testing.T) {
|
||||||
readFile("./testdata/simple.hcl")
|
readFile("./testdata/simple.hcl")
|
||||||
})
|
})
|
||||||
|
|
||||||
// read file in json format
|
// read file in json format
|
||||||
t.Run("json", func(t *testing.T) {
|
t.Run("json", func(t *testing.T) {
|
||||||
readFile("./testdata/simple.json")
|
readFile("./testdata/simple.json")
|
||||||
|
|
@ -152,7 +161,11 @@ func TestConfigBootnodesDefault(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMakePasswordListFromFile(t *testing.T) {
|
func TestMakePasswordListFromFile(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
t.Run("ReadPasswordFile", func(t *testing.T) {
|
t.Run("ReadPasswordFile", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
result, _ := MakePasswordListFromFile("./testdata/password.txt")
|
result, _ := MakePasswordListFromFile("./testdata/password.txt")
|
||||||
assert.Equal(t, []string{"test1", "test2"}, result)
|
assert.Equal(t, []string{"test1", "test2"}, result)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,13 @@ func findAvailablePort(from int32, count int32) (int32, error) {
|
||||||
if count == maxPortCheck {
|
if count == maxPortCheck {
|
||||||
return 0, fmt.Errorf("no available port found")
|
return 0, fmt.Errorf("no available port found")
|
||||||
}
|
}
|
||||||
|
|
||||||
port := atomic.AddInt32(&from, 1)
|
port := atomic.AddInt32(&from, 1)
|
||||||
addr := fmt.Sprintf("localhost:%d", port)
|
addr := fmt.Sprintf("localhost:%d", port)
|
||||||
lis, err := net.Listen("tcp", addr)
|
|
||||||
count++
|
count++
|
||||||
|
|
||||||
|
lis, err := net.Listen("tcp", addr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
lis.Close()
|
lis.Close()
|
||||||
return port, nil
|
return port, nil
|
||||||
|
|
@ -36,8 +39,13 @@ func CreateMockServer(config *Config) (*Server, error) {
|
||||||
|
|
||||||
// find available port for grpc server
|
// find available port for grpc server
|
||||||
rand.Seed(time.Now().UnixNano())
|
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)
|
port, err := findAvailablePort(rand.Int31n(to-from+1)+from, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -53,10 +61,13 @@ func CreateMockServer(config *Config) (*Server, error) {
|
||||||
// find available port for http server
|
// find available port for http server
|
||||||
from = 8545
|
from = 8545
|
||||||
to = 9545
|
to = 9545
|
||||||
|
|
||||||
|
//nolint: gosec
|
||||||
port, err = findAvailablePort(rand.Int31n(to-from+1)+from, 0)
|
port, err = findAvailablePort(rand.Int31n(to-from+1)+from, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.JsonRPC.Http.Port = uint64(port)
|
config.JsonRPC.Http.Port = uint64(port)
|
||||||
|
|
||||||
// start the server
|
// start the server
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,16 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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"
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
"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/influxdb"
|
||||||
"github.com/ethereum/go-ethereum/metrics/prometheus"
|
"github.com/ethereum/go-ethereum/metrics/prometheus"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"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 {
|
type Server struct {
|
||||||
|
|
@ -71,6 +72,7 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stack, err := node.New(nodeCfg)
|
stack, err := node.New(nodeCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -82,6 +84,7 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
|
|
||||||
// register backend to account manager with keystore for signing
|
// register backend to account manager with keystore for signing
|
||||||
keydir := stack.KeyStoreDir()
|
keydir := stack.KeyStoreDir()
|
||||||
|
|
||||||
n, p := keystore.StandardScryptN, keystore.StandardScryptP
|
n, p := keystore.StandardScryptN, keystore.StandardScryptP
|
||||||
if config.Accounts.UseLightweightKDF {
|
if config.Accounts.UseLightweightKDF {
|
||||||
n, p = keystore.LightScryptN, keystore.LightScryptP
|
n, p = keystore.LightScryptN, keystore.LightScryptP
|
||||||
|
|
@ -94,6 +97,7 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
authorized := false
|
authorized := false
|
||||||
|
|
||||||
// check if personal wallet endpoints are disabled or not
|
// check if personal wallet endpoints are disabled or not
|
||||||
|
// nolint:nestif
|
||||||
if !config.Accounts.DisableBorWallet {
|
if !config.Accounts.DisableBorWallet {
|
||||||
// add keystore globally to the node's account manager if personal wallet is enabled
|
// add keystore globally to the node's account manager if personal wallet is enabled
|
||||||
stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p))
|
stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p))
|
||||||
|
|
@ -103,10 +107,12 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
backend, err := eth.New(stack, ethCfg)
|
backend, err := eth.New(stack, ethCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
srv.backend = backend
|
srv.backend = backend
|
||||||
} else {
|
} else {
|
||||||
// register the ethereum backend (with temporary created account manager)
|
// register the ethereum backend (with temporary created account manager)
|
||||||
|
|
@ -114,10 +120,12 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
backend, err := eth.New(stack, ethCfg)
|
backend, err := eth.New(stack, ethCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
srv.backend = backend
|
srv.backend = backend
|
||||||
|
|
||||||
// authorize only if mining or in developer mode
|
// authorize only if mining or in developer mode
|
||||||
|
|
@ -126,6 +134,7 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
eb, err := srv.backend.Etherbase()
|
eb, err := srv.backend.Etherbase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot start mining without etherbase", "err", err)
|
log.Error("Cannot start mining without etherbase", "err", err)
|
||||||
|
|
||||||
return nil, fmt.Errorf("etherbase missing: %v", 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})
|
wallet, err := accountManager.Find(accounts.Account{Address: eb})
|
||||||
if wallet == nil || err != nil {
|
if wallet == nil || err != nil {
|
||||||
log.Error("Etherbase account unavailable locally", "err", err)
|
log.Error("Etherbase account unavailable locally", "err", err)
|
||||||
|
|
||||||
return nil, fmt.Errorf("signer missing: %v", err)
|
return nil, fmt.Errorf("signer missing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cli.Authorize(eb, wallet.SignData)
|
cli.Authorize(eb, wallet.SignData)
|
||||||
authorized = true
|
authorized = true
|
||||||
}
|
}
|
||||||
|
|
@ -155,6 +166,7 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
log.Error("Etherbase account unavailable locally", "err", err)
|
log.Error("Etherbase account unavailable locally", "err", err)
|
||||||
return nil, fmt.Errorf("signer missing: %v", err)
|
return nil, fmt.Errorf("signer missing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bor.Authorize(eb, wallet.SignData)
|
bor.Authorize(eb, wallet.SignData)
|
||||||
authorized = true
|
authorized = true
|
||||||
}
|
}
|
||||||
|
|
@ -200,6 +212,7 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
if err := srv.node.Start(); err != nil {
|
if err := srv.node.Start(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return srv, nil
|
return srv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,10 +251,12 @@ func (s *Server) setupMetrics(config *TelemetryConfig, serviceName string) error
|
||||||
|
|
||||||
if v1Enabled {
|
if v1Enabled {
|
||||||
log.Info("Enabling metrics export to InfluxDB (v1)")
|
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)
|
go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, cfg.Database, cfg.Username, cfg.Password, "geth.", tags)
|
||||||
}
|
}
|
||||||
if v2Enabled {
|
if v2Enabled {
|
||||||
log.Info("Enabling metrics export to InfluxDB (v2)")
|
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)
|
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)
|
log.Info("GRPC Server started", "addr", addr)
|
||||||
|
|
||||||
return nil
|
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) {
|
func (s *Server) loggingServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
h, err := handler(ctx, req)
|
h, err := handler(ctx, req)
|
||||||
|
|
||||||
log.Trace("Request", "method", info.FullMethod, "duration", time.Since(start), "error", err)
|
log.Trace("Request", "method", info.FullMethod, "duration", time.Since(start), "error", err)
|
||||||
|
|
||||||
return h, err
|
return h, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupLogger(logLevel string) {
|
func setupLogger(logLevel string) {
|
||||||
output := io.Writer(os.Stderr)
|
output := io.Writer(os.Stderr)
|
||||||
|
|
||||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||||
if usecolor {
|
if usecolor {
|
||||||
output = colorable.NewColorableStderr()
|
output = colorable.NewColorableStderr()
|
||||||
}
|
}
|
||||||
|
|
||||||
ostream := log.StreamHandler(output, log.TerminalFormat(usecolor))
|
ostream := log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||||
glogger := log.NewGlogHandler(ostream)
|
glogger := log.NewGlogHandler(ostream)
|
||||||
|
|
||||||
|
|
@ -358,6 +378,7 @@ func setupLogger(logLevel string) {
|
||||||
} else {
|
} else {
|
||||||
glogger.Verbosity(log.LvlInfo)
|
glogger.Verbosity(log.LvlInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Root().SetHandler(glogger)
|
log.Root().SetHandler(glogger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -18,9 +19,11 @@ func nextPort() uint64 {
|
||||||
log.Info("Checking for new port", "current", initialPort)
|
log.Info("Checking for new port", "current", initialPort)
|
||||||
port := atomic.AddUint64(&initialPort, 1)
|
port := atomic.AddUint64(&initialPort, 1)
|
||||||
addr := fmt.Sprintf("localhost:%d", port)
|
addr := fmt.Sprintf("localhost:%d", port)
|
||||||
|
|
||||||
lis, err := net.Listen("tcp", addr)
|
lis, err := net.Listen("tcp", addr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
lis.Close()
|
lis.Close()
|
||||||
|
|
||||||
return port
|
return port
|
||||||
} else {
|
} else {
|
||||||
return nextPort()
|
return nextPort()
|
||||||
|
|
@ -28,6 +31,8 @@ func nextPort() uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServer_DeveloperMode(t *testing.T) {
|
func TestServer_DeveloperMode(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
// get the default config
|
// get the default config
|
||||||
config := DefaultConfig()
|
config := DefaultConfig()
|
||||||
|
|
||||||
|
|
@ -38,6 +43,7 @@ func TestServer_DeveloperMode(t *testing.T) {
|
||||||
// start the mock server
|
// start the mock server
|
||||||
server, err := CreateMockServer(config)
|
server, err := CreateMockServer(config)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
defer CloseMockServer(server)
|
defer CloseMockServer(server)
|
||||||
|
|
||||||
// record the initial block number
|
// record the initial block number
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"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"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
"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/internal/cli/server/proto"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"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
|
const chunkSize = 1024 * 1024 * 1024
|
||||||
|
|
@ -45,6 +46,7 @@ func sendStreamDebugFile(stream proto.Bor_DebugPprofServer, headers map[string]s
|
||||||
Request: &proto.DebugFileResponse_Input{},
|
Request: &proto.DebugFileResponse_Input{},
|
||||||
Encode: grpc_net_conn.ChunkedEncoder(encoder, chunkSize),
|
Encode: grpc_net_conn.ChunkedEncoder(encoder, chunkSize),
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := conn.Write(data); err != nil {
|
if _, err := conn.Write(data); err != nil {
|
||||||
return err
|
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 {
|
func (s *Server) DebugPprof(req *proto.DebugPprofRequest, stream proto.Bor_DebugPprofServer) error {
|
||||||
var payload []byte
|
var (
|
||||||
var headers map[string]string
|
payload []byte
|
||||||
var err error
|
headers map[string]string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case proto.DebugPprofRequest_CPU:
|
case proto.DebugPprofRequest_CPU:
|
||||||
payload, headers, err = pprof.CPUProfile(ctx, int(req.Seconds))
|
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:
|
case proto.DebugPprofRequest_LOOKUP:
|
||||||
payload, headers, err = pprof.Profile(req.Profile, 0, 0)
|
payload, headers, err = pprof.Profile(req.Profile, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if err := sendStreamDebugFile(stream, headers, payload); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,6 +199,7 @@ func (s *Server) DebugBlock(req *proto.DebugBlockRequest, stream proto.Bor_Debug
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := s.tracerAPI.TraceBorBlock(traceReq)
|
res, err := s.tracerAPI.TraceBorBlock(traceReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -202,6 +210,7 @@ func (s *Server) DebugBlock(req *proto.DebugBlockRequest, stream proto.Bor_Debug
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sendStreamDebugFile(stream, map[string]string{}, data); err != nil {
|
if err := sendStreamDebugFile(stream, map[string]string{}, data); err != nil {
|
||||||
return err
|
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
|
package miner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/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) {
|
func TestMiner(t *testing.T) {
|
||||||
miner, mux, cleanup := createMiner(t)
|
t.Parallel()
|
||||||
defer cleanup(false)
|
|
||||||
|
minerBor := NewBorDefaultMiner(t)
|
||||||
|
defer func() {
|
||||||
|
minerBor.Cleanup(false)
|
||||||
|
minerBor.Ctrl.Finish()
|
||||||
|
}()
|
||||||
|
|
||||||
|
miner := minerBor.Miner
|
||||||
|
mux := minerBor.Mux
|
||||||
|
|
||||||
miner.Start(common.HexToAddress("0x12345"))
|
miner.Start(common.HexToAddress("0x12345"))
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
// Start the downloader
|
// Start the downloader
|
||||||
mux.Post(downloader.StartEvent{})
|
mux.Post(downloader.StartEvent{})
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
|
|
||||||
// Stop the downloader and wait for the update loop to run
|
// Stop the downloader and wait for the update loop to run
|
||||||
mux.Post(downloader.DoneEvent{})
|
mux.Post(downloader.DoneEvent{})
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
@ -113,10 +65,20 @@ func TestMiner(t *testing.T) {
|
||||||
// An initial FailedEvent should allow mining to stop on a subsequent
|
// An initial FailedEvent should allow mining to stop on a subsequent
|
||||||
// downloader StartEvent.
|
// downloader StartEvent.
|
||||||
func TestMinerDownloaderFirstFails(t *testing.T) {
|
func TestMinerDownloaderFirstFails(t *testing.T) {
|
||||||
miner, mux, cleanup := createMiner(t)
|
t.Parallel()
|
||||||
defer cleanup(false)
|
|
||||||
|
minerBor := NewBorDefaultMiner(t)
|
||||||
|
defer func() {
|
||||||
|
minerBor.Cleanup(false)
|
||||||
|
minerBor.Ctrl.Finish()
|
||||||
|
}()
|
||||||
|
|
||||||
|
miner := minerBor.Miner
|
||||||
|
mux := minerBor.Mux
|
||||||
|
|
||||||
miner.Start(common.HexToAddress("0x12345"))
|
miner.Start(common.HexToAddress("0x12345"))
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
// Start the downloader
|
// Start the downloader
|
||||||
mux.Post(downloader.StartEvent{})
|
mux.Post(downloader.StartEvent{})
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
|
|
@ -145,10 +107,20 @@ func TestMinerDownloaderFirstFails(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMinerStartStopAfterDownloaderEvents(t *testing.T) {
|
func TestMinerStartStopAfterDownloaderEvents(t *testing.T) {
|
||||||
miner, mux, cleanup := createMiner(t)
|
t.Parallel()
|
||||||
defer cleanup(false)
|
|
||||||
|
minerBor := NewBorDefaultMiner(t)
|
||||||
|
defer func() {
|
||||||
|
minerBor.Cleanup(false)
|
||||||
|
minerBor.Ctrl.Finish()
|
||||||
|
}()
|
||||||
|
|
||||||
|
miner := minerBor.Miner
|
||||||
|
mux := minerBor.Mux
|
||||||
|
|
||||||
miner.Start(common.HexToAddress("0x12345"))
|
miner.Start(common.HexToAddress("0x12345"))
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
// Start the downloader
|
// Start the downloader
|
||||||
mux.Post(downloader.StartEvent{})
|
mux.Post(downloader.StartEvent{})
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
|
|
@ -168,58 +140,104 @@ func TestMinerStartStopAfterDownloaderEvents(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStartWhileDownload(t *testing.T) {
|
func TestStartWhileDownload(t *testing.T) {
|
||||||
miner, mux, cleanup := createMiner(t)
|
t.Parallel()
|
||||||
defer cleanup(false)
|
|
||||||
|
minerBor := NewBorDefaultMiner(t)
|
||||||
|
defer func() {
|
||||||
|
minerBor.Cleanup(false)
|
||||||
|
minerBor.Ctrl.Finish()
|
||||||
|
}()
|
||||||
|
|
||||||
|
miner := minerBor.Miner
|
||||||
|
mux := minerBor.Mux
|
||||||
|
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
miner.Start(common.HexToAddress("0x12345"))
|
miner.Start(common.HexToAddress("0x12345"))
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
// Stop the downloader and wait for the update loop to run
|
// Stop the downloader and wait for the update loop to run
|
||||||
mux.Post(downloader.StartEvent{})
|
mux.Post(downloader.StartEvent{})
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
|
|
||||||
// Starting the miner after the downloader should not work
|
// Starting the miner after the downloader should not work
|
||||||
miner.Start(common.HexToAddress("0x12345"))
|
miner.Start(common.HexToAddress("0x12345"))
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStartStopMiner(t *testing.T) {
|
func TestStartStopMiner(t *testing.T) {
|
||||||
miner, _, cleanup := createMiner(t)
|
t.Parallel()
|
||||||
defer cleanup(false)
|
|
||||||
|
minerBor := NewBorDefaultMiner(t)
|
||||||
|
defer func() {
|
||||||
|
minerBor.Cleanup(false)
|
||||||
|
minerBor.Ctrl.Finish()
|
||||||
|
}()
|
||||||
|
|
||||||
|
miner := minerBor.Miner
|
||||||
|
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
miner.Start(common.HexToAddress("0x12345"))
|
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) {
|
func TestCloseMiner(t *testing.T) {
|
||||||
miner, _, cleanup := createMiner(t)
|
t.Parallel()
|
||||||
defer cleanup(true)
|
|
||||||
|
minerBor := NewBorDefaultMiner(t)
|
||||||
|
defer func() {
|
||||||
|
minerBor.Cleanup(true)
|
||||||
|
minerBor.Ctrl.Finish()
|
||||||
|
}()
|
||||||
|
|
||||||
|
miner := minerBor.Miner
|
||||||
|
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
|
|
||||||
miner.Start(common.HexToAddress("0x12345"))
|
miner.Start(common.HexToAddress("0x12345"))
|
||||||
|
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
// Terminate the miner and wait for the update loop to run
|
// Terminate the miner and wait for the update loop to run
|
||||||
miner.Close()
|
miner.Close()
|
||||||
|
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestMinerSetEtherbase checks that etherbase becomes set even if mining isn't
|
// TestMinerSetEtherbase checks that etherbase becomes set even if mining isn't
|
||||||
// possible at the moment
|
// possible at the moment
|
||||||
func TestMinerSetEtherbase(t *testing.T) {
|
func TestMinerSetEtherbase(t *testing.T) {
|
||||||
miner, mux, cleanup := createMiner(t)
|
t.Parallel()
|
||||||
defer cleanup(false)
|
|
||||||
|
minerBor := NewBorDefaultMiner(t)
|
||||||
|
defer func() {
|
||||||
|
minerBor.Cleanup(false)
|
||||||
|
minerBor.Ctrl.Finish()
|
||||||
|
}()
|
||||||
|
|
||||||
|
miner := minerBor.Miner
|
||||||
|
mux := minerBor.Mux
|
||||||
|
|
||||||
// Start with a 'bad' mining address
|
// Start with a 'bad' mining address
|
||||||
miner.Start(common.HexToAddress("0xdead"))
|
miner.Start(common.HexToAddress("0xdead"))
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
// Start the downloader
|
// Start the downloader
|
||||||
mux.Post(downloader.StartEvent{})
|
mux.Post(downloader.StartEvent{})
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
|
|
||||||
// Now user tries to configure proper mining address
|
// Now user tries to configure proper mining address
|
||||||
miner.Start(common.HexToAddress("0x1337"))
|
miner.Start(common.HexToAddress("0x1337"))
|
||||||
|
|
||||||
// Stop the downloader and wait for the update loop to run
|
// Stop the downloader and wait for the update loop to run
|
||||||
mux.Post(downloader.DoneEvent{})
|
mux.Post(downloader.DoneEvent{})
|
||||||
|
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
// The miner should now be using the good address
|
// The miner should now be using the good address
|
||||||
if got, exp := miner.coinbase, common.HexToAddress("0x1337"); got != exp {
|
if got, exp := miner.coinbase, common.HexToAddress("0x1337"); got != exp {
|
||||||
t.Fatalf("Wrong coinbase, got %x expected %x", 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
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Fatalf("Mining() == %t, want %t", state, mining)
|
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++ {
|
for i := 0; i < int(depth); i++ {
|
||||||
pool.Insert(depth, [32]byte{byte(depth), byte(i)})
|
pool.Insert(depth, [32]byte{byte(depth), byte(i)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate that no blocks below the depth allowance are left in
|
// Validate that no blocks below the depth allowance are left in
|
||||||
pool.blocks.Do(func(block interface{}) {
|
pool.blocks.Do(func(block interface{}) {
|
||||||
if block := block.(*unconfirmedBlock); block.index+uint64(limit) <= depth {
|
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++ {
|
for depth := start; depth < start+uint64(limit); depth++ {
|
||||||
pool.Insert(depth, [32]byte{byte(depth)})
|
pool.Insert(depth, [32]byte{byte(depth)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to shift below the limit and ensure no blocks are dropped
|
// Try to shift below the limit and ensure no blocks are dropped
|
||||||
pool.Shift(start + uint64(limit) - 1)
|
pool.Shift(start + uint64(limit) - 1)
|
||||||
if n := pool.blocks.Len(); n != int(limit) {
|
if n := pool.blocks.Len(); n != int(limit) {
|
||||||
t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit)
|
t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to shift half the blocks out and verify remainder
|
// Try to shift half the blocks out and verify remainder
|
||||||
pool.Shift(start + uint64(limit) - 1 + uint64(limit/2))
|
pool.Shift(start + uint64(limit) - 1 + uint64(limit/2))
|
||||||
if n := pool.blocks.Len(); n != int(limit)/2 {
|
if n := pool.blocks.Len(); n != int(limit)/2 {
|
||||||
t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 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
|
// Try to shift all the remaining blocks out and verify emptyness
|
||||||
pool.Shift(start + 2*uint64(limit))
|
pool.Shift(start + 2*uint64(limit))
|
||||||
|
|
||||||
if n := pool.blocks.Len(); n != 0 {
|
if n := pool.blocks.Len(); n != 0 {
|
||||||
t.Errorf("unconfirmed count mismatch: have %d, want %d", 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
|
// Try to shift out from the empty set and make sure it doesn't break
|
||||||
pool.Shift(start + 3*uint64(limit))
|
pool.Shift(start + 3*uint64(limit))
|
||||||
|
|
||||||
if n := pool.blocks.Len(); n != 0 {
|
if n := pool.blocks.Len(); n != 0 {
|
||||||
t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0)
|
t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mapset "github.com/deckarep/golang-set"
|
mapset "github.com/deckarep/golang-set"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
"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())
|
prevF = float64(prev.Nanoseconds())
|
||||||
next float64
|
next float64
|
||||||
)
|
)
|
||||||
|
|
||||||
if inc {
|
if inc {
|
||||||
next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias)
|
next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias)
|
||||||
|
|
||||||
max := float64(maxRecommitInterval.Nanoseconds())
|
max := float64(maxRecommitInterval.Nanoseconds())
|
||||||
if next > max {
|
if next > max {
|
||||||
next = max
|
next = max
|
||||||
|
|
@ -406,6 +409,7 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t
|
||||||
next = min
|
next = min
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return time.Duration(int64(next))
|
return time.Duration(int64(next))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,14 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"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/clique"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
@ -38,6 +43,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -49,43 +55,9 @@ const (
|
||||||
testGas = 144109
|
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() {
|
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)
|
signer := types.LatestSigner(params.TestChainConfig)
|
||||||
|
|
||||||
tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{
|
tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{
|
||||||
ChainID: params.TestChainConfig.ChainID,
|
ChainID: params.TestChainConfig.ChainID,
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
|
|
@ -94,6 +66,7 @@ func init() {
|
||||||
Gas: params.TxGas,
|
Gas: params.TxGas,
|
||||||
GasPrice: big.NewInt(params.InitialBaseFee),
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||||
})
|
})
|
||||||
|
|
||||||
pendingTxs = append(pendingTxs, tx1)
|
pendingTxs = append(pendingTxs, tx1)
|
||||||
|
|
||||||
tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{
|
tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{
|
||||||
|
|
@ -103,6 +76,7 @@ func init() {
|
||||||
Gas: params.TxGas,
|
Gas: params.TxGas,
|
||||||
GasPrice: big.NewInt(params.InitialBaseFee),
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||||
})
|
})
|
||||||
|
|
||||||
newTxs = append(newTxs, tx2)
|
newTxs = append(newTxs, tx2)
|
||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
@ -125,6 +99,12 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
|
||||||
}
|
}
|
||||||
|
|
||||||
switch e := engine.(type) {
|
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:
|
case *clique.Clique:
|
||||||
gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength)
|
gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength)
|
||||||
copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes())
|
copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes())
|
||||||
|
|
@ -135,6 +115,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
|
||||||
default:
|
default:
|
||||||
t.Fatalf("unexpected consensus engine type: %T", engine)
|
t.Fatalf("unexpected consensus engine type: %T", engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
genesis := gspec.MustCommit(db)
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil)
|
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)
|
t.Fatalf("failed to insert origin chain: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parent := genesis
|
parent := genesis
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash())
|
parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) {
|
blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) {
|
||||||
gen.SetCoinbase(testUserAddress)
|
gen.SetCoinbase(testUserAddress)
|
||||||
})
|
})
|
||||||
|
|
@ -174,28 +157,36 @@ func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base
|
||||||
|
|
||||||
func (b *testWorkerBackend) newRandomUncle() *types.Block {
|
func (b *testWorkerBackend) newRandomUncle() *types.Block {
|
||||||
var parent *types.Block
|
var parent *types.Block
|
||||||
|
|
||||||
cur := b.chain.CurrentBlock()
|
cur := b.chain.CurrentBlock()
|
||||||
|
|
||||||
if cur.NumberU64() == 0 {
|
if cur.NumberU64() == 0 {
|
||||||
parent = b.chain.Genesis()
|
parent = b.chain.Genesis()
|
||||||
} else {
|
} else {
|
||||||
parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash())
|
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) {
|
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)
|
var addr = make([]byte, common.AddressLength)
|
||||||
|
|
||||||
rand.Read(addr)
|
rand.Read(addr)
|
||||||
gen.SetCoinbase(common.BytesToAddress(addr))
|
gen.SetCoinbase(common.BytesToAddress(addr))
|
||||||
})
|
})
|
||||||
|
|
||||||
return blocks[0]
|
return blocks[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
|
func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
|
||||||
var tx *types.Transaction
|
var tx *types.Transaction
|
||||||
|
|
||||||
gasPrice := big.NewInt(10 * params.InitialBaseFee)
|
gasPrice := big.NewInt(10 * params.InitialBaseFee)
|
||||||
|
|
||||||
if creation {
|
if creation {
|
||||||
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey)
|
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey)
|
||||||
} else {
|
} else {
|
||||||
tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey)
|
tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,39 +195,85 @@ func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consens
|
||||||
backend.txPool.AddLocals(pendingTxs)
|
backend.txPool.AddLocals(pendingTxs)
|
||||||
w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false)
|
w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false)
|
||||||
w.setEtherbase(testBankAddress)
|
w.setEtherbase(testBankAddress)
|
||||||
|
|
||||||
return w, backend
|
return w, backend
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateBlockAndImportEthash(t *testing.T) {
|
func TestGenerateBlockAndImportEthash(t *testing.T) {
|
||||||
testGenerateBlockAndImport(t, false)
|
t.Parallel()
|
||||||
|
|
||||||
|
testGenerateBlockAndImport(t, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateBlockAndImportClique(t *testing.T) {
|
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 (
|
var (
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
)
|
)
|
||||||
if isClique {
|
|
||||||
chainConfig = params.AllCliqueProtocolChanges
|
if isBor {
|
||||||
chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000}
|
chainConfig = params.BorUnittestChainConfig
|
||||||
engine = clique.New(chainConfig.Clique, db)
|
|
||||||
|
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 {
|
} else {
|
||||||
chainConfig = params.AllEthashProtocolChanges
|
if isClique {
|
||||||
engine = ethash.NewFaker()
|
chainConfig = params.AllCliqueProtocolChanges
|
||||||
|
chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000}
|
||||||
|
engine = clique.New(chainConfig.Clique, db)
|
||||||
|
} else {
|
||||||
|
chainConfig = params.AllEthashProtocolChanges
|
||||||
|
engine = ethash.NewFaker()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer engine.Close()
|
||||||
|
|
||||||
chainConfig.LondonBlock = big.NewInt(0)
|
chainConfig.LondonBlock = big.NewInt(0)
|
||||||
|
|
||||||
w, b := newTestWorker(t, chainConfig, engine, db, 0)
|
w, b := newTestWorker(t, chainConfig, engine, db, 0)
|
||||||
defer w.close()
|
defer w.close()
|
||||||
|
|
||||||
// This test chain imports the mined blocks.
|
// This test chain imports the mined blocks.
|
||||||
db2 := rawdb.NewMemoryDatabase()
|
db2 := rawdb.NewMemoryDatabase()
|
||||||
b.genesis.MustCommit(db2)
|
b.genesis.MustCommit(db2)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
|
|
@ -287,20 +324,25 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens
|
||||||
taskIndex int
|
taskIndex int
|
||||||
taskCh = make(chan struct{}, 2)
|
taskCh = make(chan struct{}, 2)
|
||||||
)
|
)
|
||||||
|
|
||||||
checkEqual := func(t *testing.T, task *task, index int) {
|
checkEqual := func(t *testing.T, task *task, index int) {
|
||||||
// The first empty work without any txs included
|
// The first empty work without any txs included
|
||||||
receiptLen, balance := 0, big.NewInt(0)
|
receiptLen, balance := 0, big.NewInt(0)
|
||||||
|
|
||||||
if index == 1 {
|
if index == 1 {
|
||||||
// The second full work with 1 tx included
|
// The second full work with 1 tx included
|
||||||
receiptLen, balance = 1, big.NewInt(1000)
|
receiptLen, balance = 1, big.NewInt(1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(task.receipts) != receiptLen {
|
if len(task.receipts) != receiptLen {
|
||||||
t.Fatalf("receipt number mismatch: have %d, want %d", 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 {
|
if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 {
|
||||||
t.Fatalf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance)
|
t.Fatalf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.newTaskHook = func(task *task) {
|
w.newTaskHook = func(task *task) {
|
||||||
if task.block.NumberU64() == 1 {
|
if task.block.NumberU64() == 1 {
|
||||||
checkEqual(t, task, taskIndex)
|
checkEqual(t, task, taskIndex)
|
||||||
|
|
@ -308,11 +350,14 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens
|
||||||
taskCh <- struct{}{}
|
taskCh <- struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.skipSealHook = func(task *task) bool { return true }
|
w.skipSealHook = func(task *task) bool { return true }
|
||||||
w.fullTaskHook = func() {
|
w.fullTaskHook = func() {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.start() // Start mining!
|
w.start() // Start mining!
|
||||||
|
|
||||||
for i := 0; i < 2; i += 1 {
|
for i := 0; i < 2; i += 1 {
|
||||||
select {
|
select {
|
||||||
case <-taskCh:
|
case <-taskCh:
|
||||||
|
|
@ -344,16 +389,20 @@ func TestStreamUncleBlock(t *testing.T) {
|
||||||
t.Errorf("uncle hash mismatch: have %s, want %s", have.Hex(), want.Hex())
|
t.Errorf("uncle hash mismatch: have %s, want %s", have.Hex(), want.Hex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
taskCh <- struct{}{}
|
taskCh <- struct{}{}
|
||||||
taskIndex += 1
|
taskIndex += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.skipSealHook = func(task *task) bool {
|
w.skipSealHook = func(task *task) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
w.fullTaskHook = func() {
|
w.fullTaskHook = func() {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.start()
|
w.start()
|
||||||
|
|
||||||
for i := 0; i < 2; i += 1 {
|
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
|
// one has 1 pending tx, the third one has 2 txs
|
||||||
if taskIndex == 2 {
|
if taskIndex == 2 {
|
||||||
receiptLen, balance := 2, big.NewInt(2000)
|
receiptLen, balance := 2, big.NewInt(2000)
|
||||||
|
|
||||||
if len(task.receipts) != receiptLen {
|
if len(task.receipts) != receiptLen {
|
||||||
t.Errorf("receipt number mismatch: have %d, want %d", 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 {
|
if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 {
|
||||||
t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance)
|
t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
taskCh <- struct{}{}
|
taskCh <- struct{}{}
|
||||||
taskIndex += 1
|
taskIndex += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.skipSealHook = func(task *task) bool {
|
w.skipSealHook = func(task *task) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
w.fullTaskHook = func() {
|
w.fullTaskHook = func() {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
@ -423,6 +477,7 @@ func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, en
|
||||||
t.Error("new task timeout")
|
t.Error("new task timeout")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.txPool.AddLocals(newTxs)
|
b.txPool.AddLocals(newTxs)
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
|
@ -459,6 +514,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co
|
||||||
index = 0
|
index = 0
|
||||||
start uint32
|
start uint32
|
||||||
)
|
)
|
||||||
|
|
||||||
w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) {
|
w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) {
|
||||||
// Short circuit if interval checking hasn't started.
|
// Short circuit if interval checking hasn't started.
|
||||||
if atomic.LoadUint32(&start) == 0 {
|
if atomic.LoadUint32(&start) == 0 {
|
||||||
|
|
@ -489,16 +545,19 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co
|
||||||
if recommitInterval != wantRecommitInterval {
|
if recommitInterval != wantRecommitInterval {
|
||||||
t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval)
|
t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, float64(recommitInterval.Nanoseconds()))
|
result = append(result, float64(recommitInterval.Nanoseconds()))
|
||||||
index += 1
|
index += 1
|
||||||
progress <- struct{}{}
|
progress <- struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.start()
|
w.start()
|
||||||
|
|
||||||
time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt
|
time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt
|
||||||
atomic.StoreUint32(&start, 1)
|
atomic.StoreUint32(&start, 1)
|
||||||
|
|
||||||
w.setRecommitInterval(3 * time.Second)
|
w.setRecommitInterval(3 * time.Second)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-progress:
|
case <-progress:
|
||||||
case <-time.NewTimer(time.Second).C:
|
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}
|
w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-progress:
|
case <-progress:
|
||||||
case <-time.NewTimer(time.Second).C:
|
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}
|
w.resubmitAdjustCh <- &intervalAdjust{inc: false}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-progress:
|
case <-progress:
|
||||||
case <-time.NewTimer(time.Second).C:
|
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)
|
w.setRecommitInterval(500 * time.Millisecond)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-progress:
|
case <-progress:
|
||||||
case <-time.NewTimer(time.Second).C:
|
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 {
|
w.skipSealHook = func(task *task) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
w.fullTaskHook = func() {
|
w.fullTaskHook = func() {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp := uint64(time.Now().Unix())
|
timestamp := uint64(time.Now().Unix())
|
||||||
assertBlock := func(block *types.Block, number uint64, coinbase common.Address, random common.Hash) {
|
assertBlock := func(block *types.Block, number uint64, coinbase common.Address, random common.Hash) {
|
||||||
if block.Time() != timestamp {
|
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.
|
// is even smaller than parent block's. It's OK.
|
||||||
t.Logf("Invalid timestamp, want %d, get %d", timestamp, block.Time())
|
t.Logf("Invalid timestamp, want %d, get %d", timestamp, block.Time())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(block.Uncles()) != 0 {
|
if len(block.Uncles()) != 0 {
|
||||||
t.Error("Unexpected uncle block")
|
t.Error("Unexpected uncle block")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, isClique := engine.(*clique.Clique)
|
_, isClique := engine.(*clique.Clique)
|
||||||
if !isClique {
|
if !isClique {
|
||||||
if len(block.Extra()) != 0 {
|
if len(block.Extra()) != 0 {
|
||||||
t.Error("Unexpected extra field")
|
t.Error("Unexpected extra field")
|
||||||
}
|
}
|
||||||
|
|
||||||
if block.Coinbase() != coinbase {
|
if block.Coinbase() != coinbase {
|
||||||
t.Errorf("Unexpected coinbase got %x want %x", 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")
|
t.Error("Unexpected coinbase")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isClique {
|
if !isClique {
|
||||||
if block.MixDigest() != random {
|
if block.MixDigest() != random {
|
||||||
t.Error("Unexpected mix digest")
|
t.Error("Unexpected mix digest")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if block.Nonce() != 0 {
|
if block.Nonce() != 0 {
|
||||||
t.Error("Unexpected block nonce")
|
t.Error("Unexpected block nonce")
|
||||||
}
|
}
|
||||||
|
|
||||||
if block.NumberU64() != number {
|
if block.NumberU64() != number {
|
||||||
t.Errorf("Mismatched block number, want %d got %d", number, block.NumberU64())
|
t.Errorf("Mismatched block number, want %d got %d", number, block.NumberU64())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
parent common.Hash
|
parent common.Hash
|
||||||
coinbase common.Address
|
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
|
// This API should work even when the automatic sealing is not enabled
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random)
|
block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random)
|
||||||
|
|
||||||
if c.expectErr {
|
if c.expectErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Expect error but get 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 {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error %v", err)
|
t.Errorf("Unexpected error %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assertBlock(block, c.expectNumber, c.coinbase, c.random)
|
assertBlock(block, c.expectNumber, c.coinbase, c.random)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This API should work even when the automatic sealing is enabled
|
// This API should work even when the automatic sealing is enabled
|
||||||
w.start()
|
w.start()
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random)
|
block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random)
|
||||||
if c.expectErr {
|
if c.expectErr {
|
||||||
|
|
@ -663,6 +737,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error %v", err)
|
t.Errorf("Unexpected error %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assertBlock(block, c.expectNumber, c.coinbase, c.random)
|
assertBlock(block, c.expectNumber, c.coinbase, c.random)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,9 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Genesis hashes to enforce below configs on.
|
// 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 contains the chain parameters to run a node on the Mumbai test network.
|
||||||
MumbaiChainConfig = &ChainConfig{
|
MumbaiChainConfig = &ChainConfig{
|
||||||
|
|
@ -550,7 +583,9 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin
|
||||||
for k := range field {
|
for k := range field {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
for i := 0; i < len(keys)-1; i++ {
|
for i := 0; i < len(keys)-1; i++ {
|
||||||
valUint, _ := strconv.ParseUint(keys[i], 10, 64)
|
valUint, _ := strconv.ParseUint(keys[i], 10, 64)
|
||||||
valUintNext, _ := strconv.ParseUint(keys[i+1], 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[i]]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return field[keys[len(keys)-1]]
|
return field[keys[len(keys)-1]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,17 @@ package bor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
"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/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
|
@ -22,12 +25,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
spanPath = "bor/span/1"
|
spanPath = "bor/span/1"
|
||||||
clerkPath = "clerk/event-record/list"
|
clerkPath = "clerk/event-record/list"
|
||||||
clerkQueryParams = "from-time=%d&to-time=%d&page=%d&limit=50"
|
clerkQueryParams = "from-time=%d&to-time=%d&page=%d&limit=50"
|
||||||
|
|
@ -38,7 +41,10 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
||||||
chain := init.ethereum.BlockChain()
|
chain := init.ethereum.BlockChain()
|
||||||
engine := init.ethereum.Engine()
|
engine := init.ethereum.Engine()
|
||||||
_bor := engine.(*bor.Bor)
|
_bor := engine.(*bor.Bor)
|
||||||
h, heimdallSpan := getMockedHeimdallClient(t)
|
|
||||||
|
h, heimdallSpan, ctrl := getMockedHeimdallClient(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
|
||||||
_bor.SetHeimdallClient(h)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
db := init.ethereum.ChainDb()
|
db := init.ethereum.ChainDb()
|
||||||
|
|
@ -51,7 +57,6 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
||||||
insertNewBlock(t, chain, block)
|
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
|
validators, err := _bor.GetCurrentValidators(block.Hash(), spanSize) // check validator set at the first block of new span
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
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. Before inserting 1st block of the next sprint, mock heimdall deps
|
||||||
// B.1 Mock /bor/span/1
|
// B.1 Mock /bor/span/1
|
||||||
res, _ := loadSpanFromFile(t)
|
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
|
// B.2 Mock State Sync events
|
||||||
fromID := uint64(1)
|
fromID := uint64(1)
|
||||||
|
|
@ -94,14 +103,12 @@ func TestFetchStateSyncEvents(t *testing.T) {
|
||||||
sample := getSampleEventRecord(t)
|
sample := getSampleEventRecord(t)
|
||||||
sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to
|
sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to
|
||||||
eventRecords := generateFakeStateSyncEvents(sample, eventCount)
|
eventRecords := generateFakeStateSyncEvents(sample, eventCount)
|
||||||
h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
|
|
||||||
|
h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes()
|
||||||
_bor.SetHeimdallClient(h)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||||
insertNewBlock(t, chain, block)
|
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) {
|
func TestFetchStateSyncEvents_2(t *testing.T) {
|
||||||
|
|
@ -112,8 +119,12 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
||||||
|
|
||||||
// Mock /bor/span/1
|
// Mock /bor/span/1
|
||||||
res, _ := loadSpanFromFile(t)
|
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
|
// Mock State Sync events
|
||||||
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
// 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]
|
// First query will be from [id=1, (block-sprint).Time]
|
||||||
// Insert 5 events in this time range
|
// Insert 5 events in this time range
|
||||||
eventRecords := []*bor.EventRecordWithTime{
|
eventRecords := []*clerk.EventRecordWithTime{
|
||||||
buildStateEvent(sample, 1, 3), // id = 1, time = 1
|
buildStateEvent(sample, 1, 3), // id = 1, time = 1
|
||||||
buildStateEvent(sample, 2, 1), // id = 2, time = 3
|
buildStateEvent(sample, 2, 1), // id = 2, time = 3
|
||||||
buildStateEvent(sample, 3, 2), // id = 3, time = 2
|
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, 4, 5), // id = 4, time = 5
|
||||||
buildStateEvent(sample, 6, 4), // id = 6, time = 4
|
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)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
// Insert blocks for 0th sprint
|
// 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)
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||||
insertNewBlock(t, chain, block)
|
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)
|
lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize)
|
||||||
|
|
||||||
// state 6 was not written
|
// state 6 was not written
|
||||||
assert.Equal(t, uint64(4), lastStateID.Uint64())
|
assert.Equal(t, uint64(4), lastStateID.Uint64())
|
||||||
|
|
||||||
//
|
//
|
||||||
fromID = uint64(5)
|
fromID = uint64(5)
|
||||||
to = int64(chain.GetHeaderByNumber(sprintSize).Time)
|
to = int64(chain.GetHeaderByNumber(sprintSize).Time)
|
||||||
eventRecords = []*bor.EventRecordWithTime{
|
|
||||||
|
eventRecords = []*clerk.EventRecordWithTime{
|
||||||
buildStateEvent(sample, 5, 7),
|
buildStateEvent(sample, 5, 7),
|
||||||
buildStateEvent(sample, 6, 4),
|
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++ {
|
for i := sprintSize + 1; i <= spanSize; i++ {
|
||||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||||
insertNewBlock(t, chain, block)
|
insertNewBlock(t, chain, block)
|
||||||
}
|
}
|
||||||
assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
|
|
||||||
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
|
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
|
||||||
assert.Equal(t, uint64(6), lastStateID.Uint64())
|
assert.Equal(t, uint64(6), lastStateID.Uint64())
|
||||||
}
|
}
|
||||||
|
|
@ -169,7 +183,10 @@ func TestOutOfTurnSigning(t *testing.T) {
|
||||||
chain := init.ethereum.BlockChain()
|
chain := init.ethereum.BlockChain()
|
||||||
engine := init.ethereum.Engine()
|
engine := init.ethereum.Engine()
|
||||||
_bor := engine.(*bor.Bor)
|
_bor := engine.(*bor.Bor)
|
||||||
h, _ := getMockedHeimdallClient(t)
|
|
||||||
|
h, _, ctrl := getMockedHeimdallClient(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
|
||||||
_bor.SetHeimdallClient(h)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
db := init.ethereum.ChainDb()
|
db := init.ethereum.ChainDb()
|
||||||
|
|
@ -217,7 +234,10 @@ func TestSignerNotFound(t *testing.T) {
|
||||||
chain := init.ethereum.BlockChain()
|
chain := init.ethereum.BlockChain()
|
||||||
engine := init.ethereum.Engine()
|
engine := init.ethereum.Engine()
|
||||||
_bor := engine.(*bor.Bor)
|
_bor := engine.(*bor.Bor)
|
||||||
h, _ := getMockedHeimdallClient(t)
|
|
||||||
|
h, _, ctrl := getMockedHeimdallClient(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
|
||||||
_bor.SetHeimdallClient(h)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
db := init.ethereum.ChainDb()
|
db := init.ethereum.ChainDb()
|
||||||
|
|
@ -236,47 +256,46 @@ func TestSignerNotFound(t *testing.T) {
|
||||||
bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()})
|
bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMockedHeimdallClient(t *testing.T) (*mocks.IHeimdallClient, *bor.HeimdallSpan) {
|
func getMockedHeimdallClient(t *testing.T) (*mocks.MockIHeimdallClient, *span.HeimdallSpan, *gomock.Controller) {
|
||||||
res, heimdallSpan := loadSpanFromFile(t)
|
ctrl := gomock.NewController(t)
|
||||||
h := &mocks.IHeimdallClient{}
|
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||||
h.On("FetchWithRetry", "bor/span/1", "").Return(res, nil)
|
|
||||||
h.On(
|
_, heimdallSpan := loadSpanFromFile(t)
|
||||||
"FetchStateSyncEvents",
|
|
||||||
mock.AnythingOfType("uint64"),
|
h.EXPECT().Span(uint64(1)).Return(heimdallSpan, nil).AnyTimes()
|
||||||
mock.AnythingOfType("int64")).Return([]*bor.EventRecordWithTime{getSampleEventRecord(t)}, nil)
|
|
||||||
return h, heimdallSpan
|
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 {
|
func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime {
|
||||||
events := make([]*bor.EventRecordWithTime, count)
|
events := make([]*clerk.EventRecordWithTime, count)
|
||||||
event := *sample
|
event := *sample
|
||||||
event.ID = 1
|
event.ID = 1
|
||||||
events[0] = &bor.EventRecordWithTime{}
|
events[0] = &clerk.EventRecordWithTime{}
|
||||||
*events[0] = event
|
*events[0] = event
|
||||||
for i := 1; i < count; i++ {
|
for i := 1; i < count; i++ {
|
||||||
event.ID = uint64(i)
|
event.ID = uint64(i)
|
||||||
event.Time = event.Time.Add(1 * time.Second)
|
event.Time = event.Time.Add(1 * time.Second)
|
||||||
events[i] = &bor.EventRecordWithTime{}
|
events[i] = &clerk.EventRecordWithTime{}
|
||||||
*events[i] = event
|
*events[i] = event
|
||||||
}
|
}
|
||||||
return events
|
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 := *sample
|
||||||
event.ID = id
|
event.ID = id
|
||||||
event.Time = time.Unix(timeStamp, 0)
|
event.Time = time.Unix(timeStamp, 0)
|
||||||
return &event
|
return &event
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSampleEventRecord(t *testing.T) *bor.EventRecordWithTime {
|
func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime {
|
||||||
res := stateSyncEventsPayload(t)
|
eventRecords := stateSyncEventsPayload(t)
|
||||||
var _eventRecords []*bor.EventRecordWithTime
|
eventRecords.Result[0].Time = time.Unix(1, 0)
|
||||||
if err := json.Unmarshal(res.Result, &_eventRecords); err != nil {
|
return eventRecords.Result[0]
|
||||||
t.Fatalf("%s", err)
|
|
||||||
}
|
|
||||||
_eventRecords[0].Time = time.Unix(1, 0)
|
|
||||||
return _eventRecords[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEIP1559Transition tests the following:
|
// TestEIP1559Transition tests the following:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
"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/consensus/misc"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -46,17 +49,23 @@ type initializeData struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
genesisData, err := ioutil.ReadFile("./testdata/genesis.json")
|
genesisData, err := ioutil.ReadFile("./testdata/genesis.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gen := &core.Genesis{}
|
gen := &core.Genesis{}
|
||||||
|
|
||||||
if err := json.Unmarshal(genesisData, gen); err != nil {
|
if err := json.Unmarshal(genesisData, gen); err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ethConf := ð.Config{
|
ethConf := ð.Config{
|
||||||
Genesis: gen,
|
Genesis: gen,
|
||||||
}
|
}
|
||||||
|
|
||||||
ethConf.Genesis.MustCommit(db)
|
ethConf.Genesis.MustCommit(db)
|
||||||
|
|
||||||
ethereum := utils.CreateBorEthereum(ethConf)
|
ethereum := utils.CreateBorEthereum(ethConf)
|
||||||
|
|
@ -65,6 +74,7 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
||||||
}
|
}
|
||||||
|
|
||||||
ethConf.Genesis.MustCommit(ethereum.ChainDb())
|
ethConf.Genesis.MustCommit(ethereum.ChainDb())
|
||||||
|
|
||||||
return &initializeData{
|
return &initializeData{
|
||||||
genesis: gen,
|
genesis: gen,
|
||||||
ethereum: ethereum,
|
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) {
|
func insertNewBlock(t *testing.T, chain *core.BlockChain, block *types.Block) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
if _, err := chain.InsertChain([]*types.Block{block}); err != nil {
|
if _, err := chain.InsertChain([]*types.Block{block}); err != nil {
|
||||||
t.Fatalf("%s", err)
|
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 {
|
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 := block.Header()
|
||||||
header.Number.Add(header.Number, big.NewInt(1))
|
header.Number.Add(header.Number, big.NewInt(1))
|
||||||
number := header.Number.Uint64()
|
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.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig)
|
||||||
header.Extra = make([]byte, 32+65) // vanity + extraSeal
|
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
|
isSpanEnd := (number+1)%spanSize == 0
|
||||||
isSpanStart := number%spanSize == 0
|
isSpanStart := number%spanSize == 0
|
||||||
isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0
|
isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0
|
||||||
|
|
||||||
if isSpanEnd {
|
if isSpanEnd {
|
||||||
_, heimdallSpan := loadSpanFromFile(t)
|
_, heimdallSpan := loadSpanFromFile(t)
|
||||||
// this is to stash the validator bytes in the header
|
// 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 {
|
} else if isSpanStart {
|
||||||
header.Difficulty = new(big.Int).SetInt64(3)
|
header.Difficulty = new(big.Int).SetInt64(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSprintEnd {
|
if isSprintEnd {
|
||||||
sort.Sort(bor.ValidatorsByAddress(currentValidators))
|
sort.Sort(valset.ValidatorsByAddress(currentValidators))
|
||||||
|
|
||||||
validatorBytes := make([]byte, len(currentValidators)*validatorHeaderBytesLength)
|
validatorBytes := make([]byte, len(currentValidators)*validatorHeaderBytesLength)
|
||||||
header.Extra = make([]byte, 32+len(validatorBytes)+65) // vanity + validatorBytes + extraSeal
|
header.Extra = make([]byte, 32+len(validatorBytes)+65) // vanity + validatorBytes + extraSeal
|
||||||
|
|
||||||
for i, val := range currentValidators {
|
for i, val := range currentValidators {
|
||||||
copy(validatorBytes[i*validatorHeaderBytesLength:], val.HeaderBytes())
|
copy(validatorBytes[i*validatorHeaderBytesLength:], val.HeaderBytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(header.Extra[32:], validatorBytes)
|
copy(header.Extra[32:], validatorBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if chain.Config().IsLondon(header.Number) {
|
if chain.Config().IsLondon(header.Number) {
|
||||||
header.BaseFee = misc.CalcBaseFee(chain.Config(), block.Header())
|
header.BaseFee = misc.CalcBaseFee(chain.Config(), block.Header())
|
||||||
|
|
||||||
if !chain.Config().IsLondon(block.Number()) {
|
if !chain.Config().IsLondon(block.Number()) {
|
||||||
parentGasLimit := block.GasLimit() * params.ElasticityMultiplier
|
parentGasLimit := block.GasLimit() * params.ElasticityMultiplier
|
||||||
header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil)
|
_, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sign(t, header, signer, borConfig)
|
sign(t, header, signer, borConfig)
|
||||||
|
|
||||||
return types.NewBlockWithHeader(header)
|
return types.NewBlockWithHeader(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sign(t *testing.T, header *types.Header, signer []byte, c *params.BorConfig) {
|
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)
|
sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header, c)), signer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(header.Extra[len(header.Extra)-extraSeal:], sig)
|
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")
|
stateData, err := ioutil.ReadFile("./testdata/states.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
res := &bor.ResponseWithHeight{}
|
|
||||||
|
res := &heimdall.StateSyncEventsResponse{}
|
||||||
if err := json.Unmarshal(stateData, res); err != nil {
|
if err := json.Unmarshal(stateData, res); err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
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")
|
spanData, err := ioutil.ReadFile("./testdata/span.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
res := &bor.ResponseWithHeight{}
|
|
||||||
|
res := &heimdall.SpanResponse{}
|
||||||
|
|
||||||
if err := json.Unmarshal(spanData, res); err != nil {
|
if err := json.Unmarshal(spanData, res); err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
heimdallSpan := &bor.HeimdallSpan{}
|
return res, &res.Result
|
||||||
if err := json.Unmarshal(res.Result, heimdallSpan); err != nil {
|
|
||||||
t.Fatalf("%s", err)
|
|
||||||
}
|
|
||||||
return res, heimdallSpan
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSignerKey(number uint64) []byte {
|
func getSignerKey(number uint64) []byte {
|
||||||
signerKey := privKey
|
signerKey := privKey
|
||||||
|
|
||||||
isSpanStart := number%spanSize == 0
|
isSpanStart := number%spanSize == 0
|
||||||
if isSpanStart {
|
if isSpanStart {
|
||||||
// validator set in the new span has changed
|
// validator set in the new span has changed
|
||||||
signerKey = privKey2
|
signerKey = privKey2
|
||||||
}
|
}
|
||||||
|
|
||||||
_key, _ := hex.DecodeString(signerKey)
|
_key, _ := hex.DecodeString(signerKey)
|
||||||
|
|
||||||
return _key
|
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
|
package mocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
bor "github.com/ethereum/go-ethereum/consensus/bor"
|
reflect "reflect"
|
||||||
mock "github.com/stretchr/testify/mock"
|
|
||||||
|
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
|
// MockIHeimdallClient is a mock of IHeimdallClient interface.
|
||||||
type IHeimdallClient struct {
|
type MockIHeimdallClient struct {
|
||||||
mock.Mock
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockIHeimdallClientMockRecorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close provides a mock function with given fields:
|
// MockIHeimdallClientMockRecorder is the mock recorder for MockIHeimdallClient.
|
||||||
func (_m *IHeimdallClient) Close() {
|
type MockIHeimdallClientMockRecorder struct {
|
||||||
_m.Called()
|
mock *MockIHeimdallClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch provides a mock function with given fields: path, query
|
// NewMockIHeimdallClient creates a new mock instance.
|
||||||
func (_m *IHeimdallClient) Fetch(path string, query string) (*bor.ResponseWithHeight, error) {
|
func NewMockIHeimdallClient(ctrl *gomock.Controller) *MockIHeimdallClient {
|
||||||
ret := _m.Called(path, query)
|
mock := &MockIHeimdallClient{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockIHeimdallClientMockRecorder{mock}
|
||||||
var r0 *bor.ResponseWithHeight
|
return mock
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchStateSyncEvents provides a mock function with given fields: fromID, to
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
func (_m *IHeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*bor.EventRecordWithTime, error) {
|
func (m *MockIHeimdallClient) EXPECT() *MockIHeimdallClientMockRecorder {
|
||||||
ret := _m.Called(fromID, to)
|
return m.recorder
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var r1 error
|
|
||||||
if rf, ok := ret.Get(1).(func(uint64, int64) error); ok {
|
|
||||||
r1 = rf(fromID, to)
|
|
||||||
} else {
|
|
||||||
r1 = ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0, r1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchWithRetry provides a mock function with given fields: path, query
|
// Close mocks base method.
|
||||||
func (_m *IHeimdallClient) FetchWithRetry(path string, query string) (*bor.ResponseWithHeight, error) {
|
func (m *MockIHeimdallClient) Close() {
|
||||||
ret := _m.Called(path, query)
|
m.ctrl.T.Helper()
|
||||||
|
m.ctrl.Call(m, "Close")
|
||||||
var r0 *bor.ResponseWithHeight
|
}
|
||||||
if rf, ok := ret.Get(0).(func(string, string) *bor.ResponseWithHeight); ok {
|
|
||||||
r0 = rf(path, query)
|
// Close indicates an expected call of Close.
|
||||||
} else {
|
func (mr *MockIHeimdallClientMockRecorder) Close() *gomock.Call {
|
||||||
if ret.Get(0) != nil {
|
mr.mock.ctrl.T.Helper()
|
||||||
r0 = ret.Get(0).(*bor.ResponseWithHeight)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIHeimdallClient)(nil).Close))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Span mocks base method.
|
||||||
var r1 error
|
func (m *MockIHeimdallClient) Span(arg0 uint64) (*span.HeimdallSpan, error) {
|
||||||
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
m.ctrl.T.Helper()
|
||||||
r1 = rf(path, query)
|
ret := m.ctrl.Call(m, "Span", arg0)
|
||||||
} else {
|
ret0, _ := ret[0].(*span.HeimdallSpan)
|
||||||
r1 = ret.Error(1)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"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
|
// hasher is a type used for the trie Hash operation. A hasher has some
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue