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"
"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 (

View file

@ -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
}

View file

@ -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, &params.BorConfig{JaipurBlock: 10})
assert.Equal(t, hash, hashWithoutBaseFee)
require.Equal(t, hash, hashWithoutBaseFee)
// Jaipur enabled (Jaipur=0) and BaseFee not set
hash = SealHash(h, &params.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, &params.BorConfig{JaipurBlock: 1})
assert.Equal(t, hash, hashWithBaseFee)
require.Equal(t, hash, hashWithBaseFee)
// Jaipur NOT enabled and BaseFee set
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) {
blockNr := rpc.BlockNumber(snapshotNumber)
method := "lastStateId"
const method = "lastStateId"
data, err := gc.stateReceiverABI.Pack(method)
if err != nil {

View file

@ -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
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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())

View file

@ -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)
}

View file

@ -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"

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
// 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) {

View file

@ -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")
}

View file

@ -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 {

View file

@ -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
}

View file

@ -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)

View file

@ -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",

View file

@ -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
}

View file

@ -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

View file

@ -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
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"
"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))
}
}
}

View file

@ -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 := &eth.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
}

View file

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