mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-16 17:03:46 +00:00
Reciept e2e test (#431)
* initial * fixed tests * eip155 tests * progress * fix * fix TestFetchStateSyncEvents* * debug * fixed with updated list of validators * fix * a bit more stable * optimize allocations * linters * fix vals copy * a bit of refactoring * update TestGetTransactionReceiptsByBlock * remove logs from TestGetTransactionReceiptsByBlock in favour of checks * comments * Linters * linters * fixes after merge * fixes after merge * fixes after merge * fixes after merge * fail fast Co-authored-by: Evgeny Danienko <6655321@bk.ru>
This commit is contained in:
parent
1147994c65
commit
7b25997830
26 changed files with 820 additions and 281 deletions
|
|
@ -5,11 +5,12 @@ import (
|
||||||
"io/ioutil"
|
"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 (
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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, ¶ms.BorConfig{JaipurBlock: 10})
|
hash := SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
||||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
require.Equal(t, hash, hashWithoutBaseFee)
|
||||||
|
|
||||||
// Jaipur enabled (Jaipur=0) and BaseFee not set
|
// Jaipur enabled (Jaipur=0) and BaseFee not set
|
||||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 0})
|
hash = SealHash(h, ¶ms.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, ¶ms.BorConfig{JaipurBlock: 1})
|
hash = SealHash(h, ¶ms.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, ¶ms.BorConfig{JaipurBlock: 10})
|
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
||||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
require.Equal(t, hash, hashWithoutBaseFee)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,8 @@ func (gc *GenesisContractsClient) CommitState(
|
||||||
|
|
||||||
func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) {
|
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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
168
tests/bor/bor_api_test.go
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package bor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetTransactionReceiptsByBlock(t *testing.T) {
|
||||||
|
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
||||||
|
chain := init.ethereum.BlockChain()
|
||||||
|
engine := init.ethereum.Engine()
|
||||||
|
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
|
||||||
|
_bor := engine.(*bor.Bor)
|
||||||
|
defer _bor.Close()
|
||||||
|
|
||||||
|
// Mock /bor/span/1
|
||||||
|
res, _ := loadSpanFromFile(t)
|
||||||
|
|
||||||
|
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||||
|
|
||||||
|
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(&res.Result, nil).MinTimes(1)
|
||||||
|
h.EXPECT().Close().MinTimes(1)
|
||||||
|
h.EXPECT().FetchLatestCheckpoint(gomock.Any()).Return(&checkpoint.Checkpoint{
|
||||||
|
Proposer: res.Result.SelectedProducers[0].Address,
|
||||||
|
StartBlock: big.NewInt(0),
|
||||||
|
EndBlock: big.NewInt(int64(spanSize)),
|
||||||
|
}, nil).AnyTimes()
|
||||||
|
|
||||||
|
// Mock State Sync events
|
||||||
|
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
||||||
|
fromID := uint64(1)
|
||||||
|
to := int64(chain.GetHeaderByNumber(0).Time)
|
||||||
|
sample := getSampleEventRecord(t)
|
||||||
|
|
||||||
|
// First query will be from [id=1, (block-sprint).Time]
|
||||||
|
eventRecords := []*clerk.EventRecordWithTime{
|
||||||
|
buildStateEvent(sample, 1, 1),
|
||||||
|
buildStateEvent(sample, 2, 2),
|
||||||
|
buildStateEvent(sample, 3, 3),
|
||||||
|
}
|
||||||
|
|
||||||
|
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).MinTimes(1)
|
||||||
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
|
// Insert blocks for 0th sprint
|
||||||
|
db := init.ethereum.ChainDb()
|
||||||
|
block := init.genesis.ToBlock(db)
|
||||||
|
|
||||||
|
signer := types.LatestSigner(init.genesis.Config)
|
||||||
|
toAddress := common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||||
|
|
||||||
|
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||||
|
txHashes := map[int]common.Hash{} // blockNumber -> txHash
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
nonce uint64
|
||||||
|
tx *types.Transaction
|
||||||
|
txs []*types.Transaction
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := uint64(1); i <= sprintSize; i++ {
|
||||||
|
if IsSpanEnd(i) {
|
||||||
|
currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i%3 == 0 {
|
||||||
|
txdata := &types.LegacyTx{
|
||||||
|
Nonce: nonce,
|
||||||
|
To: &toAddress,
|
||||||
|
Gas: 30000,
|
||||||
|
GasPrice: newGwei(5),
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce++
|
||||||
|
|
||||||
|
tx = types.NewTx(txdata)
|
||||||
|
tx, err = types.SignTx(tx, signer, key)
|
||||||
|
require.Nil(t, err, "an incorrect transaction or signer")
|
||||||
|
|
||||||
|
txs = []*types.Transaction{tx}
|
||||||
|
} else {
|
||||||
|
txs = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, txs, currentValidators)
|
||||||
|
insertNewBlock(t, chain, block)
|
||||||
|
|
||||||
|
if len(txs) != 0 {
|
||||||
|
txHashes[int(block.Number().Uint64())] = tx.Hash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// state 6 was not written
|
||||||
|
//
|
||||||
|
fromID = uint64(4)
|
||||||
|
to = int64(chain.GetHeaderByNumber(sprintSize).Time)
|
||||||
|
|
||||||
|
eventRecords = []*clerk.EventRecordWithTime{
|
||||||
|
buildStateEvent(sample, 4, 4),
|
||||||
|
buildStateEvent(sample, 5, 5),
|
||||||
|
}
|
||||||
|
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).MinTimes(1)
|
||||||
|
|
||||||
|
for i := sprintSize + 1; i <= spanSize; i++ {
|
||||||
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||||
|
insertNewBlock(t, chain, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
ethAPI := ethapi.NewPublicBlockChainAPI(init.ethereum.APIBackend)
|
||||||
|
txPoolAPI := ethapi.NewPublicTransactionPoolAPI(init.ethereum.APIBackend, nil)
|
||||||
|
|
||||||
|
for n := 0; n < int(spanSize)+1; n++ {
|
||||||
|
rpcNumber := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(n))
|
||||||
|
|
||||||
|
txs, err := ethAPI.GetTransactionReceiptsByBlock(context.Background(), rpcNumber)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
tx := txPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(n), 0)
|
||||||
|
|
||||||
|
blockMap, err := ethAPI.GetBlockByNumber(context.Background(), rpc.BlockNumber(n), true)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
expectedTxHash, ok := txHashes[n]
|
||||||
|
// FIXME: add `IsSprintStart(uint64(n)) || IsSpanStart(uint64(n))` after adding a full state receiver contract
|
||||||
|
if ok {
|
||||||
|
require.Len(t, txs, 1)
|
||||||
|
|
||||||
|
require.NotNil(t, tx, "not nil receipt expected")
|
||||||
|
|
||||||
|
require.Equal(t, expectedTxHash, tx.Hash, "got different from expected receipt")
|
||||||
|
|
||||||
|
blockTxs, ok := blockMap["transactions"].([]interface{})
|
||||||
|
require.Len(t, blockTxs, 1)
|
||||||
|
|
||||||
|
blockTx, ok := blockTxs[0].(*ethapi.RPCTransaction)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, expectedTxHash, blockTx.Hash)
|
||||||
|
} else {
|
||||||
|
require.Len(t, txs, 0)
|
||||||
|
|
||||||
|
require.Nil(t, tx, "nil receipt expected")
|
||||||
|
|
||||||
|
blockTxs, _ := blockMap["transactions"].([]interface{})
|
||||||
|
require.Len(t, blockTxs, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,14 +11,15 @@ import (
|
||||||
"time"
|
"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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 := ð.Config{
|
ethConf := ð.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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
tests/bor/testdata/genesis.json
vendored
3
tests/bor/testdata/genesis.json
vendored
|
|
@ -52,6 +52,9 @@
|
||||||
},
|
},
|
||||||
"71562b71999873DB5b286dF957af199Ec94617F7": {
|
"71562b71999873DB5b286dF957af199Ec94617F7": {
|
||||||
"balance": "0x3635c9adc5dea00000"
|
"balance": "0x3635c9adc5dea00000"
|
||||||
|
},
|
||||||
|
"9fB29AAc15b9A4B7F17c3385939b007540f4d791": {
|
||||||
|
"balance": "0x3635c9adc5dea00000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"number": "0x0",
|
"number": "0x0",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue