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:
Arpit Temani 2022-07-14 21:58:56 +05:30 committed by GitHub
parent 1147994c65
commit 7b25997830
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 820 additions and 281 deletions

View file

@ -5,11 +5,12 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"gopkg.in/urfave/cli.v1"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"gopkg.in/urfave/cli.v1"
) )
var ( var (

View file

@ -606,7 +606,7 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
return err 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 // Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
return &UnauthorizedSignerError{number - 1, signer.Bytes()} 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) 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} return &BlockTooSoonError{number, succession}
} }
// Ensure that the difficulty corresponds to the turn-ness of the signer // Ensure that the difficulty corresponds to the turn-ness of the signer
if !c.fakeDiff { if !c.fakeDiff {
difficulty := snap.Difficulty(signer) difficulty := Difficulty(snap.ValidatorSet, signer)
if header.Difficulty.Uint64() != difficulty { if header.Difficulty.Uint64() != difficulty {
return &WrongDifficultyError{number, difficulty, header.Difficulty.Uint64(), signer.Bytes()} 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 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 // Prepare implements consensus.Engine, preparing all the consensus fields of the
// header for running the transactions on top. // header for running the transactions on top.
func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { 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 // 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 // Ensure the extra data has all it's components
if len(header.Extra) < extraVanity { if len(header.Extra) < extraVanity {
@ -716,7 +720,7 @@ 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 IsSprintStart(headerNumber, c.config.Sprint) {
ctx := context.Background() ctx := context.Background()
cx := statefull.ChainContext{Chain: chain, Bor: c} 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 { if c.HeimdallClient != nil {
// commit statees // commit states
stateSyncData, err = c.CommitStates(ctx, state, header, cx) stateSyncData, err = c.CommitStates(ctx, state, header, cx)
if err != nil { if err != nil {
log.Error("Error while committing states", "error", err) 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() headerNumber := header.Number.Uint64()
if headerNumber%c.config.Sprint == 0 { if IsSprintStart(headerNumber, c.config.Sprint) {
ctx := context.Background() ctx := context.Background()
cx := statefull.ChainContext{Chain: chain, Bor: c} 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 // 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 // Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
return &UnauthorizedSignerError{number - 1, signer.Bytes()} return &UnauthorizedSignerError{number - 1, signer.Bytes()}
} }
@ -945,7 +949,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, _ uint64, parent
return nil 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. // SealHash returns the hash of a block prior to it being sealed.
@ -1059,7 +1063,6 @@ func (c *Bor) CommitStates(
header *types.Header, header *types.Header,
chain statefull.ChainContext, chain statefull.ChainContext,
) ([]*types.StateSyncData, error) { ) ([]*types.StateSyncData, error) {
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)
@ -1087,15 +1090,17 @@ func (c *Bor) CommitStates(
} }
totalGas := 0 /// limit on gas for state sync per block totalGas := 0 /// limit on gas for state sync per block
chainID := c.chainConfig.ChainID.String() chainID := c.chainConfig.ChainID.String()
stateSyncs := make([]*types.StateSyncData, len(eventRecords))
var gasUsed uint64
for _, eventRecord := range eventRecords { for _, eventRecord := range eventRecords {
if eventRecord.ID <= lastStateID { if eventRecord.ID <= lastStateID {
continue continue
} }
if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil { if err = validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error()) log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error())
break break
} }
@ -1109,7 +1114,10 @@ func (c *Bor) CommitStates(
stateSyncs = append(stateSyncs, &stateData) 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -4,7 +4,7 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
@ -55,11 +55,11 @@ func TestGenesisContractChange(t *testing.T) {
genesis := genspec.MustCommit(db) genesis := genspec.MustCommit(db)
statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil) statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil)
assert.NoError(t, err) require.NoError(t, err)
config := params.ChainConfig{} config := params.ChainConfig{}
chain, err := core.NewBlockChain(db, nil, &config, b, vm.Config{}, nil, nil) 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) { addBlock := func(root common.Hash, num int64) (common.Hash, *state.StateDB) {
h := &types.Header{ h := &types.Header{
@ -70,37 +70,37 @@ func TestGenesisContractChange(t *testing.T) {
// write state to database // write state to database
root, err := statedb.Commit(false) root, err := statedb.Commit(false)
assert.NoError(t, err) require.NoError(t, err)
assert.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil)) require.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil))
statedb, err := state.New(h.Root, state.NewDatabase(db), nil) statedb, err := state.New(h.Root, state.NewDatabase(db), nil)
assert.NoError(t, err) require.NoError(t, err)
return root, statedb return root, statedb
} }
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1}) require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
root := genesis.Root() root := genesis.Root()
// code does not change // code does not change
root, statedb = addBlock(root, 1) 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 // code changes 1st time
root, statedb = addBlock(root, 2) 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 // code same as 1st change
root, statedb = addBlock(root, 3) 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 // code changes 2nd time
_, statedb = addBlock(root, 4) _, 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 // 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) { func TestEncodeSigHeaderJaipur(t *testing.T) {
@ -124,19 +124,19 @@ func TestEncodeSigHeaderJaipur(t *testing.T) {
// Jaipur NOT enabled and BaseFee not set // Jaipur NOT enabled and BaseFee not set
hash := SealHash(h, &params.BorConfig{JaipurBlock: 10}) hash := SealHash(h, &params.BorConfig{JaipurBlock: 10})
assert.Equal(t, hash, hashWithoutBaseFee) require.Equal(t, hash, hashWithoutBaseFee)
// Jaipur enabled (Jaipur=0) and BaseFee not set // Jaipur enabled (Jaipur=0) and BaseFee not set
hash = SealHash(h, &params.BorConfig{JaipurBlock: 0}) hash = SealHash(h, &params.BorConfig{JaipurBlock: 0})
assert.Equal(t, hash, hashWithoutBaseFee) require.Equal(t, hash, hashWithoutBaseFee)
h.BaseFee = big.NewInt(2) h.BaseFee = big.NewInt(2)
// Jaipur enabled (Jaipur=Header block) and BaseFee set // Jaipur enabled (Jaipur=Header block) and BaseFee set
hash = SealHash(h, &params.BorConfig{JaipurBlock: 1}) hash = SealHash(h, &params.BorConfig{JaipurBlock: 1})
assert.Equal(t, hash, hashWithBaseFee) require.Equal(t, hash, hashWithBaseFee)
// Jaipur NOT enabled and BaseFee set // Jaipur NOT enabled and BaseFee set
hash = SealHash(h, &params.BorConfig{JaipurBlock: 10}) hash = SealHash(h, &params.BorConfig{JaipurBlock: 10})
assert.Equal(t, hash, hashWithoutBaseFee) require.Equal(t, hash, hashWithoutBaseFee)
} }

View file

@ -102,7 +102,8 @@ func (gc *GenesisContractsClient) CommitState(
func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) { func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) {
blockNr := rpc.BlockNumber(snapshotNumber) blockNr := rpc.BlockNumber(snapshotNumber)
method := "lastStateId"
const method = "lastStateId"
data, err := gc.stateReceiverABI.Pack(method) data, err := gc.stateReceiverABI.Pack(method)
if err != nil { if err != nil {

View file

@ -5,7 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io"
"net/http" "net/http"
"net/url" "net/url"
"sort" "sort"
@ -251,7 +251,7 @@ func internalFetch(ctx context.Context, client http.Client, u *url.URL) ([]byte,
} }
// get response // get response
body, err := ioutil.ReadAll(res.Body) body, err := io.ReadAll(res.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -44,7 +44,7 @@ func (c *ChainSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Has
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false) blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
// method // method
method := "getCurrentSpan" const method = "getCurrentSpan"
data, err := c.validatorSet.Pack(method) data, err := c.validatorSet.Pack(method)
if err != nil { if err != nil {

View file

@ -39,7 +39,7 @@ func convertTo32(input []byte) (output [32]byte) {
return return
} }
func convert(input []([32]byte)) [][]byte { func convert(input [][32]byte) [][]byte {
output := make([][]byte, 0, len(input)) output := make([][]byte, 0, len(input))
for _, in := range input { for _, in := range input {

View file

@ -131,7 +131,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
} }
// check if signer is in validator set // check if signer is in validator set
if !snap.ValidatorSet.HasAddress(signer.Bytes()) { if !snap.ValidatorSet.HasAddress(signer) {
return nil, &UnauthorizedSignerError{number, signer.Bytes()} 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 // 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 is empty
if signer == (common.Address{}) { if signer == (common.Address{}) {
return 1 return 1
} }
validators := s.ValidatorSet.Validators validators := validatorSet.Validators
proposer := s.ValidatorSet.GetProposer().Address proposer := validatorSet.GetProposer().Address
totalValidators := len(validators) totalValidators := len(validators)
proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer) proposerIndex, _ := validatorSet.GetByAddress(proposer)
signerIndex, _ := s.ValidatorSet.GetByAddress(signer) signerIndex, _ := validatorSet.GetByAddress(signer)
// temp index // temp index
tempIndex := signerIndex tempIndex := signerIndex

View file

@ -6,7 +6,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
"pgregory.net/rapid" "pgregory.net/rapid"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -34,7 +34,7 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
t.Fatalf("%s", err) t.Fatalf("%s", err)
} }
assert.Equal(t, 0, successionNumber) require.Equal(t, 0, successionNumber)
} }
func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) { func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
@ -60,7 +60,7 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
t.Fatalf("%s", err) t.Fatalf("%s", err)
} }
assert.Equal(t, signerIndex-proposerIndex, successionNumber) require.Equal(t, signerIndex-proposerIndex, successionNumber)
} }
func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) { func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
@ -82,7 +82,7 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
t.Fatalf("%s", err) t.Fatalf("%s", err)
} }
assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber) require.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
} }
func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) { func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
@ -93,6 +93,8 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
ValidatorSet: valset.NewValidatorSet(validators), ValidatorSet: valset.NewValidatorSet(validators),
} }
require.Len(t, snap.ValidatorSet.Validators, numVals)
dummyProposerAddress := randomAddress() dummyProposerAddress := randomAddress()
snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress} snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress}
@ -100,11 +102,11 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
signer := snap.ValidatorSet.Validators[3].Address signer := snap.ValidatorSet.Validators[3].Address
_, err := snap.GetSignerSuccessionNumber(signer) _, err := snap.GetSignerSuccessionNumber(signer)
assert.NotNil(t, err) require.NotNil(t, err)
e, ok := err.(*UnauthorizedProposerError) e, ok := err.(*UnauthorizedProposerError)
assert.True(t, ok) require.True(t, ok)
assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer) require.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
} }
func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) { func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
@ -116,10 +118,10 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
} }
dummySignerAddress := randomAddress() dummySignerAddress := randomAddress()
_, err := snap.GetSignerSuccessionNumber(dummySignerAddress) _, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
assert.NotNil(t, err) require.NotNil(t, err)
e, ok := err.(*UnauthorizedSignerError) e, ok := err.(*UnauthorizedSignerError)
assert.True(t, ok) require.True(t, ok)
assert.Equal(t, dummySignerAddress.Bytes(), e.Signer) require.Equal(t, dummySignerAddress.Bytes(), e.Signer)
} }
// nolint: unparam // nolint: unparam

View file

@ -47,21 +47,26 @@ func (v *Validator) Cmp(other *Validator) *Validator {
return v return v
} }
// nolint:nestif
if v.ProposerPriority > other.ProposerPriority { if v.ProposerPriority > other.ProposerPriority {
return v return v
} else if v.ProposerPriority < other.ProposerPriority {
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 { func (v *Validator) String() string {

View file

@ -46,6 +46,7 @@ type ValidatorSet struct {
// cached (unexported) // cached (unexported)
totalVotingPower int64 totalVotingPower int64
validatorsMap map[common.Address]int // address -> index
} }
// NewValidatorSet initializes a ValidatorSet by copying over the // 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 // The addresses of validators in `valz` must be unique otherwise the
// function panics. // function panics.
func NewValidatorSet(valz []*Validator) *ValidatorSet { func NewValidatorSet(valz []*Validator) *ValidatorSet {
vals := &ValidatorSet{} vals := &ValidatorSet{validatorsMap: make(map[common.Address]int)}
err := vals.updateWithChangeSet(valz, false) err := vals.updateWithChangeSet(valz, false)
if err != nil { if err != nil {
@ -232,30 +233,34 @@ func validatorListCopy(valsList []*Validator) []*Validator {
// Copy each validator into a new ValidatorSet. // Copy each validator into a new ValidatorSet.
func (vals *ValidatorSet) Copy() *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{ return &ValidatorSet{
Validators: validatorListCopy(vals.Validators), Validators: validatorListCopy(vals.Validators),
Proposer: vals.Proposer, Proposer: vals.Proposer,
totalVotingPower: vals.totalVotingPower, totalVotingPower: vals.totalVotingPower,
validatorsMap: validatorsMap,
} }
} }
// HasAddress returns true if address given is in the validator set, false - // HasAddress returns true if address given is in the validator set, false -
// otherwise. // otherwise.
func (vals *ValidatorSet) HasAddress(address []byte) bool { func (vals *ValidatorSet) HasAddress(address common.Address) bool {
idx := sort.Search(len(vals.Validators), func(i int) bool { _, ok := vals.validatorsMap[address]
return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0
})
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 // GetByAddress returns an index of the validator with address and validator
// itself if found. Otherwise, -1 and nil are returned. // itself if found. Otherwise, -1 and nil are returned.
func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *Validator) { func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *Validator) {
idx := sort.Search(len(vals.Validators), func(i int) bool { idx, ok := vals.validatorsMap[address]
return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0 if ok {
})
if idx < len(vals.Validators) && vals.Validators[idx].Address == address {
return idx, vals.Validators[idx].Copy() 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. // 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 // It returns nil values if index is less than 0 or greater or equal to
// len(ValidatorSet.Validators). // 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) { if index < 0 || index >= len(vals.Validators) {
return nil, nil return common.Address{}, nil
} }
val = vals.Validators[index] val = vals.Validators[index]
return val.Address.Bytes(), val.Copy() return val.Address, val.Copy()
} }
// Size returns the length of the validator set. // Size returns the length of the validator set.
@ -328,7 +333,7 @@ func (vals *ValidatorSet) GetProposer() (proposer *Validator) {
func (vals *ValidatorSet) findProposer() *Validator { func (vals *ValidatorSet) findProposer() *Validator {
var proposer *Validator var proposer *Validator
for _, val := range vals.Validators { 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) proposer = proposer.Cmp(val)
} }
} }
@ -371,14 +376,19 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
changes := validatorListCopy(origChanges) changes := validatorListCopy(origChanges)
sort.Sort(ValidatorsByAddress(changes)) sort.Sort(ValidatorsByAddress(changes))
removals = make([]*Validator, 0, len(changes)) sliceCap := len(changes) / 2
updates = make([]*Validator, 0, len(changes)) if sliceCap == 0 {
sliceCap = 1
}
removals = make([]*Validator, 0, sliceCap)
updates = make([]*Validator, 0, sliceCap)
var prevAddr common.Address var prevAddr common.Address
// Scan changes by address and append valid validators to updates or removals lists. // Scan changes by address and append valid validators to updates or removals lists.
for _, valUpdate := range changes { 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) err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes)
return nil, nil, err return nil, nil, err
} }
@ -489,10 +499,11 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
} else { } else {
// Apply add or update. // Apply add or update.
merged[i] = updates[0] 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. // Validator is present in both, advance existing.
existing = existing[1:] existing = existing[1:]
} }
updates = updates[1:] updates = updates[1:]
} }
i++ i++
@ -503,6 +514,7 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
merged[i] = existing[j] merged[i] = existing[j]
i++ i++
} }
// OR add updates which are left. // OR add updates which are left.
for j := 0; j < len(updates); j++ { for j := 0; j < len(updates); j++ {
merged[i] = 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. // Loop over deletes until we removed all of them.
for len(deletes) > 0 { 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:] deletes = deletes[1:]
} else { // Leave it in the resulting slice. } else { // Leave it in the resulting slice.
merged[i] = existing[0] merged[i] = existing[0]
@ -599,8 +611,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
computeNewPriorities(updates, vals, updatedTotalVotingPower) computeNewPriorities(updates, vals, updatedTotalVotingPower)
// Apply updates and removals. // Apply updates and removals.
vals.applyUpdates(updates) vals.updateValidators(updates, deletes)
vals.applyRemovals(deletes)
if err := vals.UpdateTotalVotingPower(); err != nil { if err := vals.UpdateTotalVotingPower(); err != nil {
return err return err
@ -613,6 +624,17 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
return nil 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'. // UpdateWithChangeSet attempts to update the validator set with 'changes'.
// It performs the following steps: // It performs the following steps:
// - validates the changes making sure there are no duplicates and splits them in updates and deletes // - 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" return "nil-ValidatorSet"
} }
var valStrings []string valStrings := make([]string, 0, len(vals.Validators))
vals.Iterate(func(index int, val *Validator) bool { vals.Iterate(func(index int, val *Validator) bool {
valStrings = append(valStrings, val.String()) valStrings = append(valStrings, val.String())

View file

@ -3,14 +3,16 @@ package valset
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
"gotest.tools/assert"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"gotest.tools/assert"
) )
func NewValidatorFromKey(key string, votingPower int64) *Validator { func NewValidatorFromKey(key string, votingPower int64) *Validator {
privKey, _ := crypto.HexToECDSA(key) privKey, _ := crypto.HexToECDSA(key)
return NewValidator(crypto.PubkeyToAddress(privKey.PublicKey), votingPower) return NewValidator(crypto.PubkeyToAddress(privKey.PublicKey), votingPower)
} }
@ -50,7 +52,7 @@ func TestIncrementProposerPriority(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
valSet.IncrementProposerPriority(1) 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 // Validator set length = 2
@ -61,7 +63,7 @@ func TestIncrementProposerPriority(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
valSet.IncrementProposerPriority(1) 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 // Validator set length = 3
@ -72,7 +74,7 @@ func TestIncrementProposerPriority(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
valSet.IncrementProposerPriority(1) 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 // Validator set length = 4
@ -83,7 +85,7 @@ func TestIncrementProposerPriority(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
valSet.IncrementProposerPriority(1) 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} expectedPriorities := []int64{0}
for i, val := range valSet.Validators { for i, val := range valSet.Validators {
assert.Equal(t, expectedPriorities[i], val.ProposerPriority) require.Equal(t, expectedPriorities[i], val.ProposerPriority)
} }
// Validator set length = 2 // Validator set length = 2
@ -110,7 +112,7 @@ func TestRescalePriorities(t *testing.T) {
expectedPriorities = []int64{50, -50} expectedPriorities = []int64{50, -50}
for i, val := range valSet.Validators { for i, val := range valSet.Validators {
assert.Equal(t, expectedPriorities[i], val.ProposerPriority) require.Equal(t, expectedPriorities[i], val.ProposerPriority)
} }
// Validator set length = 3 // Validator set length = 3
@ -121,7 +123,7 @@ func TestRescalePriorities(t *testing.T) {
expectedPriorities = []int64{-17, 5, 11} expectedPriorities = []int64{-17, 5, 11}
for i, val := range valSet.Validators { for i, val := range valSet.Validators {
assert.Equal(t, expectedPriorities[i], val.ProposerPriority) require.Equal(t, expectedPriorities[i], val.ProposerPriority)
} }
// Validator set length = 4 // Validator set length = 4
@ -132,7 +134,7 @@ func TestRescalePriorities(t *testing.T) {
expectedPriorities = []int64{-6, 3, 1, 2} expectedPriorities = []int64{-6, 3, 1, 2}
for i, val := range valSet.Validators { 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, valByIndex)
assert.DeepEqual(t, val, valByAddress) assert.DeepEqual(t, val, valByAddress)
assert.DeepEqual(t, val.Address, common.BytesToAddress(addr)) assert.DeepEqual(t, val.Address, addr)
} }
tempAddress := common.HexToAddress("0x12345") tempAddress := common.HexToAddress("0x12345")
// Negative Testcase // Negative Testcase
idx, _ := valSet.GetByAddress(tempAddress) idx, _ := valSet.GetByAddress(tempAddress)
assert.Equal(t, idx, -1) require.Equal(t, idx, -1)
// checking for validator index out of range // checking for validator index out of range
addr, _ := valSet.GetByIndex(100) addr, _ := valSet.GetByIndex(100)
assert.Equal(t, common.BytesToAddress(addr), common.Address{}) require.Equal(t, addr, common.Address{})
} }
func TestUpdateWithChangeSet(t *testing.T) { func TestUpdateWithChangeSet(t *testing.T) {
@ -169,28 +171,29 @@ func TestUpdateWithChangeSet(t *testing.T) {
valSet := NewValidatorSet(vals[:4]) valSet := NewValidatorSet(vals[:4])
// halved the power of vals[2] and doubled the power of vals[3] // halved the power of vals[2] and doubled the power of vals[3]
val2 := NewValidatorFromKey("c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd7", 150) // signer2 vals[2].VotingPower = 150
val3 := NewValidatorFromKey("c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd6", 800) // signer3 vals[3].VotingPower = 800
// Adding new temp validator in the set // Adding new temp validator in the set
tempSigner := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd5" const tempSigner = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd5"
tempVal := NewValidatorFromKey(tempSigner, 250) tempVal := NewValidatorFromKey(tempSigner, 250)
// check totalVotingPower before updating validator set // 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}) err := valSet.UpdateWithChangeSet([]*Validator{vals[2], vals[3], tempVal})
assert.NilError(t, err) require.NoError(t, err)
// check totalVotingPower after updating validator set // 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) _, 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) _, 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) _, updatedTempVal := valSet.GetByAddress(tempVal.Address)
assert.Equal(t, int64(250), updatedTempVal.VotingPower) require.Equal(t, int64(250), updatedTempVal.VotingPower)
} }

View file

@ -18,7 +18,11 @@ var (
getDerivedBorTxHash = types.GetDerivedBorTxHash getDerivedBorTxHash = types.GetDerivedBorTxHash
// borTxLookupPrefix + hash -> transaction/receipt lookup metadata // 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 indicates the name of the freezer bor receipts table.
freezerBorReceiptTable = "matic-bor-receipts" freezerBorReceiptTable = "matic-bor-receipts"

View file

@ -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 // CreateAccount is called during the EVM CREATE operation. The situation might arise that
// a contract does the following: // a contract does the following:
// //
// 1. sends funds to sha(account ++ (nonce + 1)) // 1. sends funds to sha(account ++ (nonce + 1))
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 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. // Carrying over the balance ensures that Ether doesn't disappear.
func (s *StateDB) CreateAccount(addr common.Address) { func (s *StateDB) CreateAccount(addr common.Address) {

View file

@ -5,7 +5,7 @@ import (
"math/big" "math/big"
"testing" "testing"
"gotest.tools/assert" "github.com/stretchr/testify/require"
"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"
@ -28,11 +28,11 @@ func TestWhitelistCheckpoint(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
s.enqueueCheckpointWhitelist(uint64(i), common.Hash{}) 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.enqueueCheckpointWhitelist(11, common.Hash{})
s.dequeueCheckpointWhitelist() 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 // 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 // case1: no checkpoint whitelist, should consider the chain as valid
res, err := s.IsValidChain(nil, nil) res, err := s.IsValidChain(nil, nil)
assert.NilError(t, err, "expected no error") require.NoError(t, err, "expected no error")
assert.Equal(t, res, true, "expected chain to be valid") require.Equal(t, res, true, "expected chain to be valid")
// add checkpoint entries and mock fetchHeadersByNumber function // add checkpoint entries and mock fetchHeadersByNumber function
s.ProcessCheckpoint(uint64(0), common.Hash{}) s.ProcessCheckpoint(uint64(0), common.Hash{})
s.ProcessCheckpoint(uint64(1), 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 // create a false function, returning absolutely nothing
falseFetchHeadersByNumber := func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error) { 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) 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 // case3: correct fetchHeadersByNumber function provided, should consider the chain as valid
// create a mock function, returning a the required header // create a mock function, returning a the required header
@ -92,16 +92,16 @@ func TestIsValidChain(t *testing.T) {
} }
res, err = s.IsValidChain(nil, fetchHeadersByNumber) res, err = s.IsValidChain(nil, fetchHeadersByNumber)
assert.NilError(t, err, "expected no error") require.NoError(t, err, "expected no error")
assert.Equal(t, res, true, "expected chain to be valid") require.Equal(t, res, true, "expected chain to be valid")
// add one more checkpoint whitelist entry // add one more checkpoint whitelist entry
s.ProcessCheckpoint(uint64(2), common.Hash{}) 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 // case4: correct fetchHeadersByNumber function provided with wrong header
// for block number 2. Should consider the chain as invalid and throw an error // for block number 2. Should consider the chain as invalid and throw an error
res, err = s.IsValidChain(nil, fetchHeadersByNumber) res, err = s.IsValidChain(nil, fetchHeadersByNumber)
assert.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error") require.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error")
assert.Equal(t, res, false, "expected chain to be invalid") require.Equal(t, res, false, "expected chain to be invalid")
} }

View file

@ -59,8 +59,9 @@ func (api *PublicFilterAPI) NewDeposits(ctx context.Context, crit ethereum.State
} }
rpcSub := notifier.CreateSubscription() rpcSub := notifier.CreateSubscription()
go func() { go func() {
stateSyncData := make(chan *types.StateSyncData) stateSyncData := make(chan *types.StateSyncData, 10)
stateSyncSub := api.events.SubscribeNewDeposits(stateSyncData) stateSyncSub := api.events.SubscribeNewDeposits(stateSyncData)
for { for {

View file

@ -4,7 +4,6 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"os/signal" "os/signal"
@ -162,7 +161,7 @@ func (b *BootnodeCommand) Run(args []string) int {
} }
// save the public key // save the public key
pubRaw := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:]) pubRaw := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:])
if err := ioutil.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 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)) b.UI.Error(fmt.Sprintf("failed to write node pub key: %v", err))
return 1 return 1
} }

View file

@ -8,7 +8,7 @@ import (
"time" "time"
"github.com/mitchellh/cli" "github.com/mitchellh/cli"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/internal/cli/server" "github.com/ethereum/go-ethereum/internal/cli/server"
) )
@ -30,7 +30,7 @@ func TestCommand_DebugBlock(t *testing.T) {
// start the mock server // start the mock server
srv, err := server.CreateMockServer(config) srv, err := server.CreateMockServer(config)
assert.NoError(t, err) require.NoError(t, err)
defer server.CloseMockServer(srv) defer server.CloseMockServer(srv)
@ -53,7 +53,7 @@ func TestCommand_DebugBlock(t *testing.T) {
start := time.Now() start := time.Now()
dst1 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json") dst1 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json")
res := traceBlock(port, 1, output) 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) 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 // adding this to avoid debug directory name conflicts
@ -64,14 +64,14 @@ func TestCommand_DebugBlock(t *testing.T) {
latestBlock := srv.GetLatestBlockNumber().Int64() latestBlock := srv.GetLatestBlockNumber().Int64()
dst2 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json") dst2 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json")
res = traceBlock(port, latestBlock, output) 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) 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 // verify if the trace files are created
done := verify(dst1) done := verify(dst1)
assert.Equal(t, true, done) require.Equal(t, true, done)
done = verify(dst2) done = verify(dst2)
assert.Equal(t, true, done) require.Equal(t, true, done)
// delete the traces // delete the traces
deleteTraces(output) deleteTraces(output)

View file

@ -3,12 +3,12 @@ package cli
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
) )
func TestCodeBlock(t *testing.T) { func TestCodeBlock(t *testing.T) {
t.Parallel() t.Parallel()
assert := assert.New(t) assert := require.New(t)
lines := []string{ lines := []string{
"abc", "abc",

View file

@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -50,7 +49,7 @@ func GetChain(name string) (*Chain, error) {
} }
func ImportFromFile(filename string) (*Chain, error) { func ImportFromFile(filename string) (*Chain, error) {
data, err := ioutil.ReadFile(filename) data, err := os.ReadFile(filename)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -2,7 +2,6 @@ package server
import ( import (
"fmt" "fmt"
"io/ioutil"
"math/rand" "math/rand"
"net" "net"
"os" "os"
@ -55,7 +54,7 @@ func CreateMockServer(config *Config) (*Server, error) {
config.GRPC.Addr = fmt.Sprintf(":%d", port) config.GRPC.Addr = fmt.Sprintf(":%d", port)
// datadir // datadir
datadir, _ := ioutil.TempDir("/tmp", "bor-cli-test") datadir, _ := os.MkdirTemp("/tmp", "bor-cli-test")
config.DataDir = datadir config.DataDir = datadir
// find available port for http server // find available port for http server

View file

@ -25,6 +25,8 @@ import (
"time" "time"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/tyler-smith/go-bip39"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
@ -47,7 +49,6 @@ 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/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/tyler-smith/go-bip39"
) )
// PublicEthereumAPI provides an API to access Ethereum related information. // 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. // GetBlockByNumber returns the requested canonical block.
// * When blockNr is -1 the chain head is returned. // - When blockNr is -1 the chain head is returned.
// * When blockNr is -2 the pending 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 // - When fullTx is true all transactions in the block are returned, otherwise
// only the transaction hash is returned. // only the transaction hash is returned.
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
block, err := s.b.BlockByNumber(ctx, number) block, err := s.b.BlockByNumber(ctx, number)
if block != nil && err == nil { if block != nil && err == nil {

168
tests/bor/bor_api_test.go Normal file
View 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)
}
}
}

View file

@ -11,14 +11,15 @@ import (
"time" "time"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
"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"
"github.com/ethereum/go-ethereum/consensus/bor/clerk" "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/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/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"
@ -38,11 +39,11 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
defer _bor.Close() defer _bor.Close()
h, heimdallSpan, ctrl := getMockedHeimdallClient(t)
defer ctrl.Finish()
_, currentSpan := loadSpanFromFile(t) _, currentSpan := loadSpanFromFile(t)
h, ctrl := getMockedHeimdallClient(t, currentSpan)
defer ctrl.Finish()
h.EXPECT().Close().AnyTimes() h.EXPECT().Close().AnyTimes()
h.EXPECT().FetchLatestCheckpoint(gomock.Any()).Return(&checkpoint.Checkpoint{ h.EXPECT().FetchLatestCheckpoint(gomock.Any()).Return(&checkpoint.Checkpoint{
Proposer: currentSpan.SelectedProducers[0].Address, Proposer: currentSpan.SelectedProducers[0].Address,
@ -56,9 +57,11 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
block := init.genesis.ToBlock(db) block := init.genesis.ToBlock(db)
// to := int64(block.Header().Time) // 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 // Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
for i := uint64(1); i <= spanSize; i++ { 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) insertNewBlock(t, chain, block)
} }
@ -67,10 +70,10 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
t.Fatalf("%s", err) t.Fatalf("%s", err)
} }
assert.Equal(t, 3, len(validators)) require.Equal(t, 3, len(validators))
for i, validator := range validators { for i, validator := range validators {
assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes()) require.Equal(t, validator.Address.Bytes(), currentSpan.SelectedProducers[i].Address.Bytes())
assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower) require.Equal(t, validator.VotingPower, currentSpan.SelectedProducers[i].VotingPower)
} }
} }
@ -85,16 +88,23 @@ func TestFetchStateSyncEvents(t *testing.T) {
// A. Insert blocks for 0th sprint // A. Insert blocks for 0th sprint
db := init.ethereum.ChainDb() db := init.ethereum.ChainDb()
block := init.genesis.ToBlock(db) 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 // Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
for i := uint64(1); i < sprintSize; i++ { 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) insertNewBlock(t, chain, block)
} }
// 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
res, _ := loadSpanFromFile(t)
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
@ -115,7 +125,7 @@ func TestFetchStateSyncEvents(t *testing.T) {
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes() h.EXPECT().StateSyncEvents(gomock.Any(), 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, nil, res.Result.ValidatorSet.Validators)
insertNewBlock(t, chain, block) insertNewBlock(t, chain, block)
} }
@ -130,6 +140,9 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
// Mock /bor/span/1 // Mock /bor/span/1
res, _ := loadSpanFromFile(t) res, _ := loadSpanFromFile(t)
// add the block producer
res.Result.ValidatorSet.Validators = append(res.Result.ValidatorSet.Validators, valset.NewValidator(addr, 4500))
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
@ -160,15 +173,24 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
// Insert blocks for 0th sprint // Insert blocks for 0th sprint
db := init.ethereum.ChainDb() db := init.ethereum.ChainDb()
block := init.genesis.ToBlock(db) block := init.genesis.ToBlock(db)
var currentValidators []*valset.Validator
for i := uint64(1); i <= sprintSize; i++ { 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) insertNewBlock(t, chain, block)
} }
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()) require.Equal(t, uint64(4), lastStateID.Uint64())
// //
fromID = uint64(5) fromID = uint64(5)
@ -181,12 +203,18 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes() h.EXPECT().StateSyncEvents(gomock.Any(), 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) 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) insertNewBlock(t, chain, block)
} }
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize) lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
assert.Equal(t, uint64(6), lastStateID.Uint64()) require.Equal(t, uint64(6), lastStateID.Uint64())
} }
func TestOutOfTurnSigning(t *testing.T) { func TestOutOfTurnSigning(t *testing.T) {
@ -197,17 +225,29 @@ func TestOutOfTurnSigning(t *testing.T) {
defer _bor.Close() 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() defer ctrl.Finish()
h.EXPECT().Close().AnyTimes() h.EXPECT().Close().AnyTimes()
_bor.SetHeimdallClient(h) _bor.SetHeimdallClient(h)
db := init.ethereum.ChainDb() db := init.ethereum.ChainDb()
block := init.genesis.ToBlock(db) 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++ { 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) 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 // This account is one the out-of-turn validators for 1st (0-indexed) span
signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9" signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
signerKey, _ := hex.DecodeString(signer) signerKey, _ := hex.DecodeString(signer)
key, _ = crypto.HexToECDSA(signer) newKey, _ := crypto.HexToECDSA(signer)
addr = crypto.PubkeyToAddress(key.PublicKey) newAddr := crypto.PubkeyToAddress(newKey.PublicKey)
expectedSuccessionNumber := 2 expectedSuccessionNumber := 2
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor) parentTime := block.Time()
_, err := chain.InsertChain([]*types.Block{block})
assert.Equal(t,
*err.(*bor.BlockTooSoonError),
bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber})
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 := block.Header()
header.Time += bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) - diff := bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor)
bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor) header.Time += diff
sign(t, header, signerKey, init.genesis.Config.Bor) sign(t, header, signerKey, init.genesis.Config.Bor)
block = types.NewBlockWithHeader(header) block = types.NewBlockWithHeader(header)
_, err = chain.InsertChain([]*types.Block{block}) _, err = chain.InsertChain([]*types.Block{block})
assert.Equal(t, require.NotNil(t, err)
*err.(*bor.WrongDifficultyError), require.Equal(t,
bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()}) bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: newAddr.Bytes()},
*err.(*bor.WrongDifficultyError))
header.Difficulty = new(big.Int).SetUint64(expectedDifficulty) header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
sign(t, header, signerKey, init.genesis.Config.Bor) sign(t, header, signerKey, init.genesis.Config.Bor)
block = types.NewBlockWithHeader(header) block = types.NewBlockWithHeader(header)
_, err = chain.InsertChain([]*types.Block{block}) _, err = chain.InsertChain([]*types.Block{block})
assert.Nil(t, err) require.Nil(t, err)
} }
func TestSignerNotFound(t *testing.T) { func TestSignerNotFound(t *testing.T) {
@ -255,7 +309,9 @@ func TestSignerNotFound(t *testing.T) {
defer _bor.Close() defer _bor.Close()
h, _, ctrl := getMockedHeimdallClient(t) _, heimdallSpan := loadSpanFromFile(t)
h, ctrl := getMockedHeimdallClient(t, heimdallSpan)
defer ctrl.Finish() defer ctrl.Finish()
h.EXPECT().Close().AnyTimes() h.EXPECT().Close().AnyTimes()
@ -266,62 +322,21 @@ func TestSignerNotFound(t *testing.T) {
block := init.genesis.ToBlock(db) block := init.genesis.ToBlock(db)
// random signer account that is not a part of the validator set // random signer account that is not a part of the validator set
signer := "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b" const signer = "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b"
signerKey, _ := hex.DecodeString(signer) signerKey, _ := hex.DecodeString(signer)
key, _ = crypto.HexToECDSA(signer) newKey, _ := crypto.HexToECDSA(signer)
addr = crypto.PubkeyToAddress(key.PublicKey) 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}) _, err := chain.InsertChain([]*types.Block{block})
assert.Equal(t, require.Equal(t,
*err.(*bor.UnauthorizedSignerError), *err.(*bor.UnauthorizedSignerError),
bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()}) bor.UnauthorizedSignerError{Number: 0, Signer: newAddr.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
} }
// TestEIP1559Transition tests the following: // TestEIP1559Transition tests the following:
@ -351,7 +366,7 @@ func TestEIP1559Transition(t *testing.T) {
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
gspec = &core.Genesis{ gspec = &core.Genesis{
Config: params.BorTestChainConfig, Config: params.BorUnittestChainConfig,
Alloc: core.GenesisAlloc{ Alloc: core.GenesisAlloc{
addr1: {Balance: funds}, addr1: {Balance: funds},
addr2: {Balance: funds}, addr2: {Balance: funds},
@ -433,7 +448,7 @@ func TestEIP1559Transition(t *testing.T) {
} }
// check burnt contract balance // 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()) expected = new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee())
burntContractBalance := expected burntContractBalance := expected
if actual.Cmp(expected) != 0 { if actual.Cmp(expected) != 0 {
@ -481,7 +496,7 @@ func TestEIP1559Transition(t *testing.T) {
} }
// check burnt contract balance // 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())) expected = new(big.Int).Add(burntContractBalance, new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee()))
burntContractBalance = expected burntContractBalance = expected
if actual.Cmp(expected) != 0 { if actual.Cmp(expected) != 0 {
@ -539,7 +554,7 @@ func TestEIP1559Transition(t *testing.T) {
state, _ = chain.State() state, _ = chain.State()
// check burnt contract balance // 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( burntAmount := new(big.Int).Mul(
block.BaseFee(), block.BaseFee(),
big.NewInt(int64(block.GasUsed())), big.NewInt(int64(block.GasUsed())),
@ -550,25 +565,188 @@ func TestEIP1559Transition(t *testing.T) {
} }
} }
func newGwei(n int64) *big.Int { // EIP1559 is not supported without EIP155. An error is expected
return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei)) 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) { func TestJaipurFork(t *testing.T) {
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
chain := init.ethereum.BlockChain() chain := init.ethereum.BlockChain()
engine := init.ethereum.Engine() engine := init.ethereum.Engine()
_bor := engine.(*bor.Bor) _bor := engine.(*bor.Bor)
defer _bor.Close()
db := init.ethereum.ChainDb() db := init.ethereum.ChainDb()
block := init.genesis.ToBlock(db) block := init.genesis.ToBlock(db)
res, _ := loadSpanFromFile(t)
for i := uint64(1); i < sprintSize; i++ { 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) insertNewBlock(t, chain, block)
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock-1 { 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 { 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))
} }
} }
} }

View file

@ -1,46 +1,63 @@
//go:build integration
package bor package bor
import ( import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"sort" "sort"
"testing" "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/cmd/utils"
"github.com/ethereum/go-ethereum/common" "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"
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
"github.com/ethereum/go-ethereum/consensus/bor/heimdall" "github.com/ethereum/go-ethereum/consensus/bor/heimdall"
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
"github.com/ethereum/go-ethereum/consensus/bor/valset" "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/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/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/tests/bor/mocks"
) )
var ( 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 // The genesis for tests was generated with following parameters
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
// Only this account is a validator for the 0th span sprintSize uint64 = 4
privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" spanSize uint64 = 8
key, _ = crypto.HexToECDSA(privKey)
addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7
// This account is one the validators for 1st span (0-indexed) validatorHeaderBytesLength = common.AddressLength + 20 // address + power
privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
key2, _ = crypto.HexToECDSA(privKey2)
addr2 = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
sprintSize uint64 = 4
spanSize uint64 = 8
) )
type initializeData struct { type initializeData struct {
@ -49,8 +66,6 @@ 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)
@ -64,6 +79,7 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
ethConf := &eth.Config{ ethConf := &eth.Config{
Genesis: gen, Genesis: gen,
BorLogs: true,
} }
ethConf.Genesis.MustCommit(db) ethConf.Genesis.MustCommit(db)
@ -75,6 +91,10 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
ethConf.Genesis.MustCommit(ethereum.ChainDb()) 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{ return &initializeData{
genesis: gen, genesis: gen,
ethereum: ethereum, 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() t.Helper()
header := block.Header() header := &types.Header{
header.Number.Add(header.Number, big.NewInt(1)) 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() number := header.Number.Uint64()
if signer == nil { if signer == nil {
signer = getSignerKey(header.Number.Uint64()) signer = getSignerKey(header.Number.Uint64())
} }
header.ParentHash = block.Hash() header.Time = parentBlock.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 := []*valset.Validator{valset.NewValidator(addr, 10)} isSpanStart := IsSpanStart(number)
isSprintEnd := IsSprintEnd(number)
isSpanEnd := (number+1)%spanSize == 0 if isSpanStart {
isSpanStart := number%spanSize == 0 header.Difficulty = new(big.Int).SetInt64(int64(len(currentValidators)))
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 isSprintEnd { if isSprintEnd {
@ -132,27 +150,87 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *
} }
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(), parentBlock.Header())
if !chain.Config().IsLondon(block.Number()) { if !chain.Config().IsLondon(parentBlock.Number()) {
parentGasLimit := block.GasLimit() * params.ElasticityMultiplier parentGasLimit := parentBlock.GasLimit() * params.ElasticityMultiplier
header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit) header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit)
} }
} }
for _, opt := range opts {
opt(header)
}
state, err := chain.State() state, err := chain.State()
if err != nil { if err != nil {
t.Fatalf("%s", err) t.Fatalf("%s", err)
} }
_, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil) b := &blockGen{header: header}
if err != nil { for _, tx := range txs {
t.Fatalf("%s", err) 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) { 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 { func getSignerKey(number uint64) []byte {
signerKey := privKey signerKey := privKey
isSpanStart := number%spanSize == 0 if IsSpanStart(number) {
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) 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
} }

View file

@ -52,6 +52,9 @@
}, },
"71562b71999873DB5b286dF957af199Ec94617F7": { "71562b71999873DB5b286dF957af199Ec94617F7": {
"balance": "0x3635c9adc5dea00000" "balance": "0x3635c9adc5dea00000"
},
"9fB29AAc15b9A4B7F17c3385939b007540f4d791": {
"balance": "0x3635c9adc5dea00000"
} }
}, },
"number": "0x0", "number": "0x0",