mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
Reciept e2e test (#431)
* initial * fixed tests * eip155 tests * progress * fix * fix TestFetchStateSyncEvents* * debug * fixed with updated list of validators * fix * a bit more stable * optimize allocations * linters * fix vals copy * a bit of refactoring * update TestGetTransactionReceiptsByBlock * remove logs from TestGetTransactionReceiptsByBlock in favour of checks * comments * Linters * linters * fixes after merge * fixes after merge * fixes after merge * fixes after merge * fail fast Co-authored-by: Evgeny Danienko <6655321@bk.ru>
This commit is contained in:
parent
1147994c65
commit
7b25997830
26 changed files with 820 additions and 281 deletions
|
|
@ -5,11 +5,12 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -606,7 +606,7 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
|
|||
return err
|
||||
}
|
||||
|
||||
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
||||
if !snap.ValidatorSet.HasAddress(signer) {
|
||||
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
|
||||
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
|
||||
}
|
||||
|
|
@ -623,13 +623,13 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
|
|||
parent = chain.GetHeader(header.ParentHash, number-1)
|
||||
}
|
||||
|
||||
if parent != nil && header.Time < parent.Time+CalcProducerDelay(number, succession, c.config) {
|
||||
if IsBlockOnTime(parent, header, number, succession, c.config) {
|
||||
return &BlockTooSoonError{number, succession}
|
||||
}
|
||||
|
||||
// Ensure that the difficulty corresponds to the turn-ness of the signer
|
||||
if !c.fakeDiff {
|
||||
difficulty := snap.Difficulty(signer)
|
||||
difficulty := Difficulty(snap.ValidatorSet, signer)
|
||||
if header.Difficulty.Uint64() != difficulty {
|
||||
return &WrongDifficultyError{number, difficulty, header.Difficulty.Uint64(), signer.Bytes()}
|
||||
}
|
||||
|
|
@ -638,6 +638,10 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
|
|||
return nil
|
||||
}
|
||||
|
||||
func IsBlockOnTime(parent *types.Header, header *types.Header, number uint64, succession int, cfg *params.BorConfig) bool {
|
||||
return parent != nil && header.Time < parent.Time+CalcProducerDelay(number, succession, cfg)
|
||||
}
|
||||
|
||||
// Prepare implements consensus.Engine, preparing all the consensus fields of the
|
||||
// header for running the transactions on top.
|
||||
func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
|
|
@ -653,7 +657,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
|
|||
}
|
||||
|
||||
// Set the correct difficulty
|
||||
header.Difficulty = new(big.Int).SetUint64(snap.Difficulty(c.signer))
|
||||
header.Difficulty = new(big.Int).SetUint64(Difficulty(snap.ValidatorSet, c.signer))
|
||||
|
||||
// Ensure the extra data has all it's components
|
||||
if len(header.Extra) < extraVanity {
|
||||
|
|
@ -716,7 +720,7 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
|
|||
|
||||
headerNumber := header.Number.Uint64()
|
||||
|
||||
if headerNumber%c.config.Sprint == 0 {
|
||||
if IsSprintStart(headerNumber, c.config.Sprint) {
|
||||
ctx := context.Background()
|
||||
|
||||
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
||||
|
|
@ -727,7 +731,7 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
|
|||
}
|
||||
|
||||
if c.HeimdallClient != nil {
|
||||
// commit statees
|
||||
// commit states
|
||||
stateSyncData, err = c.CommitStates(ctx, state, header, cx)
|
||||
if err != nil {
|
||||
log.Error("Error while committing states", "error", err)
|
||||
|
|
@ -790,7 +794,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
|
|||
|
||||
headerNumber := header.Number.Uint64()
|
||||
|
||||
if headerNumber%c.config.Sprint == 0 {
|
||||
if IsSprintStart(headerNumber, c.config.Sprint) {
|
||||
ctx := context.Background()
|
||||
|
||||
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
||||
|
|
@ -867,7 +871,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
|||
}
|
||||
|
||||
// Bail out if we're unauthorized to sign a block
|
||||
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
||||
if !snap.ValidatorSet.HasAddress(signer) {
|
||||
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
|
||||
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
|
||||
}
|
||||
|
|
@ -945,7 +949,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, _ uint64, parent
|
|||
return nil
|
||||
}
|
||||
|
||||
return new(big.Int).SetUint64(snap.Difficulty(c.signer))
|
||||
return new(big.Int).SetUint64(Difficulty(snap.ValidatorSet, c.signer))
|
||||
}
|
||||
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
|
|
@ -1059,7 +1063,6 @@ func (c *Bor) CommitStates(
|
|||
header *types.Header,
|
||||
chain statefull.ChainContext,
|
||||
) ([]*types.StateSyncData, error) {
|
||||
stateSyncs := make([]*types.StateSyncData, 0)
|
||||
number := header.Number.Uint64()
|
||||
|
||||
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
|
||||
|
|
@ -1087,15 +1090,17 @@ func (c *Bor) CommitStates(
|
|||
}
|
||||
|
||||
totalGas := 0 /// limit on gas for state sync per block
|
||||
|
||||
chainID := c.chainConfig.ChainID.String()
|
||||
stateSyncs := make([]*types.StateSyncData, len(eventRecords))
|
||||
|
||||
var gasUsed uint64
|
||||
|
||||
for _, eventRecord := range eventRecords {
|
||||
if eventRecord.ID <= lastStateID {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
|
||||
if err = validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
|
||||
log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error())
|
||||
break
|
||||
}
|
||||
|
|
@ -1109,7 +1114,10 @@ func (c *Bor) CommitStates(
|
|||
|
||||
stateSyncs = append(stateSyncs, &stateData)
|
||||
|
||||
gasUsed, err := c.GenesisContractsClient.CommitState(eventRecord, state, header, chain)
|
||||
// we expect that this call MUST emit an event, otherwise we wouldn't make a receipt
|
||||
// if the receiver address is not a contract then we'll skip the most of the execution and emitting an event as well
|
||||
// https://github.com/maticnetwork/genesis-contracts/blob/master/contracts/StateReceiver.sol#L27
|
||||
gasUsed, err = c.GenesisContractsClient.CommitState(eventRecord, state, header, chain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
|
|
@ -55,11 +55,11 @@ func TestGenesisContractChange(t *testing.T) {
|
|||
genesis := genspec.MustCommit(db)
|
||||
|
||||
statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
config := params.ChainConfig{}
|
||||
chain, err := core.NewBlockChain(db, nil, &config, b, vm.Config{}, nil, nil)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
addBlock := func(root common.Hash, num int64) (common.Hash, *state.StateDB) {
|
||||
h := &types.Header{
|
||||
|
|
@ -70,37 +70,37 @@ func TestGenesisContractChange(t *testing.T) {
|
|||
|
||||
// write state to database
|
||||
root, err := statedb.Commit(false)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil))
|
||||
|
||||
statedb, err := state.New(h.Root, state.NewDatabase(db), nil)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
return root, statedb
|
||||
}
|
||||
|
||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
|
||||
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
|
||||
|
||||
root := genesis.Root()
|
||||
|
||||
// code does not change
|
||||
root, statedb = addBlock(root, 1)
|
||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
|
||||
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
|
||||
|
||||
// code changes 1st time
|
||||
root, statedb = addBlock(root, 2)
|
||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
|
||||
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
|
||||
|
||||
// code same as 1st change
|
||||
root, statedb = addBlock(root, 3)
|
||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
|
||||
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
|
||||
|
||||
// code changes 2nd time
|
||||
_, statedb = addBlock(root, 4)
|
||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x3})
|
||||
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x3})
|
||||
|
||||
// make sure balance change DOES NOT take effect
|
||||
assert.Equal(t, statedb.GetBalance(addr0), big.NewInt(0))
|
||||
require.Equal(t, statedb.GetBalance(addr0), big.NewInt(0))
|
||||
}
|
||||
|
||||
func TestEncodeSigHeaderJaipur(t *testing.T) {
|
||||
|
|
@ -124,19 +124,19 @@ func TestEncodeSigHeaderJaipur(t *testing.T) {
|
|||
|
||||
// Jaipur NOT enabled and BaseFee not set
|
||||
hash := SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
||||
require.Equal(t, hash, hashWithoutBaseFee)
|
||||
|
||||
// Jaipur enabled (Jaipur=0) and BaseFee not set
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 0})
|
||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
||||
require.Equal(t, hash, hashWithoutBaseFee)
|
||||
|
||||
h.BaseFee = big.NewInt(2)
|
||||
|
||||
// Jaipur enabled (Jaipur=Header block) and BaseFee set
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 1})
|
||||
assert.Equal(t, hash, hashWithBaseFee)
|
||||
require.Equal(t, hash, hashWithBaseFee)
|
||||
|
||||
// Jaipur NOT enabled and BaseFee set
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
||||
require.Equal(t, hash, hashWithoutBaseFee)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,8 @@ func (gc *GenesisContractsClient) CommitState(
|
|||
|
||||
func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) {
|
||||
blockNr := rpc.BlockNumber(snapshotNumber)
|
||||
method := "lastStateId"
|
||||
|
||||
const method = "lastStateId"
|
||||
|
||||
data, err := gc.stateReceiverABI.Pack(method)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
|
@ -251,7 +251,7 @@ func internalFetch(ctx context.Context, client http.Client, u *url.URL) ([]byte,
|
|||
}
|
||||
|
||||
// get response
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ func (c *ChainSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Has
|
|||
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||
|
||||
// method
|
||||
method := "getCurrentSpan"
|
||||
const method = "getCurrentSpan"
|
||||
|
||||
data, err := c.validatorSet.Pack(method)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ func convertTo32(input []byte) (output [32]byte) {
|
|||
return
|
||||
}
|
||||
|
||||
func convert(input []([32]byte)) [][]byte {
|
||||
func convert(input [][32]byte) [][]byte {
|
||||
output := make([][]byte, 0, len(input))
|
||||
|
||||
for _, in := range input {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
|||
}
|
||||
|
||||
// check if signer is in validator set
|
||||
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
||||
if !snap.ValidatorSet.HasAddress(signer) {
|
||||
return nil, &UnauthorizedSignerError{number, signer.Bytes()}
|
||||
}
|
||||
|
||||
|
|
@ -201,18 +201,18 @@ func (s *Snapshot) signers() []common.Address {
|
|||
}
|
||||
|
||||
// Difficulty returns the difficulty for a particular signer at the current snapshot number
|
||||
func (s *Snapshot) Difficulty(signer common.Address) uint64 {
|
||||
func Difficulty(validatorSet *valset.ValidatorSet, signer common.Address) uint64 {
|
||||
// if signer is empty
|
||||
if signer == (common.Address{}) {
|
||||
return 1
|
||||
}
|
||||
|
||||
validators := s.ValidatorSet.Validators
|
||||
proposer := s.ValidatorSet.GetProposer().Address
|
||||
validators := validatorSet.Validators
|
||||
proposer := validatorSet.GetProposer().Address
|
||||
totalValidators := len(validators)
|
||||
|
||||
proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
|
||||
signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
|
||||
proposerIndex, _ := validatorSet.GetByAddress(proposer)
|
||||
signerIndex, _ := validatorSet.GetByAddress(signer)
|
||||
|
||||
// temp index
|
||||
tempIndex := signerIndex
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"pgregory.net/rapid"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -34,7 +34,7 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
|||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 0, successionNumber)
|
||||
require.Equal(t, 0, successionNumber)
|
||||
}
|
||||
|
||||
func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
||||
|
|
@ -60,7 +60,7 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
|||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, signerIndex-proposerIndex, successionNumber)
|
||||
require.Equal(t, signerIndex-proposerIndex, successionNumber)
|
||||
}
|
||||
|
||||
func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
||||
|
|
@ -82,7 +82,7 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
|||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
|
||||
require.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
|
||||
}
|
||||
|
||||
func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
||||
|
|
@ -93,6 +93,8 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
|||
ValidatorSet: valset.NewValidatorSet(validators),
|
||||
}
|
||||
|
||||
require.Len(t, snap.ValidatorSet.Validators, numVals)
|
||||
|
||||
dummyProposerAddress := randomAddress()
|
||||
snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress}
|
||||
|
||||
|
|
@ -100,11 +102,11 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
|||
signer := snap.ValidatorSet.Validators[3].Address
|
||||
|
||||
_, err := snap.GetSignerSuccessionNumber(signer)
|
||||
assert.NotNil(t, err)
|
||||
require.NotNil(t, err)
|
||||
|
||||
e, ok := err.(*UnauthorizedProposerError)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
|
||||
}
|
||||
|
||||
func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
||||
|
|
@ -116,10 +118,10 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
|||
}
|
||||
dummySignerAddress := randomAddress()
|
||||
_, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
|
||||
assert.NotNil(t, err)
|
||||
require.NotNil(t, err)
|
||||
e, ok := err.(*UnauthorizedSignerError)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, dummySignerAddress.Bytes(), e.Signer)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, dummySignerAddress.Bytes(), e.Signer)
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
|
|
|
|||
|
|
@ -47,21 +47,26 @@ func (v *Validator) Cmp(other *Validator) *Validator {
|
|||
return v
|
||||
}
|
||||
|
||||
// nolint:nestif
|
||||
if v.ProposerPriority > other.ProposerPriority {
|
||||
return v
|
||||
} else if v.ProposerPriority < other.ProposerPriority {
|
||||
return other
|
||||
} else {
|
||||
result := bytes.Compare(v.Address.Bytes(), other.Address.Bytes())
|
||||
if result < 0 {
|
||||
return v
|
||||
} else if result > 0 {
|
||||
return other
|
||||
} else {
|
||||
panic("Cannot compare identical validators")
|
||||
}
|
||||
}
|
||||
|
||||
if v.ProposerPriority < other.ProposerPriority {
|
||||
return other
|
||||
}
|
||||
|
||||
result := bytes.Compare(v.Address.Bytes(), other.Address.Bytes())
|
||||
|
||||
if result == 0 {
|
||||
panic("Cannot compare identical validators")
|
||||
}
|
||||
|
||||
if result < 0 {
|
||||
return v
|
||||
}
|
||||
|
||||
// result > 0
|
||||
return other
|
||||
}
|
||||
|
||||
func (v *Validator) String() string {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ type ValidatorSet struct {
|
|||
|
||||
// cached (unexported)
|
||||
totalVotingPower int64
|
||||
validatorsMap map[common.Address]int // address -> index
|
||||
}
|
||||
|
||||
// NewValidatorSet initializes a ValidatorSet by copying over the
|
||||
|
|
@ -54,7 +55,7 @@ type ValidatorSet struct {
|
|||
// The addresses of validators in `valz` must be unique otherwise the
|
||||
// function panics.
|
||||
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
||||
vals := &ValidatorSet{}
|
||||
vals := &ValidatorSet{validatorsMap: make(map[common.Address]int)}
|
||||
|
||||
err := vals.updateWithChangeSet(valz, false)
|
||||
if err != nil {
|
||||
|
|
@ -232,30 +233,34 @@ func validatorListCopy(valsList []*Validator) []*Validator {
|
|||
|
||||
// Copy each validator into a new ValidatorSet.
|
||||
func (vals *ValidatorSet) Copy() *ValidatorSet {
|
||||
valCopy := validatorListCopy(vals.Validators)
|
||||
validatorsMap := make(map[common.Address]int, len(vals.Validators))
|
||||
|
||||
for i, val := range valCopy {
|
||||
validatorsMap[val.Address] = i
|
||||
}
|
||||
|
||||
return &ValidatorSet{
|
||||
Validators: validatorListCopy(vals.Validators),
|
||||
Proposer: vals.Proposer,
|
||||
totalVotingPower: vals.totalVotingPower,
|
||||
validatorsMap: validatorsMap,
|
||||
}
|
||||
}
|
||||
|
||||
// HasAddress returns true if address given is in the validator set, false -
|
||||
// otherwise.
|
||||
func (vals *ValidatorSet) HasAddress(address []byte) bool {
|
||||
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
||||
return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0
|
||||
})
|
||||
func (vals *ValidatorSet) HasAddress(address common.Address) bool {
|
||||
_, ok := vals.validatorsMap[address]
|
||||
|
||||
return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address)
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetByAddress returns an index of the validator with address and validator
|
||||
// itself if found. Otherwise, -1 and nil are returned.
|
||||
func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *Validator) {
|
||||
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
||||
return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0
|
||||
})
|
||||
if idx < len(vals.Validators) && vals.Validators[idx].Address == address {
|
||||
idx, ok := vals.validatorsMap[address]
|
||||
if ok {
|
||||
return idx, vals.Validators[idx].Copy()
|
||||
}
|
||||
|
||||
|
|
@ -265,14 +270,14 @@ func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *
|
|||
// GetByIndex returns the validator's address and validator itself by index.
|
||||
// It returns nil values if index is less than 0 or greater or equal to
|
||||
// len(ValidatorSet.Validators).
|
||||
func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) {
|
||||
func (vals *ValidatorSet) GetByIndex(index int) (address common.Address, val *Validator) {
|
||||
if index < 0 || index >= len(vals.Validators) {
|
||||
return nil, nil
|
||||
return common.Address{}, nil
|
||||
}
|
||||
|
||||
val = vals.Validators[index]
|
||||
|
||||
return val.Address.Bytes(), val.Copy()
|
||||
return val.Address, val.Copy()
|
||||
}
|
||||
|
||||
// Size returns the length of the validator set.
|
||||
|
|
@ -328,7 +333,7 @@ func (vals *ValidatorSet) GetProposer() (proposer *Validator) {
|
|||
func (vals *ValidatorSet) findProposer() *Validator {
|
||||
var proposer *Validator
|
||||
for _, val := range vals.Validators {
|
||||
if proposer == nil || !bytes.Equal(val.Address.Bytes(), proposer.Address.Bytes()) {
|
||||
if proposer == nil || val.Address != proposer.Address {
|
||||
proposer = proposer.Cmp(val)
|
||||
}
|
||||
}
|
||||
|
|
@ -371,14 +376,19 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
|
|||
changes := validatorListCopy(origChanges)
|
||||
sort.Sort(ValidatorsByAddress(changes))
|
||||
|
||||
removals = make([]*Validator, 0, len(changes))
|
||||
updates = make([]*Validator, 0, len(changes))
|
||||
sliceCap := len(changes) / 2
|
||||
if sliceCap == 0 {
|
||||
sliceCap = 1
|
||||
}
|
||||
|
||||
removals = make([]*Validator, 0, sliceCap)
|
||||
updates = make([]*Validator, 0, sliceCap)
|
||||
|
||||
var prevAddr common.Address
|
||||
|
||||
// Scan changes by address and append valid validators to updates or removals lists.
|
||||
for _, valUpdate := range changes {
|
||||
if bytes.Equal(valUpdate.Address.Bytes(), prevAddr.Bytes()) {
|
||||
if valUpdate.Address == prevAddr {
|
||||
err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -489,10 +499,11 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
|||
} else {
|
||||
// Apply add or update.
|
||||
merged[i] = updates[0]
|
||||
if bytes.Equal(existing[0].Address.Bytes(), updates[0].Address.Bytes()) {
|
||||
if existing[0].Address == updates[0].Address {
|
||||
// Validator is present in both, advance existing.
|
||||
existing = existing[1:]
|
||||
}
|
||||
|
||||
updates = updates[1:]
|
||||
}
|
||||
i++
|
||||
|
|
@ -503,6 +514,7 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
|||
merged[i] = existing[j]
|
||||
i++
|
||||
}
|
||||
|
||||
// OR add updates which are left.
|
||||
for j := 0; j < len(updates); j++ {
|
||||
merged[i] = updates[j]
|
||||
|
|
@ -541,7 +553,7 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
|||
|
||||
// Loop over deletes until we removed all of them.
|
||||
for len(deletes) > 0 {
|
||||
if bytes.Equal(existing[0].Address.Bytes(), deletes[0].Address.Bytes()) {
|
||||
if existing[0].Address == deletes[0].Address {
|
||||
deletes = deletes[1:]
|
||||
} else { // Leave it in the resulting slice.
|
||||
merged[i] = existing[0]
|
||||
|
|
@ -599,8 +611,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
|
|||
computeNewPriorities(updates, vals, updatedTotalVotingPower)
|
||||
|
||||
// Apply updates and removals.
|
||||
vals.applyUpdates(updates)
|
||||
vals.applyRemovals(deletes)
|
||||
vals.updateValidators(updates, deletes)
|
||||
|
||||
if err := vals.UpdateTotalVotingPower(); err != nil {
|
||||
return err
|
||||
|
|
@ -613,6 +624,17 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
|
|||
return nil
|
||||
}
|
||||
|
||||
func (vals *ValidatorSet) updateValidators(updates []*Validator, deletes []*Validator) {
|
||||
vals.applyUpdates(updates)
|
||||
vals.applyRemovals(deletes)
|
||||
|
||||
vals.validatorsMap = make(map[common.Address]int, len(vals.Validators))
|
||||
|
||||
for i, val := range vals.Validators {
|
||||
vals.validatorsMap[val.Address] = i
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateWithChangeSet attempts to update the validator set with 'changes'.
|
||||
// It performs the following steps:
|
||||
// - validates the changes making sure there are no duplicates and splits them in updates and deletes
|
||||
|
|
@ -661,7 +683,7 @@ func (vals *ValidatorSet) StringIndented(indent string) string {
|
|||
return "nil-ValidatorSet"
|
||||
}
|
||||
|
||||
var valStrings []string
|
||||
valStrings := make([]string, 0, len(vals.Validators))
|
||||
|
||||
vals.Iterate(func(index int, val *Validator) bool {
|
||||
valStrings = append(valStrings, val.String())
|
||||
|
|
|
|||
|
|
@ -3,14 +3,16 @@ package valset
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gotest.tools/assert"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func NewValidatorFromKey(key string, votingPower int64) *Validator {
|
||||
privKey, _ := crypto.HexToECDSA(key)
|
||||
|
||||
return NewValidator(crypto.PubkeyToAddress(privKey.PublicKey), votingPower)
|
||||
}
|
||||
|
||||
|
|
@ -50,7 +52,7 @@ func TestIncrementProposerPriority(t *testing.T) {
|
|||
for i := 0; i < 10; i++ {
|
||||
valSet.IncrementProposerPriority(1)
|
||||
|
||||
assert.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||
require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||
}
|
||||
|
||||
// Validator set length = 2
|
||||
|
|
@ -61,7 +63,7 @@ func TestIncrementProposerPriority(t *testing.T) {
|
|||
for i := 0; i < 10; i++ {
|
||||
valSet.IncrementProposerPriority(1)
|
||||
|
||||
assert.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||
require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||
}
|
||||
|
||||
// Validator set length = 3
|
||||
|
|
@ -72,7 +74,7 @@ func TestIncrementProposerPriority(t *testing.T) {
|
|||
for i := 0; i < 10; i++ {
|
||||
valSet.IncrementProposerPriority(1)
|
||||
|
||||
assert.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||
require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||
}
|
||||
|
||||
// Validator set length = 4
|
||||
|
|
@ -83,7 +85,7 @@ func TestIncrementProposerPriority(t *testing.T) {
|
|||
for i := 0; i < 10; i++ {
|
||||
valSet.IncrementProposerPriority(1)
|
||||
|
||||
assert.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||
require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +101,7 @@ func TestRescalePriorities(t *testing.T) {
|
|||
|
||||
expectedPriorities := []int64{0}
|
||||
for i, val := range valSet.Validators {
|
||||
assert.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||
require.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||
}
|
||||
|
||||
// Validator set length = 2
|
||||
|
|
@ -110,7 +112,7 @@ func TestRescalePriorities(t *testing.T) {
|
|||
|
||||
expectedPriorities = []int64{50, -50}
|
||||
for i, val := range valSet.Validators {
|
||||
assert.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||
require.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||
}
|
||||
|
||||
// Validator set length = 3
|
||||
|
|
@ -121,7 +123,7 @@ func TestRescalePriorities(t *testing.T) {
|
|||
|
||||
expectedPriorities = []int64{-17, 5, 11}
|
||||
for i, val := range valSet.Validators {
|
||||
assert.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||
require.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||
}
|
||||
|
||||
// Validator set length = 4
|
||||
|
|
@ -132,7 +134,7 @@ func TestRescalePriorities(t *testing.T) {
|
|||
|
||||
expectedPriorities = []int64{-6, 3, 1, 2}
|
||||
for i, val := range valSet.Validators {
|
||||
assert.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||
require.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -148,18 +150,18 @@ func TestGetValidatorByAddressAndIndex(t *testing.T) {
|
|||
|
||||
assert.DeepEqual(t, val, valByIndex)
|
||||
assert.DeepEqual(t, val, valByAddress)
|
||||
assert.DeepEqual(t, val.Address, common.BytesToAddress(addr))
|
||||
assert.DeepEqual(t, val.Address, addr)
|
||||
}
|
||||
|
||||
tempAddress := common.HexToAddress("0x12345")
|
||||
|
||||
// Negative Testcase
|
||||
idx, _ := valSet.GetByAddress(tempAddress)
|
||||
assert.Equal(t, idx, -1)
|
||||
require.Equal(t, idx, -1)
|
||||
|
||||
// checking for validator index out of range
|
||||
addr, _ := valSet.GetByIndex(100)
|
||||
assert.Equal(t, common.BytesToAddress(addr), common.Address{})
|
||||
require.Equal(t, addr, common.Address{})
|
||||
}
|
||||
|
||||
func TestUpdateWithChangeSet(t *testing.T) {
|
||||
|
|
@ -169,28 +171,29 @@ func TestUpdateWithChangeSet(t *testing.T) {
|
|||
valSet := NewValidatorSet(vals[:4])
|
||||
|
||||
// halved the power of vals[2] and doubled the power of vals[3]
|
||||
val2 := NewValidatorFromKey("c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd7", 150) // signer2
|
||||
val3 := NewValidatorFromKey("c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd6", 800) // signer3
|
||||
vals[2].VotingPower = 150
|
||||
vals[3].VotingPower = 800
|
||||
|
||||
// Adding new temp validator in the set
|
||||
tempSigner := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd5"
|
||||
const tempSigner = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd5"
|
||||
|
||||
tempVal := NewValidatorFromKey(tempSigner, 250)
|
||||
|
||||
// check totalVotingPower before updating validator set
|
||||
assert.Equal(t, int64(1000), valSet.TotalVotingPower())
|
||||
require.Equal(t, int64(1000), valSet.TotalVotingPower())
|
||||
|
||||
err := valSet.UpdateWithChangeSet([]*Validator{val2, val3, tempVal})
|
||||
assert.NilError(t, err)
|
||||
err := valSet.UpdateWithChangeSet([]*Validator{vals[2], vals[3], tempVal})
|
||||
require.NoError(t, err)
|
||||
|
||||
// check totalVotingPower after updating validator set
|
||||
assert.Equal(t, int64(1500), valSet.TotalVotingPower())
|
||||
require.Equal(t, int64(1500), valSet.TotalVotingPower())
|
||||
|
||||
_, updatedVal2 := valSet.GetByAddress(vals[2].Address)
|
||||
assert.Equal(t, int64(150), updatedVal2.VotingPower)
|
||||
require.Equal(t, int64(150), updatedVal2.VotingPower)
|
||||
|
||||
_, updatedVal3 := valSet.GetByAddress(vals[3].Address)
|
||||
assert.Equal(t, int64(800), updatedVal3.VotingPower)
|
||||
require.Equal(t, int64(800), updatedVal3.VotingPower)
|
||||
|
||||
_, updatedTempVal := valSet.GetByAddress(tempVal.Address)
|
||||
assert.Equal(t, int64(250), updatedTempVal.VotingPower)
|
||||
require.Equal(t, int64(250), updatedTempVal.VotingPower)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ var (
|
|||
getDerivedBorTxHash = types.GetDerivedBorTxHash
|
||||
|
||||
// borTxLookupPrefix + hash -> transaction/receipt lookup metadata
|
||||
borTxLookupPrefix = []byte("matic-bor-tx-lookup-")
|
||||
borTxLookupPrefix = []byte(borTxLookupPrefixStr)
|
||||
)
|
||||
|
||||
const (
|
||||
borTxLookupPrefixStr = "matic-bor-tx-lookup-"
|
||||
|
||||
// freezerBorReceiptTable indicates the name of the freezer bor receipts table.
|
||||
freezerBorReceiptTable = "matic-bor-receipts"
|
||||
|
|
|
|||
|
|
@ -601,8 +601,8 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
|
|||
// CreateAccount is called during the EVM CREATE operation. The situation might arise that
|
||||
// a contract does the following:
|
||||
//
|
||||
// 1. sends funds to sha(account ++ (nonce + 1))
|
||||
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
|
||||
// 1. sends funds to sha(account ++ (nonce + 1))
|
||||
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
|
||||
//
|
||||
// Carrying over the balance ensures that Ether doesn't disappear.
|
||||
func (s *StateDB) CreateAccount(addr common.Address) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"math/big"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -28,11 +28,11 @@ func TestWhitelistCheckpoint(t *testing.T) {
|
|||
for i := 0; i < 10; i++ {
|
||||
s.enqueueCheckpointWhitelist(uint64(i), common.Hash{})
|
||||
}
|
||||
assert.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
||||
require.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
||||
|
||||
s.enqueueCheckpointWhitelist(11, common.Hash{})
|
||||
s.dequeueCheckpointWhitelist()
|
||||
assert.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
||||
require.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
||||
}
|
||||
|
||||
// TestIsValidChain checks che IsValidChain function in isolation
|
||||
|
|
@ -44,14 +44,14 @@ func TestIsValidChain(t *testing.T) {
|
|||
|
||||
// case1: no checkpoint whitelist, should consider the chain as valid
|
||||
res, err := s.IsValidChain(nil, nil)
|
||||
assert.NilError(t, err, "expected no error")
|
||||
assert.Equal(t, res, true, "expected chain to be valid")
|
||||
require.NoError(t, err, "expected no error")
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
|
||||
// add checkpoint entries and mock fetchHeadersByNumber function
|
||||
s.ProcessCheckpoint(uint64(0), common.Hash{})
|
||||
s.ProcessCheckpoint(uint64(1), common.Hash{})
|
||||
|
||||
assert.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
||||
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
||||
|
||||
// create a false function, returning absolutely nothing
|
||||
falseFetchHeadersByNumber := func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error) {
|
||||
|
|
@ -69,7 +69,7 @@ func TestIsValidChain(t *testing.T) {
|
|||
t.Fatalf("expected error ErrNoRemoteCheckoint, got %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, res, false, "expected chain to be invalid")
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
|
||||
// case3: correct fetchHeadersByNumber function provided, should consider the chain as valid
|
||||
// create a mock function, returning a the required header
|
||||
|
|
@ -92,16 +92,16 @@ func TestIsValidChain(t *testing.T) {
|
|||
}
|
||||
|
||||
res, err = s.IsValidChain(nil, fetchHeadersByNumber)
|
||||
assert.NilError(t, err, "expected no error")
|
||||
assert.Equal(t, res, true, "expected chain to be valid")
|
||||
require.NoError(t, err, "expected no error")
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
|
||||
// add one more checkpoint whitelist entry
|
||||
s.ProcessCheckpoint(uint64(2), common.Hash{})
|
||||
assert.Equal(t, s.length(), 3, "expected 3 items in whitelist")
|
||||
require.Equal(t, s.length(), 3, "expected 3 items in whitelist")
|
||||
|
||||
// case4: correct fetchHeadersByNumber function provided with wrong header
|
||||
// for block number 2. Should consider the chain as invalid and throw an error
|
||||
res, err = s.IsValidChain(nil, fetchHeadersByNumber)
|
||||
assert.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error")
|
||||
assert.Equal(t, res, false, "expected chain to be invalid")
|
||||
require.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error")
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,8 +59,9 @@ func (api *PublicFilterAPI) NewDeposits(ctx context.Context, crit ethereum.State
|
|||
}
|
||||
|
||||
rpcSub := notifier.CreateSubscription()
|
||||
|
||||
go func() {
|
||||
stateSyncData := make(chan *types.StateSyncData)
|
||||
stateSyncData := make(chan *types.StateSyncData, 10)
|
||||
stateSyncSub := api.events.SubscribeNewDeposits(stateSyncData)
|
||||
|
||||
for {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
|
@ -162,7 +161,7 @@ func (b *BootnodeCommand) Run(args []string) int {
|
|||
}
|
||||
// save the public key
|
||||
pubRaw := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:])
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 0600); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 0600); err != nil {
|
||||
b.UI.Error(fmt.Sprintf("failed to write node pub key: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ethereum/go-ethereum/internal/cli/server"
|
||||
)
|
||||
|
|
@ -30,7 +30,7 @@ func TestCommand_DebugBlock(t *testing.T) {
|
|||
|
||||
// start the mock server
|
||||
srv, err := server.CreateMockServer(config)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer server.CloseMockServer(srv)
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ func TestCommand_DebugBlock(t *testing.T) {
|
|||
start := time.Now()
|
||||
dst1 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json")
|
||||
res := traceBlock(port, 1, output)
|
||||
assert.Equal(t, 0, res)
|
||||
require.Equal(t, 0, res)
|
||||
t.Logf("Completed trace of block %d in %d ms at %s", 1, time.Since(start).Milliseconds(), dst1)
|
||||
|
||||
// adding this to avoid debug directory name conflicts
|
||||
|
|
@ -64,14 +64,14 @@ func TestCommand_DebugBlock(t *testing.T) {
|
|||
latestBlock := srv.GetLatestBlockNumber().Int64()
|
||||
dst2 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json")
|
||||
res = traceBlock(port, latestBlock, output)
|
||||
assert.Equal(t, 0, res)
|
||||
require.Equal(t, 0, res)
|
||||
t.Logf("Completed trace of block %d in %d ms at %s", latestBlock, time.Since(start).Milliseconds(), dst2)
|
||||
|
||||
// verify if the trace files are created
|
||||
done := verify(dst1)
|
||||
assert.Equal(t, true, done)
|
||||
require.Equal(t, true, done)
|
||||
done = verify(dst2)
|
||||
assert.Equal(t, true, done)
|
||||
require.Equal(t, true, done)
|
||||
|
||||
// delete the traces
|
||||
deleteTraces(output)
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ package cli
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCodeBlock(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := assert.New(t)
|
||||
assert := require.New(t)
|
||||
|
||||
lines := []string{
|
||||
"abc",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -50,7 +49,7 @@ func GetChain(name string) (*Chain, error) {
|
|||
}
|
||||
|
||||
func ImportFromFile(filename string) (*Chain, error) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
|
|
@ -55,7 +54,7 @@ func CreateMockServer(config *Config) (*Server, error) {
|
|||
config.GRPC.Addr = fmt.Sprintf(":%d", port)
|
||||
|
||||
// datadir
|
||||
datadir, _ := ioutil.TempDir("/tmp", "bor-cli-test")
|
||||
datadir, _ := os.MkdirTemp("/tmp", "bor-cli-test")
|
||||
config.DataDir = datadir
|
||||
|
||||
// find available port for http server
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/tyler-smith/go-bip39"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
|
|
@ -47,7 +49,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/tyler-smith/go-bip39"
|
||||
)
|
||||
|
||||
// PublicEthereumAPI provides an API to access Ethereum related information.
|
||||
|
|
@ -829,10 +830,10 @@ func (s *PublicBlockChainAPI) getAuthor(head *types.Header) *common.Address {
|
|||
}
|
||||
|
||||
// GetBlockByNumber returns the requested canonical block.
|
||||
// * When blockNr is -1 the chain head is returned.
|
||||
// * When blockNr is -2 the pending chain head is returned.
|
||||
// * When fullTx is true all transactions in the block are returned, otherwise
|
||||
// only the transaction hash is returned.
|
||||
// - When blockNr is -1 the chain head is returned.
|
||||
// - When blockNr is -2 the pending chain head is returned.
|
||||
// - When fullTx is true all transactions in the block are returned, otherwise
|
||||
// only the transaction hash is returned.
|
||||
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
||||
block, err := s.b.BlockByNumber(ctx, number)
|
||||
if block != nil && err == nil {
|
||||
|
|
|
|||
168
tests/bor/bor_api_test.go
Normal file
168
tests/bor/bor_api_test.go
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
//go:build integration
|
||||
|
||||
package bor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||
)
|
||||
|
||||
func TestGetTransactionReceiptsByBlock(t *testing.T) {
|
||||
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
||||
chain := init.ethereum.BlockChain()
|
||||
engine := init.ethereum.Engine()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
_bor := engine.(*bor.Bor)
|
||||
defer _bor.Close()
|
||||
|
||||
// Mock /bor/span/1
|
||||
res, _ := loadSpanFromFile(t)
|
||||
|
||||
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||
|
||||
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(&res.Result, nil).MinTimes(1)
|
||||
h.EXPECT().Close().MinTimes(1)
|
||||
h.EXPECT().FetchLatestCheckpoint(gomock.Any()).Return(&checkpoint.Checkpoint{
|
||||
Proposer: res.Result.SelectedProducers[0].Address,
|
||||
StartBlock: big.NewInt(0),
|
||||
EndBlock: big.NewInt(int64(spanSize)),
|
||||
}, nil).AnyTimes()
|
||||
|
||||
// Mock State Sync events
|
||||
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
||||
fromID := uint64(1)
|
||||
to := int64(chain.GetHeaderByNumber(0).Time)
|
||||
sample := getSampleEventRecord(t)
|
||||
|
||||
// First query will be from [id=1, (block-sprint).Time]
|
||||
eventRecords := []*clerk.EventRecordWithTime{
|
||||
buildStateEvent(sample, 1, 1),
|
||||
buildStateEvent(sample, 2, 2),
|
||||
buildStateEvent(sample, 3, 3),
|
||||
}
|
||||
|
||||
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).MinTimes(1)
|
||||
_bor.SetHeimdallClient(h)
|
||||
|
||||
// Insert blocks for 0th sprint
|
||||
db := init.ethereum.ChainDb()
|
||||
block := init.genesis.ToBlock(db)
|
||||
|
||||
signer := types.LatestSigner(init.genesis.Config)
|
||||
toAddress := common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||
|
||||
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
txHashes := map[int]common.Hash{} // blockNumber -> txHash
|
||||
|
||||
var (
|
||||
err error
|
||||
nonce uint64
|
||||
tx *types.Transaction
|
||||
txs []*types.Transaction
|
||||
)
|
||||
|
||||
for i := uint64(1); i <= sprintSize; i++ {
|
||||
if IsSpanEnd(i) {
|
||||
currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
}
|
||||
|
||||
if i%3 == 0 {
|
||||
txdata := &types.LegacyTx{
|
||||
Nonce: nonce,
|
||||
To: &toAddress,
|
||||
Gas: 30000,
|
||||
GasPrice: newGwei(5),
|
||||
}
|
||||
|
||||
nonce++
|
||||
|
||||
tx = types.NewTx(txdata)
|
||||
tx, err = types.SignTx(tx, signer, key)
|
||||
require.Nil(t, err, "an incorrect transaction or signer")
|
||||
|
||||
txs = []*types.Transaction{tx}
|
||||
} else {
|
||||
txs = nil
|
||||
}
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, txs, currentValidators)
|
||||
insertNewBlock(t, chain, block)
|
||||
|
||||
if len(txs) != 0 {
|
||||
txHashes[int(block.Number().Uint64())] = tx.Hash()
|
||||
}
|
||||
}
|
||||
|
||||
// state 6 was not written
|
||||
//
|
||||
fromID = uint64(4)
|
||||
to = int64(chain.GetHeaderByNumber(sprintSize).Time)
|
||||
|
||||
eventRecords = []*clerk.EventRecordWithTime{
|
||||
buildStateEvent(sample, 4, 4),
|
||||
buildStateEvent(sample, 5, 5),
|
||||
}
|
||||
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).MinTimes(1)
|
||||
|
||||
for i := sprintSize + 1; i <= spanSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
||||
ethAPI := ethapi.NewPublicBlockChainAPI(init.ethereum.APIBackend)
|
||||
txPoolAPI := ethapi.NewPublicTransactionPoolAPI(init.ethereum.APIBackend, nil)
|
||||
|
||||
for n := 0; n < int(spanSize)+1; n++ {
|
||||
rpcNumber := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(n))
|
||||
|
||||
txs, err := ethAPI.GetTransactionReceiptsByBlock(context.Background(), rpcNumber)
|
||||
require.Nil(t, err)
|
||||
|
||||
tx := txPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(n), 0)
|
||||
|
||||
blockMap, err := ethAPI.GetBlockByNumber(context.Background(), rpc.BlockNumber(n), true)
|
||||
require.Nil(t, err)
|
||||
|
||||
expectedTxHash, ok := txHashes[n]
|
||||
// FIXME: add `IsSprintStart(uint64(n)) || IsSpanStart(uint64(n))` after adding a full state receiver contract
|
||||
if ok {
|
||||
require.Len(t, txs, 1)
|
||||
|
||||
require.NotNil(t, tx, "not nil receipt expected")
|
||||
|
||||
require.Equal(t, expectedTxHash, tx.Hash, "got different from expected receipt")
|
||||
|
||||
blockTxs, ok := blockMap["transactions"].([]interface{})
|
||||
require.Len(t, blockTxs, 1)
|
||||
|
||||
blockTx, ok := blockTxs[0].(*ethapi.RPCTransaction)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, expectedTxHash, blockTx.Hash)
|
||||
} else {
|
||||
require.Len(t, txs, 0)
|
||||
|
||||
require.Nil(t, tx, "nil receipt expected")
|
||||
|
||||
blockTxs, _ := blockMap["transactions"].([]interface{})
|
||||
require.Len(t, blockTxs, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,14 +11,15 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
|
|
@ -38,11 +39,11 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
|||
|
||||
defer _bor.Close()
|
||||
|
||||
h, heimdallSpan, ctrl := getMockedHeimdallClient(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
_, currentSpan := loadSpanFromFile(t)
|
||||
|
||||
h, ctrl := getMockedHeimdallClient(t, currentSpan)
|
||||
defer ctrl.Finish()
|
||||
|
||||
h.EXPECT().Close().AnyTimes()
|
||||
h.EXPECT().FetchLatestCheckpoint(gomock.Any()).Return(&checkpoint.Checkpoint{
|
||||
Proposer: currentSpan.SelectedProducers[0].Address,
|
||||
|
|
@ -56,9 +57,11 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
|||
block := init.genesis.ToBlock(db)
|
||||
// to := int64(block.Header().Time)
|
||||
|
||||
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
|
||||
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
||||
for i := uint64(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, nil, currentValidators)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
||||
|
|
@ -67,10 +70,10 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
|||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 3, len(validators))
|
||||
require.Equal(t, 3, len(validators))
|
||||
for i, validator := range validators {
|
||||
assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes())
|
||||
assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower)
|
||||
require.Equal(t, validator.Address.Bytes(), currentSpan.SelectedProducers[i].Address.Bytes())
|
||||
require.Equal(t, validator.VotingPower, currentSpan.SelectedProducers[i].VotingPower)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -85,16 +88,23 @@ func TestFetchStateSyncEvents(t *testing.T) {
|
|||
// A. Insert blocks for 0th sprint
|
||||
db := init.ethereum.ChainDb()
|
||||
block := init.genesis.ToBlock(db)
|
||||
|
||||
// B.1 Mock /bor/span/1
|
||||
res, _ := loadSpanFromFile(t)
|
||||
|
||||
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
|
||||
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
||||
for i := uint64(1); i < sprintSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||
if IsSpanEnd(i) {
|
||||
currentValidators = res.Result.ValidatorSet.Validators
|
||||
}
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
||||
// B. Before inserting 1st block of the next sprint, mock heimdall deps
|
||||
// B.1 Mock /bor/span/1
|
||||
res, _ := loadSpanFromFile(t)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
|
|
@ -115,7 +125,7 @@ func TestFetchStateSyncEvents(t *testing.T) {
|
|||
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes()
|
||||
_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, nil, res.Result.ValidatorSet.Validators)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
||||
|
|
@ -130,6 +140,9 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
// Mock /bor/span/1
|
||||
res, _ := loadSpanFromFile(t)
|
||||
|
||||
// add the block producer
|
||||
res.Result.ValidatorSet.Validators = append(res.Result.ValidatorSet.Validators, valset.NewValidator(addr, 4500))
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
|
|
@ -160,15 +173,24 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
// Insert blocks for 0th sprint
|
||||
db := init.ethereum.ChainDb()
|
||||
block := init.genesis.ToBlock(db)
|
||||
|
||||
var currentValidators []*valset.Validator
|
||||
|
||||
for i := uint64(1); i <= sprintSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||
if IsSpanEnd(i) {
|
||||
currentValidators = res.Result.ValidatorSet.Validators
|
||||
} else {
|
||||
currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
}
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
||||
lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize)
|
||||
|
||||
// state 6 was not written
|
||||
assert.Equal(t, uint64(4), lastStateID.Uint64())
|
||||
require.Equal(t, uint64(4), lastStateID.Uint64())
|
||||
|
||||
//
|
||||
fromID = uint64(5)
|
||||
|
|
@ -181,12 +203,18 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes()
|
||||
|
||||
for i := sprintSize + 1; i <= spanSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||
if IsSpanEnd(i) {
|
||||
currentValidators = res.Result.ValidatorSet.Validators
|
||||
} else {
|
||||
currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
}
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
||||
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
|
||||
assert.Equal(t, uint64(6), lastStateID.Uint64())
|
||||
require.Equal(t, uint64(6), lastStateID.Uint64())
|
||||
}
|
||||
|
||||
func TestOutOfTurnSigning(t *testing.T) {
|
||||
|
|
@ -197,17 +225,29 @@ func TestOutOfTurnSigning(t *testing.T) {
|
|||
|
||||
defer _bor.Close()
|
||||
|
||||
h, _, ctrl := getMockedHeimdallClient(t)
|
||||
_, heimdallSpan := loadSpanFromFile(t)
|
||||
proposer := valset.NewValidator(addr, 10)
|
||||
heimdallSpan.ValidatorSet.Validators = append(heimdallSpan.ValidatorSet.Validators, proposer)
|
||||
|
||||
// add the block producer
|
||||
h, ctrl := getMockedHeimdallClient(t, heimdallSpan)
|
||||
defer ctrl.Finish()
|
||||
|
||||
h.EXPECT().Close().AnyTimes()
|
||||
|
||||
_bor.SetHeimdallClient(h)
|
||||
|
||||
db := init.ethereum.ChainDb()
|
||||
block := init.genesis.ToBlock(db)
|
||||
|
||||
setDifficulty := func(header *types.Header) {
|
||||
if IsSprintStart(header.Number.Uint64()) {
|
||||
header.Difficulty = big.NewInt(int64(len(heimdallSpan.ValidatorSet.Validators)))
|
||||
}
|
||||
}
|
||||
|
||||
for i := uint64(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, nil, heimdallSpan.ValidatorSet.Validators, setDifficulty)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
||||
|
|
@ -215,36 +255,50 @@ func TestOutOfTurnSigning(t *testing.T) {
|
|||
// This account is one the out-of-turn validators for 1st (0-indexed) span
|
||||
signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
|
||||
signerKey, _ := hex.DecodeString(signer)
|
||||
key, _ = crypto.HexToECDSA(signer)
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||
newKey, _ := crypto.HexToECDSA(signer)
|
||||
newAddr := crypto.PubkeyToAddress(newKey.PublicKey)
|
||||
expectedSuccessionNumber := 2
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
|
||||
_, err := chain.InsertChain([]*types.Block{block})
|
||||
assert.Equal(t,
|
||||
*err.(*bor.BlockTooSoonError),
|
||||
bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber})
|
||||
parentTime := block.Time()
|
||||
|
||||
expectedDifficulty := uint64(3 - expectedSuccessionNumber) // len(validators) - succession
|
||||
setParentTime := func(header *types.Header) {
|
||||
header.Time = parentTime + 1
|
||||
}
|
||||
|
||||
const turn = 1
|
||||
|
||||
setDifficulty = func(header *types.Header) {
|
||||
header.Difficulty = big.NewInt(int64(len(heimdallSpan.ValidatorSet.Validators)) - turn)
|
||||
}
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators, setParentTime, setDifficulty)
|
||||
_, err := chain.InsertChain([]*types.Block{block})
|
||||
require.Equal(t,
|
||||
bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber},
|
||||
*err.(*bor.BlockTooSoonError))
|
||||
|
||||
expectedDifficulty := uint64(len(heimdallSpan.ValidatorSet.Validators) - expectedSuccessionNumber - turn) // len(validators) - succession
|
||||
header := block.Header()
|
||||
|
||||
header.Time += bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) -
|
||||
bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor)
|
||||
diff := bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor)
|
||||
header.Time += diff
|
||||
|
||||
sign(t, header, signerKey, init.genesis.Config.Bor)
|
||||
|
||||
block = types.NewBlockWithHeader(header)
|
||||
|
||||
_, err = chain.InsertChain([]*types.Block{block})
|
||||
assert.Equal(t,
|
||||
*err.(*bor.WrongDifficultyError),
|
||||
bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()})
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t,
|
||||
bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: newAddr.Bytes()},
|
||||
*err.(*bor.WrongDifficultyError))
|
||||
|
||||
header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
|
||||
sign(t, header, signerKey, init.genesis.Config.Bor)
|
||||
block = types.NewBlockWithHeader(header)
|
||||
|
||||
_, err = chain.InsertChain([]*types.Block{block})
|
||||
assert.Nil(t, err)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestSignerNotFound(t *testing.T) {
|
||||
|
|
@ -255,7 +309,9 @@ func TestSignerNotFound(t *testing.T) {
|
|||
|
||||
defer _bor.Close()
|
||||
|
||||
h, _, ctrl := getMockedHeimdallClient(t)
|
||||
_, heimdallSpan := loadSpanFromFile(t)
|
||||
|
||||
h, ctrl := getMockedHeimdallClient(t, heimdallSpan)
|
||||
defer ctrl.Finish()
|
||||
|
||||
h.EXPECT().Close().AnyTimes()
|
||||
|
|
@ -266,62 +322,21 @@ func TestSignerNotFound(t *testing.T) {
|
|||
block := init.genesis.ToBlock(db)
|
||||
|
||||
// random signer account that is not a part of the validator set
|
||||
signer := "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b"
|
||||
const signer = "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b"
|
||||
signerKey, _ := hex.DecodeString(signer)
|
||||
key, _ = crypto.HexToECDSA(signer)
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||
newKey, _ := crypto.HexToECDSA(signer)
|
||||
newAddr := crypto.PubkeyToAddress(newKey.PublicKey)
|
||||
|
||||
_bor.Authorize(newAddr, func(account accounts.Account, s string, data []byte) ([]byte, error) {
|
||||
return crypto.Sign(crypto.Keccak256(data), newKey)
|
||||
})
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators)
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
|
||||
_, err := chain.InsertChain([]*types.Block{block})
|
||||
assert.Equal(t,
|
||||
require.Equal(t,
|
||||
*err.(*bor.UnauthorizedSignerError),
|
||||
bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()})
|
||||
}
|
||||
|
||||
func getMockedHeimdallClient(t *testing.T) (*mocks.MockIHeimdallClient, *span.HeimdallSpan, *gomock.Controller) {
|
||||
ctrl := gomock.NewController(t)
|
||||
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||
|
||||
_, heimdallSpan := loadSpanFromFile(t)
|
||||
|
||||
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(heimdallSpan, nil).AnyTimes()
|
||||
|
||||
h.EXPECT().StateSyncEvents(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes()
|
||||
|
||||
return h, heimdallSpan, ctrl
|
||||
}
|
||||
|
||||
func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime {
|
||||
events := make([]*clerk.EventRecordWithTime, count)
|
||||
event := *sample
|
||||
event.ID = 1
|
||||
events[0] = &clerk.EventRecordWithTime{}
|
||||
*events[0] = event
|
||||
for i := 1; i < count; i++ {
|
||||
event.ID = uint64(i)
|
||||
event.Time = event.Time.Add(1 * time.Second)
|
||||
events[i] = &clerk.EventRecordWithTime{}
|
||||
*events[i] = event
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
func buildStateEvent(sample *clerk.EventRecordWithTime, id uint64, timeStamp int64) *clerk.EventRecordWithTime {
|
||||
event := *sample
|
||||
event.ID = id
|
||||
event.Time = time.Unix(timeStamp, 0)
|
||||
return &event
|
||||
}
|
||||
|
||||
func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime {
|
||||
eventRecords := stateSyncEventsPayload(t)
|
||||
eventRecords.Result[0].Time = time.Unix(1, 0)
|
||||
return eventRecords.Result[0]
|
||||
}
|
||||
|
||||
func getEventRecords(t *testing.T) []*clerk.EventRecordWithTime {
|
||||
return stateSyncEventsPayload(t).Result
|
||||
bor.UnauthorizedSignerError{Number: 0, Signer: newAddr.Bytes()})
|
||||
}
|
||||
|
||||
// TestEIP1559Transition tests the following:
|
||||
|
|
@ -351,7 +366,7 @@ func TestEIP1559Transition(t *testing.T) {
|
|||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
gspec = &core.Genesis{
|
||||
Config: params.BorTestChainConfig,
|
||||
Config: params.BorUnittestChainConfig,
|
||||
Alloc: core.GenesisAlloc{
|
||||
addr1: {Balance: funds},
|
||||
addr2: {Balance: funds},
|
||||
|
|
@ -433,7 +448,7 @@ func TestEIP1559Transition(t *testing.T) {
|
|||
}
|
||||
|
||||
// check burnt contract balance
|
||||
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
||||
actual = state.GetBalance(common.HexToAddress(params.BorUnittestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
||||
expected = new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee())
|
||||
burntContractBalance := expected
|
||||
if actual.Cmp(expected) != 0 {
|
||||
|
|
@ -481,7 +496,7 @@ func TestEIP1559Transition(t *testing.T) {
|
|||
}
|
||||
|
||||
// check burnt contract balance
|
||||
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
||||
actual = state.GetBalance(common.HexToAddress(params.BorUnittestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
||||
expected = new(big.Int).Add(burntContractBalance, new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee()))
|
||||
burntContractBalance = expected
|
||||
if actual.Cmp(expected) != 0 {
|
||||
|
|
@ -539,7 +554,7 @@ func TestEIP1559Transition(t *testing.T) {
|
|||
state, _ = chain.State()
|
||||
|
||||
// check burnt contract balance
|
||||
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
||||
actual = state.GetBalance(common.HexToAddress(params.BorUnittestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
||||
burntAmount := new(big.Int).Mul(
|
||||
block.BaseFee(),
|
||||
big.NewInt(int64(block.GasUsed())),
|
||||
|
|
@ -550,25 +565,188 @@ func TestEIP1559Transition(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func newGwei(n int64) *big.Int {
|
||||
return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei))
|
||||
// EIP1559 is not supported without EIP155. An error is expected
|
||||
func TestEIP1559TransitionWithEIP155(t *testing.T) {
|
||||
var (
|
||||
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||
|
||||
// Generate a canonical chain to act as the main dataset
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
engine = ethash.NewFaker()
|
||||
|
||||
// A sender who makes transactions, has some funds
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
key3, _ = crypto.HexToECDSA("225171aed3793cba1c029832886d69785b7e77a54a44211226b447aa2d16b058")
|
||||
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
gspec = &core.Genesis{
|
||||
Config: params.BorUnittestChainConfig,
|
||||
Alloc: core.GenesisAlloc{
|
||||
addr1: {Balance: funds},
|
||||
addr2: {Balance: funds},
|
||||
addr3: {Balance: funds},
|
||||
// The address 0xAAAA sloads 0x00 and 0x01
|
||||
aa: {
|
||||
Code: []byte{
|
||||
byte(vm.PC),
|
||||
byte(vm.PC),
|
||||
byte(vm.SLOAD),
|
||||
byte(vm.SLOAD),
|
||||
},
|
||||
Nonce: 0,
|
||||
Balance: big.NewInt(0),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
genesis := gspec.MustCommit(db)
|
||||
|
||||
// Use signer without chain ID
|
||||
signer := types.HomesteadSigner{}
|
||||
|
||||
_, _ = core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) {
|
||||
b.SetCoinbase(common.Address{1})
|
||||
// One transaction to 0xAAAA
|
||||
accesses := types.AccessList{types.AccessTuple{
|
||||
Address: aa,
|
||||
StorageKeys: []common.Hash{{0}},
|
||||
}}
|
||||
|
||||
txdata := &types.DynamicFeeTx{
|
||||
ChainID: gspec.Config.ChainID,
|
||||
Nonce: 0,
|
||||
To: &aa,
|
||||
Gas: 30000,
|
||||
GasFeeCap: newGwei(5),
|
||||
GasTipCap: big.NewInt(2),
|
||||
AccessList: accesses,
|
||||
Data: []byte{},
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
tx := types.NewTx(txdata)
|
||||
tx, err = types.SignTx(tx, signer, key1)
|
||||
|
||||
require.ErrorIs(t, err, types.ErrTxTypeNotSupported)
|
||||
})
|
||||
}
|
||||
|
||||
// it is up to a user to use protected transactions. so if a transaction is unprotected no errors related to chainID are expected.
|
||||
// transactions are checked in 2 places: transaction pool and blockchain processor.
|
||||
func TestTransitionWithoutEIP155(t *testing.T) {
|
||||
var (
|
||||
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||
|
||||
// Generate a canonical chain to act as the main dataset
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
engine = ethash.NewFaker()
|
||||
|
||||
// A sender who makes transactions, has some funds
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
key3, _ = crypto.HexToECDSA("225171aed3793cba1c029832886d69785b7e77a54a44211226b447aa2d16b058")
|
||||
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
gspec = &core.Genesis{
|
||||
Config: params.BorUnittestChainConfig,
|
||||
Alloc: core.GenesisAlloc{
|
||||
addr1: {Balance: funds},
|
||||
addr2: {Balance: funds},
|
||||
addr3: {Balance: funds},
|
||||
// The address 0xAAAA sloads 0x00 and 0x01
|
||||
aa: {
|
||||
Code: []byte{
|
||||
byte(vm.PC),
|
||||
byte(vm.PC),
|
||||
byte(vm.SLOAD),
|
||||
byte(vm.SLOAD),
|
||||
},
|
||||
Nonce: 0,
|
||||
Balance: big.NewInt(0),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
genesis := gspec.MustCommit(db)
|
||||
|
||||
// Use signer without chain ID
|
||||
signer := types.HomesteadSigner{}
|
||||
//signer := types.FrontierSigner{}
|
||||
|
||||
blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) {
|
||||
b.SetCoinbase(common.Address{1})
|
||||
|
||||
txdata := &types.LegacyTx{
|
||||
Nonce: 0,
|
||||
To: &aa,
|
||||
Gas: 30000,
|
||||
GasPrice: newGwei(5),
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
tx := types.NewTx(txdata)
|
||||
tx, err = types.SignTx(tx, signer, key1)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.False(t, tx.Protected())
|
||||
|
||||
from, err := types.Sender(types.EIP155Signer{}, tx)
|
||||
require.Equal(t, addr1, from)
|
||||
require.Nil(t, err)
|
||||
|
||||
b.AddTx(tx)
|
||||
})
|
||||
|
||||
diskdb := rawdb.NewMemoryDatabase()
|
||||
gspec.MustCommit(diskdb)
|
||||
|
||||
chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
if n, err := chain.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
|
||||
block := chain.GetBlockByNumber(1)
|
||||
|
||||
require.Len(t, block.Transactions(), 1)
|
||||
}
|
||||
|
||||
func TestJaipurFork(t *testing.T) {
|
||||
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
||||
chain := init.ethereum.BlockChain()
|
||||
engine := init.ethereum.Engine()
|
||||
|
||||
_bor := engine.(*bor.Bor)
|
||||
defer _bor.Close()
|
||||
|
||||
db := init.ethereum.ChainDb()
|
||||
block := init.genesis.ToBlock(db)
|
||||
|
||||
res, _ := loadSpanFromFile(t)
|
||||
|
||||
for i := uint64(1); i < sprintSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators)
|
||||
insertNewBlock(t, chain, block)
|
||||
|
||||
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock-1 {
|
||||
assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
||||
require.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
||||
}
|
||||
|
||||
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock {
|
||||
assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
||||
require.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,46 +1,63 @@
|
|||
//go:build integration
|
||||
|
||||
package bor
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"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/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/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/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// Only this account is a validator for the 0th span
|
||||
key, _ = crypto.HexToECDSA(privKey)
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7
|
||||
|
||||
// This account is one the validators for 1st span (0-indexed)
|
||||
key2, _ = crypto.HexToECDSA(privKey2)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
|
||||
)
|
||||
|
||||
const (
|
||||
privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
||||
privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
|
||||
|
||||
// The genesis for tests was generated with following parameters
|
||||
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
|
||||
// Only this account is a validator for the 0th span
|
||||
privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
||||
key, _ = crypto.HexToECDSA(privKey)
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7
|
||||
sprintSize uint64 = 4
|
||||
spanSize uint64 = 8
|
||||
|
||||
// This account is one the validators for 1st span (0-indexed)
|
||||
privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
|
||||
key2, _ = crypto.HexToECDSA(privKey2)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
|
||||
|
||||
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
|
||||
sprintSize uint64 = 4
|
||||
spanSize uint64 = 8
|
||||
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
|
||||
)
|
||||
|
||||
type initializeData struct {
|
||||
|
|
@ -49,8 +66,6 @@ type initializeData struct {
|
|||
}
|
||||
|
||||
func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
||||
t.Helper()
|
||||
|
||||
genesisData, err := ioutil.ReadFile("./testdata/genesis.json")
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
|
|
@ -64,6 +79,7 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
|||
|
||||
ethConf := ð.Config{
|
||||
Genesis: gen,
|
||||
BorLogs: true,
|
||||
}
|
||||
|
||||
ethConf.Genesis.MustCommit(db)
|
||||
|
|
@ -75,6 +91,10 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
|||
|
||||
ethConf.Genesis.MustCommit(ethereum.ChainDb())
|
||||
|
||||
ethereum.Engine().(*bor.Bor).Authorize(addr, func(account accounts.Account, s string, data []byte) ([]byte, error) {
|
||||
return crypto.Sign(crypto.Keccak256(data), key)
|
||||
})
|
||||
|
||||
return &initializeData{
|
||||
genesis: gen,
|
||||
ethereum: ethereum,
|
||||
|
|
@ -89,33 +109,31 @@ func insertNewBlock(t *testing.T, chain *core.BlockChain, block *types.Block) {
|
|||
}
|
||||
}
|
||||
|
||||
func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *types.Block, signer []byte, borConfig *params.BorConfig) *types.Block {
|
||||
type Option func(header *types.Header)
|
||||
|
||||
func buildNextBlock(t *testing.T, _bor consensus.Engine, chain *core.BlockChain, parentBlock *types.Block, signer []byte, borConfig *params.BorConfig, txs []*types.Transaction, currentValidators []*valset.Validator, opts ...Option) *types.Block {
|
||||
t.Helper()
|
||||
|
||||
header := block.Header()
|
||||
header.Number.Add(header.Number, big.NewInt(1))
|
||||
header := &types.Header{
|
||||
Number: big.NewInt(int64(parentBlock.Number().Uint64() + 1)),
|
||||
Difficulty: big.NewInt(int64(parentBlock.Difficulty().Uint64())),
|
||||
GasLimit: parentBlock.GasLimit(),
|
||||
ParentHash: parentBlock.Hash(),
|
||||
}
|
||||
number := header.Number.Uint64()
|
||||
|
||||
if signer == nil {
|
||||
signer = getSignerKey(header.Number.Uint64())
|
||||
}
|
||||
|
||||
header.ParentHash = block.Hash()
|
||||
header.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig)
|
||||
header.Time = parentBlock.Time() + bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig)
|
||||
header.Extra = make([]byte, 32+65) // vanity + extraSeal
|
||||
|
||||
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
isSpanStart := IsSpanStart(number)
|
||||
isSprintEnd := IsSprintEnd(number)
|
||||
|
||||
isSpanEnd := (number+1)%spanSize == 0
|
||||
isSpanStart := number%spanSize == 0
|
||||
isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0
|
||||
|
||||
if isSpanEnd {
|
||||
_, heimdallSpan := loadSpanFromFile(t)
|
||||
// this is to stash the validator bytes in the header
|
||||
currentValidators = heimdallSpan.ValidatorSet.Validators
|
||||
} else if isSpanStart {
|
||||
header.Difficulty = new(big.Int).SetInt64(3)
|
||||
if isSpanStart {
|
||||
header.Difficulty = new(big.Int).SetInt64(int64(len(currentValidators)))
|
||||
}
|
||||
|
||||
if isSprintEnd {
|
||||
|
|
@ -132,27 +150,87 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *
|
|||
}
|
||||
|
||||
if chain.Config().IsLondon(header.Number) {
|
||||
header.BaseFee = misc.CalcBaseFee(chain.Config(), block.Header())
|
||||
header.BaseFee = misc.CalcBaseFee(chain.Config(), parentBlock.Header())
|
||||
|
||||
if !chain.Config().IsLondon(block.Number()) {
|
||||
parentGasLimit := block.GasLimit() * params.ElasticityMultiplier
|
||||
if !chain.Config().IsLondon(parentBlock.Number()) {
|
||||
parentGasLimit := parentBlock.GasLimit() * params.ElasticityMultiplier
|
||||
header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit)
|
||||
}
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(header)
|
||||
}
|
||||
|
||||
state, err := chain.State()
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
_, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
b := &blockGen{header: header}
|
||||
for _, tx := range txs {
|
||||
b.addTxWithChain(chain, state, tx, addr)
|
||||
}
|
||||
|
||||
sign(t, header, signer, borConfig)
|
||||
// Finalize and seal the block
|
||||
block, _ := _bor.FinalizeAndAssemble(chain, b.header, state, b.txs, nil, b.receipts)
|
||||
|
||||
return types.NewBlockWithHeader(header)
|
||||
// Write state changes to db
|
||||
root, err := state.Commit(chain.Config().IsEIP158(b.header.Number))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("state write error: %v", err))
|
||||
}
|
||||
|
||||
if err := state.Database().TrieDB().Commit(root, false, nil); err != nil {
|
||||
panic(fmt.Sprintf("trie write error: %v", err))
|
||||
}
|
||||
|
||||
res := make(chan *types.Block, 1)
|
||||
|
||||
err = _bor.Seal(chain, block, res, nil)
|
||||
if err != nil {
|
||||
// an error case - sign manually
|
||||
sign(t, header, signer, borConfig)
|
||||
return types.NewBlockWithHeader(header)
|
||||
}
|
||||
|
||||
return <-res
|
||||
}
|
||||
|
||||
type blockGen struct {
|
||||
txs []*types.Transaction
|
||||
receipts []*types.Receipt
|
||||
gasPool *core.GasPool
|
||||
header *types.Header
|
||||
}
|
||||
|
||||
func (b *blockGen) addTxWithChain(bc *core.BlockChain, statedb *state.StateDB, tx *types.Transaction, coinbase common.Address) {
|
||||
if b.gasPool == nil {
|
||||
b.setCoinbase(coinbase)
|
||||
}
|
||||
|
||||
statedb.Prepare(tx.Hash(), len(b.txs))
|
||||
|
||||
receipt, err := core.ApplyTransaction(bc.Config(), bc, &b.header.Coinbase, b.gasPool, statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
b.txs = append(b.txs, tx)
|
||||
b.receipts = append(b.receipts, receipt)
|
||||
}
|
||||
|
||||
func (b *blockGen) setCoinbase(addr common.Address) {
|
||||
if b.gasPool != nil {
|
||||
if len(b.txs) > 0 {
|
||||
panic("coinbase must be set before adding transactions")
|
||||
}
|
||||
|
||||
panic("coinbase can only be set once")
|
||||
}
|
||||
|
||||
b.header.Coinbase = addr
|
||||
b.gasPool = new(core.GasPool).AddGas(b.header.GasLimit)
|
||||
}
|
||||
|
||||
func sign(t *testing.T, header *types.Header, signer []byte, c *params.BorConfig) {
|
||||
|
|
@ -204,13 +282,80 @@ func loadSpanFromFile(t *testing.T) (*heimdall.SpanResponse, *span.HeimdallSpan)
|
|||
func getSignerKey(number uint64) []byte {
|
||||
signerKey := privKey
|
||||
|
||||
isSpanStart := number%spanSize == 0
|
||||
if isSpanStart {
|
||||
if IsSpanStart(number) {
|
||||
// validator set in the new span has changed
|
||||
signerKey = privKey2
|
||||
}
|
||||
|
||||
_key, _ := hex.DecodeString(signerKey)
|
||||
newKey, _ := hex.DecodeString(signerKey)
|
||||
|
||||
return _key
|
||||
return newKey
|
||||
}
|
||||
|
||||
func getMockedHeimdallClient(t *testing.T, heimdallSpan *span.HeimdallSpan) (*mocks.MockIHeimdallClient, *gomock.Controller) {
|
||||
t.Helper()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||
|
||||
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(heimdallSpan, nil).AnyTimes()
|
||||
|
||||
h.EXPECT().StateSyncEvents(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes()
|
||||
|
||||
return h, ctrl
|
||||
}
|
||||
|
||||
func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime {
|
||||
events := make([]*clerk.EventRecordWithTime, count)
|
||||
event := *sample
|
||||
event.ID = 1
|
||||
events[0] = &clerk.EventRecordWithTime{}
|
||||
*events[0] = event
|
||||
|
||||
for i := 1; i < count; i++ {
|
||||
event.ID = uint64(i)
|
||||
event.Time = event.Time.Add(1 * time.Second)
|
||||
events[i] = &clerk.EventRecordWithTime{}
|
||||
*events[i] = event
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
func buildStateEvent(sample *clerk.EventRecordWithTime, id uint64, timeStamp int64) *clerk.EventRecordWithTime {
|
||||
event := *sample
|
||||
event.ID = id
|
||||
event.Time = time.Unix(timeStamp, 0)
|
||||
|
||||
return &event
|
||||
}
|
||||
|
||||
func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime {
|
||||
t.Helper()
|
||||
|
||||
eventRecords := stateSyncEventsPayload(t)
|
||||
eventRecords.Result[0].Time = time.Unix(1, 0)
|
||||
|
||||
return eventRecords.Result[0]
|
||||
}
|
||||
|
||||
func newGwei(n int64) *big.Int {
|
||||
return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei))
|
||||
}
|
||||
|
||||
func IsSpanEnd(number uint64) bool {
|
||||
return (number+1)%spanSize == 0
|
||||
}
|
||||
|
||||
func IsSpanStart(number uint64) bool {
|
||||
return number%spanSize == 0
|
||||
}
|
||||
|
||||
func IsSprintStart(number uint64) bool {
|
||||
return number%sprintSize == 0
|
||||
}
|
||||
|
||||
func IsSprintEnd(number uint64) bool {
|
||||
return (number+1)%sprintSize == 0
|
||||
}
|
||||
|
|
|
|||
3
tests/bor/testdata/genesis.json
vendored
3
tests/bor/testdata/genesis.json
vendored
|
|
@ -52,6 +52,9 @@
|
|||
},
|
||||
"71562b71999873DB5b286dF957af199Ec94617F7": {
|
||||
"balance": "0x3635c9adc5dea00000"
|
||||
},
|
||||
"9fB29AAc15b9A4B7F17c3385939b007540f4d791": {
|
||||
"balance": "0x3635c9adc5dea00000"
|
||||
}
|
||||
},
|
||||
"number": "0x0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue