Merge pull request #461 from maticnetwork/arpit/pos-655

sprint length change
This commit is contained in:
Arpit Temani 2022-11-17 13:03:06 +05:30 committed by GitHub
commit 55001d8023
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 1922 additions and 545 deletions

View file

@ -104,7 +104,7 @@ jobs:
uses: actions/checkout@v3
with:
repository: maticnetwork/matic-cli
ref: v0.3.0-dev
ref: arpit/pos-655-2
path: matic-cli
- name: Install dependencies on Linux

2
.gitignore vendored
View file

@ -53,3 +53,5 @@ profile.cov
./bor-debug-*
dist
*.csv

View file

@ -18,8 +18,12 @@
"period": {
"0": 2
},
"producerDelay": 6,
"sprint": 64,
"producerDelay": {
"0": 6
},
"sprint": {
"0": 64
},
"backupMultiplier": {
"0": 2
},

View file

@ -19,8 +19,12 @@
"0": 2,
"25275000": 5
},
"producerDelay": 6,
"sprint": 64,
"producerDelay": {
"0": 6
},
"sprint": {
"0": 64
},
"backupMultiplier": {
"0": 2,
"25275000": 5

View file

@ -50,7 +50,9 @@ const (
// Bor protocol constants.
var (
defaultSprintLength = uint64(64) // Default number of blocks after which to checkpoint and reset the pending votes
defaultSprintLength = map[string]uint64{
"0": 64,
} // Default number of blocks after which to checkpoint and reset the pending votes
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
@ -167,7 +169,7 @@ func encodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) {
header.Nonce,
}
if c.IsJaipur(header.Number.Uint64()) {
if c.IsJaipur(header.Number) {
if header.BaseFee != nil {
enc = append(enc, header.BaseFee)
}
@ -183,8 +185,8 @@ func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint6
// When the block is the first block of the sprint, it is expected to be delayed by `producerDelay`.
// That is to allow time for block propagation in the last sprint
delay := c.CalculatePeriod(number)
if number%c.Sprint == 0 {
delay = c.ProducerDelay
if number%c.CalculateSprint(number) == 0 {
delay = c.CalculateProducerDelay(number)
}
if succession > 0 {
@ -248,7 +250,7 @@ func New(
borConfig := chainConfig.Bor
// Set any missing consensus parameters to their defaults
if borConfig != nil && borConfig.Sprint == 0 {
if borConfig != nil && borConfig.CalculateSprint(0) == 0 {
borConfig.Sprint = defaultSprintLength
}
// Allocate the snapshot caches and create the engine
@ -339,7 +341,7 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
}
// check extr adata
isSprintEnd := IsSprintStart(number+1, c.config.Sprint)
isSprintEnd := IsSprintStart(number+1, c.config.CalculateSprint(number))
// Ensure that the extra-data contains a signer list on checkpoint, but none otherwise
signersBytes := len(header.Extra) - extraVanity - extraSeal
@ -453,7 +455,7 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
}
// verify the validator list in the last sprint block
if IsSprintStart(number, c.config.Sprint) {
if IsSprintStart(number, c.config.CalculateSprint(number)) {
parentValidatorBytes := parent.Extra[extraVanity : len(parent.Extra)-extraSeal]
validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength)
@ -685,7 +687,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
header.Extra = header.Extra[:extraVanity]
// get validator set if number
if IsSprintStart(number+1, c.config.Sprint) {
if IsSprintStart(number+1, c.config.CalculateSprint(number)) {
newValidators, err := c.spanner.GetCurrentValidators(context.Background(), header.ParentHash, number+1)
if err != nil {
return errUnknownValidators
@ -738,9 +740,8 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
headerNumber := header.Number.Uint64()
if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) {
ctx := context.Background()
if IsSprintStart(headerNumber, c.config.Sprint) {
cx := statefull.ChainContext{Chain: chain, Bor: c}
// check and commit span
if err := c.checkAndCommitSpan(ctx, state, header, cx); err != nil {
@ -817,7 +818,7 @@ func (c *Bor) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHead
var err error
if IsSprintStart(headerNumber, c.config.Sprint) {
if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) {
cx := statefull.ChainContext{Chain: chain, Bor: c}
tracing.Exec(finalizeCtx, "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) {
@ -1077,7 +1078,7 @@ func (c *Bor) needToCommitSpan(currentSpan *span.Span, headerNumber uint64) bool
}
// if current block is first block of last sprint in current span
if currentSpan.EndBlock > c.config.Sprint && currentSpan.EndBlock-c.config.Sprint+1 == headerNumber {
if currentSpan.EndBlock > c.config.CalculateSprint(headerNumber) && currentSpan.EndBlock-c.config.CalculateSprint(headerNumber)+1 == headerNumber {
return true
}
@ -1137,7 +1138,7 @@ func (c *Bor) CommitStates(
return nil, err
}
to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.Sprint).Time), 0)
to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.CalculateSprint(number)).Time), 0)
lastStateID := _lastStateID.Uint64()
log.Info(
@ -1253,7 +1254,7 @@ func (c *Bor) getNextHeimdallSpanForTest(
spanBor.StartBlock = spanBor.EndBlock + 1
}
spanBor.EndBlock = spanBor.StartBlock + (100 * c.config.Sprint) - 1
spanBor.EndBlock = spanBor.StartBlock + (100 * c.config.CalculateSprint(headerNumber)) - 1
selectedProducers := make([]valset.Validator, len(snap.ValidatorSet.Validators))
for i, v := range snap.ValidatorSet.Validators {

View file

@ -23,7 +23,9 @@ func TestGenesisContractChange(t *testing.T) {
b := &Bor{
config: &params.BorConfig{
Sprint: 10, // skip sprint transactions in sprint
Sprint: map[string]uint64{
"0": 10,
}, // skip sprint transactions in sprint
BlockAlloc: map[string]interface{}{
// write as interface since that is how it is decoded in genesis
"2": map[string]interface{}{
@ -123,20 +125,20 @@ func TestEncodeSigHeaderJaipur(t *testing.T) {
)
// Jaipur NOT enabled and BaseFee not set
hash := SealHash(h, &params.BorConfig{JaipurBlock: 10})
hash := SealHash(h, &params.BorConfig{JaipurBlock: big.NewInt(10)})
require.Equal(t, hash, hashWithoutBaseFee)
// Jaipur enabled (Jaipur=0) and BaseFee not set
hash = SealHash(h, &params.BorConfig{JaipurBlock: 0})
hash = SealHash(h, &params.BorConfig{JaipurBlock: common.Big0})
require.Equal(t, hash, hashWithoutBaseFee)
h.BaseFee = big.NewInt(2)
// Jaipur enabled (Jaipur=Header block) and BaseFee set
hash = SealHash(h, &params.BorConfig{JaipurBlock: 1})
hash = SealHash(h, &params.BorConfig{JaipurBlock: common.Big1})
require.Equal(t, hash, hashWithBaseFee)
// Jaipur NOT enabled and BaseFee set
hash = SealHash(h, &params.BorConfig{JaipurBlock: 10})
hash = SealHash(h, &params.BorConfig{JaipurBlock: big.NewInt(10)})
require.Equal(t, hash, hashWithoutBaseFee)
}

View file

@ -122,8 +122,8 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
number := header.Number.Uint64()
// Delete the oldest signer from the recent list to allow it signing again
if number >= s.config.Sprint {
delete(snap.Recents, number-s.config.Sprint)
if number >= s.config.CalculateSprint(number) {
delete(snap.Recents, number-s.config.CalculateSprint(number))
}
// Resolve the authorization key and check against signers
@ -145,7 +145,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
snap.Recents[number] = signer
// change validator set and change proposer
if number > 0 && (number+1)%s.config.Sprint == 0 {
if number > 0 && (number+1)%s.config.CalculateSprint(number) == 0 {
if err := validateHeaderExtraField(header.Extra); err != nil {
return nil, err
}

View file

@ -180,7 +180,6 @@ func TestRemoteMultiNotify(t *testing.T) {
// Tests that pushing work packages fast to the miner doesn't cause any data race
// issues in the notifications. Full pending block body / --miner.notify.full)
func TestRemoteMultiNotifyFull(t *testing.T) {
// Start a simple web server to capture notifications.
sink := make(chan map[string]interface{}, 64)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {

View file

@ -61,7 +61,8 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
var (
parentGasTarget = parent.GasLimit / params.ElasticityMultiplier
parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget)
baseFeeChangeDenominator = new(big.Int).SetUint64(params.BaseFeeChangeDenominator)
baseFeeChangeDenominatorUint64 = params.BaseFeeChangeDenominator(config.Bor, parent.Number)
baseFeeChangeDenominator = new(big.Int).SetUint64(baseFeeChangeDenominatorUint64)
)
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
if parent.GasUsed == parentGasTarget {

View file

@ -20,7 +20,6 @@ import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
@ -47,12 +46,14 @@ func copyConfig(original *params.ChainConfig) *params.ChainConfig {
TerminalTotalDifficulty: original.TerminalTotalDifficulty,
Ethash: original.Ethash,
Clique: original.Clique,
Bor: original.Bor,
}
}
func config() *params.ChainConfig {
config := copyConfig(params.TestChainConfig)
config.LondonBlock = big.NewInt(5)
config.Bor.DelhiBlock = big.NewInt(8)
return config
}
@ -108,6 +109,8 @@ func TestBlockGasLimits(t *testing.T) {
// TestCalcBaseFee assumes all blocks are 1559-blocks
func TestCalcBaseFee(t *testing.T) {
t.Parallel()
tests := []struct {
parentBaseFee int64
parentGasLimit uint64
@ -117,10 +120,12 @@ func TestCalcBaseFee(t *testing.T) {
{params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target
{params.InitialBaseFee, 20000000, 9000000, 987500000}, // usage below target
{params.InitialBaseFee, 20000000, 11000000, 1012500000}, // usage above target
{params.InitialBaseFee, 20000000, 20000000, 1125000000}, // usage full
{params.InitialBaseFee, 20000000, 0, 875000000}, // usage 0
}
for i, test := range tests {
parent := &types.Header{
Number: common.Big32,
Number: big.NewInt(6),
GasLimit: test.parentGasLimit,
GasUsed: test.parentGasUsed,
BaseFee: big.NewInt(test.parentBaseFee),
@ -130,3 +135,38 @@ func TestCalcBaseFee(t *testing.T) {
}
}
}
// TestCalcBaseFee assumes all blocks are 1559-blocks post Delhi Hard Fork
func TestCalcBaseFeeDelhi(t *testing.T) {
t.Parallel()
testConfig := copyConfig(config())
// Test Delhi Hard Fork
// Hard fork kicks in at block 8
tests := []struct {
parentBaseFee int64
parentGasLimit uint64
parentGasUsed uint64
expectedBaseFee int64
}{
{params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target
{params.InitialBaseFee, 20000000, 9000000, 993750000}, // usage below target
{params.InitialBaseFee, 20000000, 11000000, 1006250000}, // usage above target
{params.InitialBaseFee, 20000000, 20000000, 1062500000}, // usage full
{params.InitialBaseFee, 20000000, 0, 937500000}, // usage 0
}
for i, test := range tests {
parent := &types.Header{
Number: big.NewInt(8),
GasLimit: test.parentGasLimit,
GasUsed: test.parentGasUsed,
BaseFee: big.NewInt(test.parentBaseFee),
}
if have, want := CalcBaseFee(testConfig, parent), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 {
t.Errorf("test %d: have %d want %d, ", i, have, want)
}
}
}

View file

@ -1826,7 +1826,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
sideblocks, _ = core.GenerateChain(params.BorUnittestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *core.BlockGen) {
b.SetCoinbase(testAddress1)
if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.Sprint) {
if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.CalculateSprint(b.Number().Uint64())) {
b.SetExtra(back.Genesis.ExtraData)
} else {
b.SetExtra(make([]byte, 32+crypto.SignatureLength))
@ -1841,7 +1841,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
b.SetCoinbase(miner.TestBankAddress)
b.SetDifficulty(big.NewInt(1000000))
if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.Sprint) {
if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.CalculateSprint(b.Number().Uint64())) {
b.SetExtra(back.Genesis.ExtraData)
} else {
b.SetExtra(make([]byte, 32+crypto.SignatureLength))

View file

@ -2715,6 +2715,8 @@ func defaultTxPoolRapidConfig() txPoolRapidConfig {
// TestSmallTxPool is not something to run in parallel as far it uses all CPUs
// nolint:paralleltest
func TestSmallTxPool(t *testing.T) {
t.Parallel()
t.Skip("a red test to be fixed")
cfg := defaultTxPoolRapidConfig()
@ -2734,6 +2736,8 @@ func TestSmallTxPool(t *testing.T) {
// This test is not something to run in parallel as far it uses all CPUs
// nolint:paralleltest
func TestBigTxPool(t *testing.T) {
t.Parallel()
t.Skip("a red test to be fixed")
cfg := defaultTxPoolRapidConfig()
@ -2743,6 +2747,8 @@ func TestBigTxPool(t *testing.T) {
//nolint:gocognit,thelper
func testPoolBatchInsert(t *testing.T, cfg txPoolRapidConfig) {
t.Helper()
t.Parallel()
const debug = false

View file

@ -337,8 +337,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([
return nil, errors.New("No chain config found. Proper PublicFilterAPI initialization required")
}
// get sprint from bor config
sprint := api.chainConfig.Bor.Sprint
borConfig := api.chainConfig.Bor
var filter *Filter
var borLogsFilter *BorBlockLogsFilter
@ -347,7 +346,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([
filter = NewBlockFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics)
// Block bor filter
if api.borLogs {
borLogsFilter = NewBorBlockLogsFilter(api.backend, sprint, *crit.BlockHash, crit.Addresses, crit.Topics)
borLogsFilter = NewBorBlockLogsFilter(api.backend, borConfig, *crit.BlockHash, crit.Addresses, crit.Topics)
}
} else {
// Convert the RPC block numbers into internal representations
@ -363,7 +362,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([
filter = NewRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics)
// Block bor filter
if api.borLogs {
borLogsFilter = NewBorBlockLogsRangeFilter(api.backend, sprint, begin, end, crit.Addresses, crit.Topics)
borLogsFilter = NewBorBlockLogsRangeFilter(api.backend, borConfig, begin, end, crit.Addresses, crit.Topics)
}
}

View file

@ -23,12 +23,12 @@ func (api *PublicFilterAPI) GetBorBlockLogs(ctx context.Context, crit FilterCrit
}
// get sprint from bor config
sprint := api.chainConfig.Bor.Sprint
borConfig := api.chainConfig.Bor
var filter *BorBlockLogsFilter
if crit.BlockHash != nil {
// Block filter requested, construct a single-shot filter
filter = NewBorBlockLogsFilter(api.backend, sprint, *crit.BlockHash, crit.Addresses, crit.Topics)
filter = NewBorBlockLogsFilter(api.backend, borConfig, *crit.BlockHash, crit.Addresses, crit.Topics)
} else {
// Convert the RPC block numbers into internal representations
begin := rpc.LatestBlockNumber.Int64()
@ -40,7 +40,7 @@ func (api *PublicFilterAPI) GetBorBlockLogs(ctx context.Context, crit FilterCrit
end = crit.ToBlock.Int64()
}
// Construct the range filter
filter = NewBorBlockLogsRangeFilter(api.backend, sprint, begin, end, crit.Addresses, crit.Topics)
filter = NewBorBlockLogsRangeFilter(api.backend, borConfig, begin, end, crit.Addresses, crit.Topics)
}
// Run the filter and return all the logs

View file

@ -22,13 +22,14 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
// BorBlockLogsFilter can be used to retrieve and filter logs.
type BorBlockLogsFilter struct {
backend Backend
sprint uint64
borConfig *params.BorConfig
db ethdb.Database
addresses []common.Address
@ -40,9 +41,9 @@ type BorBlockLogsFilter struct {
// NewBorBlockLogsRangeFilter creates a new filter which uses a bloom filter on blocks to
// figure out whether a particular block is interesting or not.
func NewBorBlockLogsRangeFilter(backend Backend, sprint uint64, begin, end int64, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter {
func NewBorBlockLogsRangeFilter(backend Backend, borConfig *params.BorConfig, begin, end int64, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter {
// Create a generic filter and convert it into a range filter
filter := newBorBlockLogsFilter(backend, sprint, addresses, topics)
filter := newBorBlockLogsFilter(backend, borConfig, addresses, topics)
filter.begin = begin
filter.end = end
@ -51,19 +52,19 @@ func NewBorBlockLogsRangeFilter(backend Backend, sprint uint64, begin, end int64
// NewBorBlockLogsFilter creates a new filter which directly inspects the contents of
// a block to figure out whether it is interesting or not.
func NewBorBlockLogsFilter(backend Backend, sprint uint64, block common.Hash, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter {
func NewBorBlockLogsFilter(backend Backend, borConfig *params.BorConfig, block common.Hash, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter {
// Create a generic filter and convert it into a block filter
filter := newBorBlockLogsFilter(backend, sprint, addresses, topics)
filter := newBorBlockLogsFilter(backend, borConfig, addresses, topics)
filter.block = block
return filter
}
// newBorBlockLogsFilter creates a generic filter that can either filter based on a block hash,
// or based on range queries. The search criteria needs to be explicitly set.
func newBorBlockLogsFilter(backend Backend, sprint uint64, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter {
func newBorBlockLogsFilter(backend Backend, borConfig *params.BorConfig, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter {
return &BorBlockLogsFilter{
backend: backend,
sprint: sprint,
borConfig: borConfig,
addresses: addresses,
topics: topics,
db: backend.ChainDb(),
@ -94,7 +95,7 @@ func (f *BorBlockLogsFilter) Logs(ctx context.Context) ([]*types.Log, error) {
}
// adjust begin for sprint
f.begin = currentSprintEnd(f.sprint, f.begin)
f.begin = currentSprintEnd(f.borConfig.CalculateSprint(uint64(f.begin)), f.begin)
end := f.end
if f.end == -1 {
@ -110,7 +111,9 @@ func (f *BorBlockLogsFilter) Logs(ctx context.Context) ([]*types.Log, error) {
func (f *BorBlockLogsFilter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) {
var logs []*types.Log
for ; f.begin <= int64(end); f.begin = f.begin + int64(f.sprint) {
sprintLength := f.borConfig.CalculateSprint(uint64(f.begin))
for ; f.begin <= int64(end); f.begin = f.begin + int64(sprintLength) {
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin))
if header == nil || err != nil {
return logs, err
@ -128,6 +131,7 @@ func (f *BorBlockLogsFilter) unindexedLogs(ctx context.Context, end uint64) ([]*
return logs, err
}
logs = append(logs, found...)
sprintLength = f.borConfig.CalculateSprint(uint64(f.begin))
}
return logs, nil
}

View file

@ -62,7 +62,7 @@ func TestBorFilters(t *testing.T) {
hash4 = common.BytesToHash([]byte("topic4"))
db = NewMockDatabase(ctrl)
sprint = params.TestChainConfig.Bor.Sprint
testBorConfig = params.TestChainConfig.Bor
)
backend := NewMockBackend(ctrl)
@ -74,7 +74,7 @@ func TestBorFilters(t *testing.T) {
// Block 1
backend.expectBorReceiptsFromMock([]*common.Hash{nil, &hash1, &hash2, &hash3, &hash4})
filter := NewBorBlockLogsRangeFilter(backend, sprint, 0, 18, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
filter := NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, 18, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
logs, err := filter.Logs(context.Background())
if err != nil {
@ -88,7 +88,7 @@ func TestBorFilters(t *testing.T) {
// Block 2
backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash3})
filter = NewBorBlockLogsRangeFilter(backend, sprint, 990, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 990, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
logs, _ = filter.Logs(context.Background())
if len(logs) != 1 {
@ -102,7 +102,7 @@ func TestBorFilters(t *testing.T) {
// Block 3
backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, &hash3})
filter = NewBorBlockLogsRangeFilter(backend, sprint, 992, 1000, []common.Address{addr}, [][]common.Hash{{hash3}})
filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 992, 1000, []common.Address{addr}, [][]common.Hash{{hash3}})
logs, _ = filter.Logs(context.Background())
if len(logs) != 1 {
@ -116,7 +116,7 @@ func TestBorFilters(t *testing.T) {
// Block 4
backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, nil, &hash3})
filter = NewBorBlockLogsRangeFilter(backend, sprint, 1, 16, []common.Address{addr}, [][]common.Hash{{hash1, hash2}})
filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 1, 16, []common.Address{addr}, [][]common.Hash{{hash1, hash2}})
logs, _ = filter.Logs(context.Background())
@ -128,7 +128,7 @@ func TestBorFilters(t *testing.T) {
backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, nil, &hash3, &hash4, nil})
failHash := common.BytesToHash([]byte("fail"))
filter = NewBorBlockLogsRangeFilter(backend, sprint, 0, 20, nil, [][]common.Hash{{failHash}})
filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, 20, nil, [][]common.Hash{{failHash}})
logs, _ = filter.Logs(context.Background())
if len(logs) != 0 {
@ -139,7 +139,7 @@ func TestBorFilters(t *testing.T) {
backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, nil, &hash3, &hash4, nil})
failAddr := common.BytesToAddress([]byte("failmenow"))
filter = NewBorBlockLogsRangeFilter(backend, sprint, 0, 20, []common.Address{failAddr}, nil)
filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, 20, []common.Address{failAddr}, nil)
logs, _ = filter.Logs(context.Background())
if len(logs) != 0 {
@ -149,7 +149,7 @@ func TestBorFilters(t *testing.T) {
// Block 7
backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, nil, &hash3, &hash4, nil})
filter = NewBorBlockLogsRangeFilter(backend, sprint, 0, 20, nil, [][]common.Hash{{failHash}, {hash1}})
filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, 20, nil, [][]common.Hash{{failHash}, {hash1}})
logs, _ = filter.Logs(context.Background())
if len(logs) != 0 {

View file

@ -23,6 +23,11 @@ if (( $balance <= $balanceInit )); then
exit 1
fi
delayCheckpoint=300
echo "Wait ${delayCheckpoint} seconds for checkpoint..."
sleep $delayCheckpoint
checkpointID=$(curl -sL http://localhost:1317/checkpoints/latest | jq .result.id)
if [ $checkpointID == "null" ]; then

View file

@ -29,12 +29,16 @@ var mainnetBor = &Chain{
BerlinBlock: big.NewInt(14750000),
LondonBlock: big.NewInt(23850000),
Bor: &params.BorConfig{
JaipurBlock: 23850000,
JaipurBlock: big.NewInt(23850000),
Period: map[string]uint64{
"0": 2,
},
ProducerDelay: 6,
Sprint: 64,
ProducerDelay: map[string]uint64{
"0": 6,
},
Sprint: map[string]uint64{
"0": 64,
},
BackupMultiplier: map[string]uint64{
"0": 2,
},

View file

@ -29,13 +29,17 @@ var mumbaiTestnet = &Chain{
BerlinBlock: big.NewInt(13996000),
LondonBlock: big.NewInt(22640000),
Bor: &params.BorConfig{
JaipurBlock: 22770000,
JaipurBlock: big.NewInt(22770000),
Period: map[string]uint64{
"0": 2,
"25275000": 5,
},
ProducerDelay: 6,
Sprint: 64,
ProducerDelay: map[string]uint64{
"0": 6,
},
Sprint: map[string]uint64{
"0": 64,
},
BackupMultiplier: map[string]uint64{
"0": 2,
"25275000": 5,

View file

@ -16,12 +16,18 @@
"londonBlock": 13996000,
"bor": {
"period": {
"0":2
"0": 2,
"25275000": 5
},
"producerDelay": {
"0": 6
},
"sprint": {
"0": 64
},
"producerDelay":6,
"sprint":64,
"backupMultiplier": {
"0":2
"0": 2,
"25275000": 5
},
"validatorContract": "0x0000000000000000000000000000000000001000",
"stateReceiverContract": "0x0000000000000000000000000000000000001001",

View file

@ -18,12 +18,18 @@
"londonBlock":13996000,
"bor":{
"period":{
"0":2
"0":2,
"25275000": 5
},
"producerDelay":{
"0": 6
},
"sprint":{
"0": 64
},
"producerDelay":6,
"sprint":64,
"backupMultiplier":{
"0":2
"0": 2,
"25275000": 5
},
"validatorContract":"0x0000000000000000000000000000000000001000",
"stateReceiverContract":"0x0000000000000000000000000000000000001001",

View file

@ -138,6 +138,9 @@ func NewDBForFakes(t TensingObject) (ethdb.Database, *core.Genesis, *params.Chai
chainConfig.Bor.Period = map[string]uint64{
"0": 1,
}
chainConfig.Bor.Sprint = map[string]uint64{
"0": 64,
}
return chainDB, genesis, chainConfig
}

View file

@ -278,8 +278,12 @@ var (
Period: map[string]uint64{
"0": 2,
},
ProducerDelay: 6,
Sprint: 64,
ProducerDelay: map[string]uint64{
"0": 6,
},
Sprint: map[string]uint64{
"0": 64,
},
BackupMultiplier: map[string]uint64{
"0": 2,
},
@ -310,8 +314,12 @@ var (
Period: map[string]uint64{
"0": 1,
},
ProducerDelay: 3,
Sprint: 32,
ProducerDelay: map[string]uint64{
"0": 3,
},
Sprint: map[string]uint64{
"0": 32,
},
BackupMultiplier: map[string]uint64{
"0": 2,
},
@ -341,13 +349,17 @@ var (
BerlinBlock: big.NewInt(13996000),
LondonBlock: big.NewInt(22640000),
Bor: &BorConfig{
JaipurBlock: 22770000,
JaipurBlock: big.NewInt(22770000),
Period: map[string]uint64{
"0": 2,
"25275000": 5,
},
ProducerDelay: 6,
Sprint: 64,
ProducerDelay: map[string]uint64{
"0": 6,
},
Sprint: map[string]uint64{
"0": 64,
},
BackupMultiplier: map[string]uint64{
"0": 2,
"25275000": 5,
@ -386,12 +398,16 @@ var (
BerlinBlock: big.NewInt(14750000),
LondonBlock: big.NewInt(23850000),
Bor: &BorConfig{
JaipurBlock: 23850000,
JaipurBlock: big.NewInt(23850000),
Period: map[string]uint64{
"0": 2,
},
ProducerDelay: 6,
Sprint: 64,
ProducerDelay: map[string]uint64{
"0": 6,
},
Sprint: map[string]uint64{
"0": 64,
},
BackupMultiplier: map[string]uint64{
"0": 2,
},
@ -436,7 +452,9 @@ var (
// adding flags to the config to also have to set these fields.
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, &BorConfig{BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}}}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil, &BorConfig{Sprint: 4, BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}}}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil, &BorConfig{Sprint: map[string]uint64{
"0": 4,
}, BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}}}
TestRules = TestChainConfig.Rules(new(big.Int), false)
)
@ -550,15 +568,16 @@ func (c *CliqueConfig) String() string {
// BorConfig is the consensus engine configs for Matic bor based sealing.
type BorConfig struct {
Period map[string]uint64 `json:"period"` // Number of seconds between blocks to enforce
ProducerDelay uint64 `json:"producerDelay"` // Number of seconds delay between two producer interval
Sprint uint64 `json:"sprint"` // Epoch length to proposer
ProducerDelay map[string]uint64 `json:"producerDelay"` // Number of seconds delay between two producer interval
Sprint map[string]uint64 `json:"sprint"` // Epoch length to proposer
BackupMultiplier map[string]uint64 `json:"backupMultiplier"` // Backup multiplier to determine the wiggle time
ValidatorContract string `json:"validatorContract"` // Validator set contract
StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract
OverrideStateSyncRecords map[string]int `json:"overrideStateSyncRecords"` // override state records count
BlockAlloc map[string]interface{} `json:"blockAlloc"`
BurntContract map[string]string `json:"burntContract"` // governance contract where the token will be sent to and burnt in london fork
JaipurBlock uint64 `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur)
JaipurBlock *big.Int `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur)
DelhiBlock *big.Int `json:"delhiBlock"` // Delhi switch block (nil = no fork, 0 = already on delhi)
}
// String implements the stringer interface, returning the consensus engine details.
@ -566,6 +585,14 @@ func (b *BorConfig) String() string {
return "bor"
}
func (c *BorConfig) CalculateProducerDelay(number uint64) uint64 {
return c.calculateSprintSizeHelper(c.ProducerDelay, number)
}
func (c *BorConfig) CalculateSprint(number uint64) uint64 {
return c.calculateSprintSizeHelper(c.Sprint, number)
}
func (c *BorConfig) CalculateBackupMultiplier(number uint64) uint64 {
return c.calculateBorConfigHelper(c.BackupMultiplier, number)
}
@ -574,8 +601,12 @@ func (c *BorConfig) CalculatePeriod(number uint64) uint64 {
return c.calculateBorConfigHelper(c.Period, number)
}
func (c *BorConfig) IsJaipur(number uint64) bool {
return number >= c.JaipurBlock
func (c *BorConfig) IsJaipur(number *big.Int) bool {
return isForked(c.JaipurBlock, number)
}
func (c *BorConfig) IsDelhi(number *big.Int) bool {
return isForked(c.DelhiBlock, number)
}
func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uint64) uint64 {
@ -589,6 +620,7 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin
for i := 0; i < len(keys)-1; i++ {
valUint, _ := strconv.ParseUint(keys[i], 10, 64)
valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64)
if number > valUint && number < valUintNext {
return field[keys[i]]
}
@ -597,6 +629,26 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin
return field[keys[len(keys)-1]]
}
func (c *BorConfig) calculateSprintSizeHelper(field map[string]uint64, number uint64) uint64 {
keys := make([]string, 0, len(field))
for k := range field {
keys = append(keys, k)
}
sort.Strings(keys)
for i := 0; i < len(keys)-1; i++ {
valUint, _ := strconv.ParseUint(keys[i], 10, 64)
valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64)
if number >= valUint && number < valUintNext {
return field[keys[i]]
}
}
return field[keys[len(keys)-1]]
}
func (c *BorConfig) CalculateBurntContract(number uint64) string {
keys := make([]string, 0, len(c.BurntContract))
for k := range c.BurntContract {

View file

@ -119,7 +119,9 @@ const (
// Introduced in Tangerine Whistle (Eip 150)
CreateBySelfdestructGas uint64 = 25000
BaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks.
BaseFeeChangeDenominatorPreDelhi = 8 // Bounds the amount the base fee can change between blocks before Delhi Hard Fork.
BaseFeeChangeDenominatorPostDelhi = 16 // Bounds the amount the base fee can change between blocks after Delhi Hard Fork.
ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have.
InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks.
@ -168,3 +170,11 @@ var (
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
)
func BaseFeeChangeDenominator(borConfig *BorConfig, number *big.Int) uint64 {
if borConfig.IsDelhi(number) {
return BaseFeeChangeDenominatorPostDelhi
} else {
return BaseFeeChangeDenominatorPreDelhi
}
}

View file

@ -23,7 +23,7 @@ import (
const (
VersionMajor = 0 // Major version component of the current release
VersionMinor = 3 // Minor version component of the current release
VersionPatch = 0 // Patch version component of the current release
VersionPatch = 1 // Patch version component of the current release
VersionMeta = "beta" // Version metadata to append to the version string
)
@ -43,6 +43,7 @@ var VersionWithMeta = func() string {
// ArchiveVersion holds the textual version string used for Geth archives.
// e.g. "1.8.11-dea1ce05" for stable releases, or
//
// "1.8.13-unstable-21c059b6" for unstable releases
func ArchiveVersion(gitCommit string) string {
vsn := Version

View file

@ -138,7 +138,7 @@ func TestAPIs(t *testing.T) {
}()
genesis := core.GenesisBlockForTesting(db, addrr, big.NewInt(1000000))
sprint := params.TestChainConfig.Bor.Sprint
testBorConfig := params.TestChainConfig.Bor
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 6, func(i int, gen *core.BlockGen) {
switch i {
@ -208,7 +208,7 @@ func TestAPIs(t *testing.T) {
blockBatch := db.NewBatch()
if i%int(sprint-1) != 0 {
if i%int(testBorConfig.CalculateSprint(block.NumberU64())-1) != 0 {
// if it is not sprint start write all the transactions as normal transactions.
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
} else {

View file

@ -31,12 +31,17 @@ func TestBorFilters(t *testing.T) {
hash2 = common.BytesToHash([]byte("topic2"))
hash3 = common.BytesToHash([]byte("topic3"))
hash4 = common.BytesToHash([]byte("topic4"))
hash5 = common.BytesToHash([]byte("topic5"))
)
defer db.Close()
genesis := core.GenesisBlockForTesting(db, addr, big.NewInt(1000000))
sprint := params.TestChainConfig.Bor.Sprint
testBorConfig := params.TestChainConfig.Bor
testBorConfig.Sprint = map[string]uint64{
"0": 4,
"8": 2,
}
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) {
switch i {
@ -73,7 +78,7 @@ func TestBorFilters(t *testing.T) {
gen.AddUncheckedReceipt(receipt)
gen.AddUncheckedTx(types.NewTransaction(992, common.HexToAddress("0x992"), big.NewInt(992), 992, gen.BaseFee(), nil))
case 999: //state-sync tx at block 1000
case 993: //state-sync tx at block 994
receipt := types.NewReceipt(nil, false, 0)
receipt.Logs = []*types.Log{
{
@ -82,6 +87,17 @@ func TestBorFilters(t *testing.T) {
},
}
gen.AddUncheckedReceipt(receipt)
gen.AddUncheckedTx(types.NewTransaction(994, common.HexToAddress("0x994"), big.NewInt(994), 994, gen.BaseFee(), nil))
case 999: //state-sync tx at block 1000
receipt := types.NewReceipt(nil, false, 0)
receipt.Logs = []*types.Log{
{
Address: addr,
Topics: []common.Hash{hash5},
},
}
gen.AddUncheckedReceipt(receipt)
gen.AddUncheckedTx(types.NewTransaction(1000, common.HexToAddress("0x1000"), big.NewInt(1000), 1000, gen.BaseFee(), nil))
}
})
@ -122,14 +138,14 @@ func TestBorFilters(t *testing.T) {
}
}
filter := filters.NewBorBlockLogsRangeFilter(backend, sprint, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
filter := filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4, hash5}})
logs, _ := filter.Logs(context.Background())
if len(logs) != 4 {
t.Error("expected 4 log, got", len(logs))
if len(logs) != 5 {
t.Error("expected 5 log, got", len(logs))
}
filter = filters.NewBorBlockLogsRangeFilter(backend, sprint, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
logs, _ = filter.Logs(context.Background())
if len(logs) != 1 {
@ -140,7 +156,7 @@ func TestBorFilters(t *testing.T) {
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
}
filter = filters.NewBorBlockLogsRangeFilter(backend, sprint, 992, -1, []common.Address{addr}, [][]common.Hash{{hash3}})
filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 992, -1, []common.Address{addr}, [][]common.Hash{{hash3}})
logs, _ = filter.Logs(context.Background())
if len(logs) != 1 {
@ -151,7 +167,7 @@ func TestBorFilters(t *testing.T) {
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
}
filter = filters.NewBorBlockLogsRangeFilter(backend, sprint, 1, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2}})
filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 1, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2}})
logs, _ = filter.Logs(context.Background())
if len(logs) != 2 {
@ -159,7 +175,7 @@ func TestBorFilters(t *testing.T) {
}
failHash := common.BytesToHash([]byte("fail"))
filter = filters.NewBorBlockLogsRangeFilter(backend, sprint, 0, -1, nil, [][]common.Hash{{failHash}})
filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, -1, nil, [][]common.Hash{{failHash}})
logs, _ = filter.Logs(context.Background())
if len(logs) != 0 {
@ -167,14 +183,14 @@ func TestBorFilters(t *testing.T) {
}
failAddr := common.BytesToAddress([]byte("failmenow"))
filter = filters.NewBorBlockLogsRangeFilter(backend, sprint, 0, -1, []common.Address{failAddr}, nil)
filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, -1, []common.Address{failAddr}, nil)
logs, _ = filter.Logs(context.Background())
if len(logs) != 0 {
t.Error("expected 0 log, got", len(logs))
}
filter = filters.NewBorBlockLogsRangeFilter(backend, sprint, 0, -1, nil, [][]common.Hash{{failHash}, {hash1}})
filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, -1, nil, [][]common.Hash{{failHash}, {hash1}})
logs, _ = filter.Logs(context.Background())
if len(logs) != 0 {

View file

@ -1,281 +0,0 @@
//go:build integration
package bor
import (
"sync"
"testing"
"time"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/assert"
)
func TestValidatorWentOffline(t *testing.T) {
// Create an Ethash network based off of the Ropsten config
genesis := initGenesis(t)
stacks, nodes, enodes := setupMiner(t, 2, genesis)
defer func() {
for _, stack := range stacks {
stack.Close()
}
}()
// Iterate over all the nodes and start mining
for _, node := range nodes {
if err := node.StartMining(1); err != nil {
t.Fatal("Error occured while starting miner", "node", node, "error", err)
}
}
for {
// for block 1 to 8, the primary validator is node0
// for block 9 to 16, the primary validator is node1
// for block 17 to 24, the primary validator is node0
// for block 25 to 32, the primary validator is node1
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
// we remove peer connection between node0 and node1
if blockHeaderVal0.Number.Uint64() == 9 {
stacks[0].Server().RemovePeer(enodes[1])
}
// here, node1 is the primary validator, node0 will sign out-of-turn
// we add peer connection between node1 and node0
if blockHeaderVal0.Number.Uint64() == 14 {
stacks[0].Server().AddPeer(enodes[1])
}
// reorg happens here, node1 has higher difficulty, it will replace blocks by node0
if blockHeaderVal0.Number.Uint64() == 30 {
break
}
}
// check block 10 miner ; expected author is node1 signer
blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(10)
blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(10)
authorVal0, err := nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
t.Error("Error in getting author", "err", err)
}
authorVal1, err := nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
t.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 10
assert.Equal(t, authorVal0, authorVal1)
// check node0 has block mined by node1
assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0])
// check node1 has block mined by node1
assert.Equal(t, authorVal1, nodes[1].AccountManager().Accounts()[0])
// check block 11 miner ; expected author is node1 signer
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(11)
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(11)
authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
t.Error("Error in getting author", "err", err)
}
authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
t.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 11
assert.Equal(t, authorVal0, authorVal1)
// check node0 has block mined by node1
assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0])
// check node1 has block mined by node1
assert.Equal(t, authorVal1, nodes[1].AccountManager().Accounts()[0])
// check block 12 miner ; expected author is node1 signer
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(12)
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(12)
authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
t.Error("Error in getting author", "err", err)
}
authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
t.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 12
assert.Equal(t, authorVal0, authorVal1)
// check node0 has block mined by node1
assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0])
// check node1 has block mined by node1
assert.Equal(t, authorVal1, nodes[1].AccountManager().Accounts()[0])
// check block 17 miner ; expected author is node0 signer
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(17)
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(17)
authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
t.Error("Error in getting author", "err", err)
}
authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
t.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 17
assert.Equal(t, authorVal0, authorVal1)
// check node0 has block mined by node1
assert.Equal(t, authorVal0, nodes[0].AccountManager().Accounts()[0])
// check node1 has block mined by node1
assert.Equal(t, authorVal1, nodes[0].AccountManager().Accounts()[0])
}
func TestForkWithBlockTime(t *testing.T) {
cases := []struct {
name string
sprint uint64
blockTime map[string]uint64
change uint64
producerDelay uint64
forkExpected bool
}{
{
name: "No fork after 2 sprints with producer delay = max block time",
sprint: 128,
blockTime: map[string]uint64{
"0": 5,
"128": 2,
"256": 8,
},
change: 2,
producerDelay: 8,
forkExpected: false,
},
{
name: "No Fork after 1 sprint producer delay = max block time",
sprint: 64,
blockTime: map[string]uint64{
"0": 5,
"64": 2,
},
change: 1,
producerDelay: 5,
forkExpected: false,
},
{
name: "Fork after 4 sprints with producer delay < max block time",
sprint: 16,
blockTime: map[string]uint64{
"0": 2,
"64": 5,
},
change: 4,
producerDelay: 4,
forkExpected: true,
},
}
// Create an Ethash network based off of the Ropsten config
genesis := initGenesis(t)
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
genesis.Config.Bor.Sprint = test.sprint
genesis.Config.Bor.Period = test.blockTime
genesis.Config.Bor.BackupMultiplier = test.blockTime
genesis.Config.Bor.ProducerDelay = test.producerDelay
stacks, nodes, _ := setupMiner(t, 2, genesis)
defer func() {
for _, stack := range stacks {
stack.Close()
}
}()
// Iterate over all the nodes and start mining
for _, node := range nodes {
if err := node.StartMining(1); err != nil {
t.Fatal("Error occured while starting miner", "node", node, "error", err)
}
}
var wg sync.WaitGroup
blockHeaders := make([]*types.Header, 2)
ticker := time.NewTicker(time.Duration(test.blockTime["0"]) * time.Second)
defer ticker.Stop()
for i := 0; i < 2; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
for range ticker.C {
blockHeaders[i] = nodes[i].BlockChain().GetHeaderByNumber(test.sprint*test.change + 10)
if blockHeaders[i] != nil {
break
}
}
}(i)
}
wg.Wait()
// Before the end of sprint
blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(test.sprint - 1)
blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(test.sprint - 1)
assert.Equal(t, blockHeaderVal0.Hash(), blockHeaderVal1.Hash())
assert.Equal(t, blockHeaderVal0.Time, blockHeaderVal1.Time)
author0, err := nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
t.Error("Error occured while fetching author", "err", err)
}
author1, err := nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
t.Error("Error occured while fetching author", "err", err)
}
assert.Equal(t, author0, author1)
// After the end of sprint
author2, err := nodes[0].Engine().Author(blockHeaders[0])
if err != nil {
t.Error("Error occured while fetching author", "err", err)
}
author3, err := nodes[1].Engine().Author(blockHeaders[1])
if err != nil {
t.Error("Error occured while fetching author", "err", err)
}
if test.forkExpected {
assert.NotEqual(t, blockHeaders[0].Hash(), blockHeaders[1].Hash())
assert.NotEqual(t, blockHeaders[0].Time, blockHeaders[1].Time)
assert.NotEqual(t, author2, author3)
} else {
assert.Equal(t, blockHeaders[0].Hash(), blockHeaders[1].Hash())
assert.Equal(t, blockHeaders[0].Time, blockHeaders[1].Time)
assert.Equal(t, author2, author3)
}
})
}
}

View file

@ -0,0 +1,855 @@
package bor
import (
"crypto/ecdsa"
"encoding/csv"
"encoding/json"
"fmt"
"io/ioutil" // nolint: staticcheck
_log "log"
"math/big"
"os"
"sync"
"testing"
"time"
"gotest.tools/assert"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/params"
)
var (
// Only this account is a validator for the 0th span
keySprintLength, _ = crypto.HexToECDSA(privKeySprintLength)
// This account is one the validators for 1st span (0-indexed)
keySprintLength2, _ = crypto.HexToECDSA(privKeySprintLength2)
keysSprintLength = []*ecdsa.PrivateKey{keySprintLength, keySprintLength2}
)
const (
privKeySprintLength = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
privKeySprintLength2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
)
// Sprint length change tests
func TestValidatorsBlockProduction(t *testing.T) {
t.Parallel()
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
_, err := fdlimit.Raise(2048)
if err != nil {
panic(err)
}
// Generate a batch of accounts to seal and fund with
faucets := make([]*ecdsa.PrivateKey, 128)
for i := 0; i < len(faucets); i++ {
faucets[i], _ = crypto.GenerateKey()
}
// Create an Ethash network based off of the Ropsten config
// Generate a batch of accounts to seal and fund with
genesis := InitGenesisSprintLength(t, faucets, "./testdata/genesis_sprint_length_change.json", 8)
nodes := make([]*eth.Ethereum, 2)
enodes := make([]*enode.Node, 2)
for i := 0; i < 2; i++ {
// Start the node and wait until it's up
stack, ethBackend, err := InitMinerSprintLength(genesis, keysSprintLength[i], true)
if err != nil {
panic(err)
}
defer stack.Close()
for stack.Server().NodeInfo().Ports.Listener == 0 {
time.Sleep(250 * time.Millisecond)
}
// Connect the node to all the previous ones
for j, n := range enodes {
if j < i {
stack.Server().AddPeer(n)
}
}
// Start tracking the node and its enode
nodes[i] = ethBackend
enodes[i] = stack.Server().Self()
}
// Iterate over all the nodes and start mining
time.Sleep(3 * time.Second)
for _, node := range nodes {
if err := node.StartMining(1); err != nil {
panic(err)
}
}
for {
// for block 0 to 7, the primary validator is node0
// for block 8 to 15, the primary validator is node1
// for block 16 to 19, the primary validator is node0
// for block 20 to 23, the primary validator is node1
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
if blockHeaderVal0.Number.Uint64() == 24 {
break
}
}
// check block 7 miner ; expected author is node0 signer
blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(7)
blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(7)
authorVal0, err := nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
log.Error("Error in getting author", "err", err)
}
authorVal1, err := nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
log.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 7
assert.Equal(t, authorVal0, authorVal1)
// check block mined by node0
assert.Equal(t, authorVal0, nodes[0].AccountManager().Accounts()[0])
// check block 15 miner ; expected author is node1 signer
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(15)
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(15)
authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
log.Error("Error in getting author", "err", err)
}
authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
log.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 15
assert.Equal(t, authorVal0, authorVal1)
// check block mined by node1
assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0])
// check block 19 miner ; expected author is node0 signer
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(19)
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(19)
authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
log.Error("Error in getting author", "err", err)
}
authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
log.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 19
assert.Equal(t, authorVal0, authorVal1)
// check block mined by node0
assert.Equal(t, authorVal0, nodes[0].AccountManager().Accounts()[0])
// check block 23 miner ; expected author is node1 signer
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(23)
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(23)
authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
log.Error("Error in getting author", "err", err)
}
authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
log.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 23
assert.Equal(t, authorVal0, authorVal1)
// check block mined by node1
assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0])
}
func TestSprintLengths(t *testing.T) {
t.Parallel()
testBorConfig := params.TestChainConfig.Bor
testBorConfig.Sprint = map[string]uint64{
"0": 16,
"8": 4,
}
assert.Equal(t, testBorConfig.CalculateSprint(0), uint64(16))
assert.Equal(t, testBorConfig.CalculateSprint(8), uint64(4))
assert.Equal(t, testBorConfig.CalculateSprint(9), uint64(4))
}
func TestProducerDelay(t *testing.T) {
t.Parallel()
testBorConfig := params.TestChainConfig.Bor
testBorConfig.ProducerDelay = map[string]uint64{
"0": 16,
"8": 4,
}
assert.Equal(t, testBorConfig.CalculateProducerDelay(0), uint64(16))
assert.Equal(t, testBorConfig.CalculateProducerDelay(8), uint64(4))
assert.Equal(t, testBorConfig.CalculateProducerDelay(9), uint64(4))
}
var keys_21val = []map[string]string{
{
"address": "0x5C3E1B893B9315a968fcC6bce9EB9F7d8E22edB3",
"priv_key": "c19fac8e538447124ad2408d9fbaeda2bb686fee763dca7a6bab58ea12442413",
"pub_key": "0x0495421933eda03dcc37f9186c24e255b569513aefae71e96d55d0db3df17502e24e86297b01a167fab9ce1174f06ee3110510ac242e39218bd964de5b345edbd6",
},
{
"address": "0x73E033779C9030D4528d86FbceF5B02e97488921",
"priv_key": "61eb51cf8936309151ab7b931841ea033b6a09931f6a100b464fbbd74f3e0bd7",
"pub_key": "0x04f9a5e9bf76b45ac58f1b018ccba4b83b3531010cdadf42174c18a9db9879ef1dcb5d1254ce834bc108b110cd8d0186ed69a0387528a142bdb5936faf58bf98c9",
},
{
"address": "0x751eC4877450B8a4D652d0D70197337FC38a42e6",
"priv_key": "6e7f48d012c9c0baadbdc88af32521e2e477fd6898a9b65e6abe19fd6652cb2e",
"pub_key": "0x0479db4c0b757bf0e5d9b8954b078ab7c0e91d6c19697904d23d07ea4853c8584382de91174929ba5c598214b8a991471ae051458ea787cdc15a4e435a55ef8059",
},
{
"address": "0xA464DC4810Bc79B956810759e314d85BcE35cD1c",
"priv_key": "3efcf3f7014a6257f4a443119851414111820c681b27525dab3f35e72e28e51e",
"pub_key": "0x040180920306bf598ea050e258f2c7e50804a77a64f5a11705e08d18ee71eb0a80fafc95d0a42b92371ded042edda16c1f0b5f2fef7c4113ad66c59a71c29d977e",
},
{
"address": "0xb005bc07015170266Bd430f3EC1322938603be20",
"priv_key": "17cd9b38c2b3a639c7d97ccbf2bb6c7140ab8f625aec4c249bc8e4cfd3bf9a96",
"pub_key": "0x04435a70d343aa569e6f3386c73e39a1aa6f88c30e5943baedda9618b55cc944a2de1d114aff6d0e9fa002bebc780b04ef6c1b8a06bbf0d41c10d1efa55390f198",
},
{
"address": "0xE8d02Da3dFeeB3e755472D95D666BD6821D92129",
"priv_key": "45c9ef66361a2283cef14184f128c41949103b791aa622ead3c0bc844648b835",
"pub_key": "0x04a14651ddc80467eb589d72d95153fa695e4cb2e4bb99edeb912e840d309d61313b6f4676081b099f29e6598ecf98cb7b44bb862d019920718b558f27ba94ca51",
},
{
"address": "0xF93B54Cf36E917f625B48e1e3C9F93BC2344Fb06",
"priv_key": "93788a1305605808df1f9a96b5e1157da191680cf08bc15e077138f517563cd5",
"pub_key": "0x045eee11dceccd9cccc371ca3d96d74c848e785223f1e5df4d1a7f08efdfeb90bd8f0035342a9c26068cf6c7ab395ca3ceea555541325067fc187c375390efa57d",
},
}
func getTestSprintLengthReorgCases2Nodes() []map[string]interface{} {
sprintSizes := []uint64{64}
faultyNodes := [][]uint64{{0, 1}, {1, 2}, {0, 2}}
reorgsLengthTests := make([]map[string]interface{}, 0)
for i := uint64(0); i < uint64(len(sprintSizes)); i++ {
maxReorgLength := sprintSizes[i] * 4
for j := uint64(20); j <= maxReorgLength; j = j + 8 {
maxStartBlock := sprintSizes[i] - 1
for k := sprintSizes[i] / 2; k <= maxStartBlock; k = k + 4 {
for l := uint64(0); l < uint64(len(faultyNodes)); l++ {
if j+k < sprintSizes[i] {
continue
}
reorgsLengthTest := map[string]interface{}{
"reorgLength": j,
"startBlock": k,
"sprintSize": sprintSizes[i],
"faultyNodes": faultyNodes[l], // node 1(index) is primary validator of the first sprint
}
reorgsLengthTests = append(reorgsLengthTests, reorgsLengthTest)
}
}
}
}
// reorgsLengthTests := []map[string]uint64{
// {
// "reorgLength": 3,
// "startBlock": 7,
// "sprintSize": 8,
// "faultyNode": 1,
// },
// }
return reorgsLengthTests
}
func getTestSprintLengthReorgCases() []map[string]uint64 {
sprintSizes := []uint64{64, 32, 16, 8}
faultyNodes := []uint64{0, 1}
reorgsLengthTests := make([]map[string]uint64, 0)
for i := uint64(0); i < uint64(len(sprintSizes)); i++ {
maxReorgLength := sprintSizes[i] * 4
for j := uint64(3); j <= maxReorgLength; j = j + 4 {
maxStartBlock := sprintSizes[i] - 1
for k := sprintSizes[i] / 2; k <= maxStartBlock; k = k + 4 {
for l := uint64(0); l < uint64(len(faultyNodes)); l++ {
if j+k < sprintSizes[i] {
continue
}
reorgsLengthTest := map[string]uint64{
"reorgLength": j,
"startBlock": k,
"sprintSize": sprintSizes[i],
"faultyNode": faultyNodes[l], // node 1(index) is primary validator of the first sprint
}
reorgsLengthTests = append(reorgsLengthTests, reorgsLengthTest)
}
}
}
}
// reorgsLengthTests := []map[string]uint64{
// {
// "reorgLength": 3,
// "startBlock": 7,
// "sprintSize": 8,
// "faultyNode": 1,
// },
// }
return reorgsLengthTests
}
func SprintLengthReorgIndividual(t *testing.T, index int, tt map[string]uint64) (uint64, uint64, uint64, uint64, uint64, uint64) {
t.Helper()
log.Warn("Case ----- ", "Index", index, "InducedReorgLength", tt["reorgLength"], "BlockStart", tt["startBlock"], "SprintSize", tt["sprintSize"], "DisconnectedNode", tt["faultyNode"])
observerOldChainLength, faultyOldChainLength := SetupValidatorsAndTest(t, tt)
if observerOldChainLength > 0 {
log.Warn("Observer", "Old Chain length", observerOldChainLength)
}
if faultyOldChainLength > 0 {
log.Warn("Faulty", "Old Chain length", faultyOldChainLength)
}
return tt["reorgLength"], tt["startBlock"], tt["sprintSize"], tt["faultyNode"], faultyOldChainLength, observerOldChainLength
}
func SprintLengthReorgIndividual2Nodes(t *testing.T, index int, tt map[string]interface{}) (uint64, uint64, uint64, []uint64, uint64, uint64) {
t.Helper()
log.Warn("Case ----- ", "Index", index, "InducedReorgLength", tt["reorgLength"], "BlockStart", tt["startBlock"], "SprintSize", tt["sprintSize"], "DisconnectedNode", tt["faultyNodes"])
observerOldChainLength, faultyOldChainLength := SetupValidatorsAndTest2Nodes(t, tt)
if observerOldChainLength > 0 {
log.Warn("Observer", "Old Chain length", observerOldChainLength)
}
if faultyOldChainLength > 0 {
log.Warn("Faulty", "Old Chain length", faultyOldChainLength)
}
fNodes, _ := tt["faultyNodes"].([]uint64)
return tt["reorgLength"].(uint64), tt["startBlock"].(uint64), tt["sprintSize"].(uint64), fNodes, faultyOldChainLength, observerOldChainLength
}
func TestSprintLengthReorg2Nodes(t *testing.T) {
t.Skip()
t.Parallel()
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
_, err := fdlimit.Raise(2048)
if err != nil {
panic(err)
}
reorgsLengthTests := getTestSprintLengthReorgCases2Nodes()
f, err := os.Create("sprintReorg2Nodes.csv")
defer func() {
err = f.Close()
if err != nil {
panic(err)
}
}()
if err != nil {
_log.Fatalln("failed to open file", err)
}
w := csv.NewWriter(f)
err = w.Write([]string{"Induced Reorg Length", "Start Block", "Sprint Size", "Disconnected Node Ids", "Disconnected Node Id's Reorg Length", "Observer Node Id's Reorg Length"})
w.Flush()
if err != nil {
panic(err)
}
var wg sync.WaitGroup
for index, tt := range reorgsLengthTests {
if index%4 == 0 {
wg.Wait()
}
wg.Add(1)
go SprintLengthReorgIndividual2NodesHelper(t, index, tt, w, &wg)
}
}
func TestSprintLengthReorg(t *testing.T) {
t.Skip()
t.Parallel()
reorgsLengthTests := getTestSprintLengthReorgCases()
f, err := os.Create("sprintReorg.csv")
defer func() {
err = f.Close()
if err != nil {
panic(err)
}
}()
if err != nil {
_log.Fatalln("failed to open file", err)
}
w := csv.NewWriter(f)
err = w.Write([]string{"Induced Reorg Length", "Start Block", "Sprint Size", "Disconnected Node Id", "Disconnected Node Id's Reorg Length", "Observer Node Id's Reorg Length"})
w.Flush()
if err != nil {
panic(err)
}
var wg sync.WaitGroup
for index, tt := range reorgsLengthTests {
if index%4 == 0 {
wg.Wait()
}
wg.Add(1)
go SprintLengthReorgIndividualHelper(t, index, tt, w, &wg)
}
}
func SprintLengthReorgIndividualHelper(t *testing.T, index int, tt map[string]uint64, w *csv.Writer, wg *sync.WaitGroup) {
t.Helper()
r1, r2, r3, r4, r5, r6 := SprintLengthReorgIndividual(t, index, tt)
err := w.Write([]string{fmt.Sprint(r1), fmt.Sprint(r2), fmt.Sprint(r3), fmt.Sprint(r4), fmt.Sprint(r5), fmt.Sprint(r6)})
if err != nil {
panic(err)
}
w.Flush()
(*wg).Done()
}
func SprintLengthReorgIndividual2NodesHelper(t *testing.T, index int, tt map[string]interface{}, w *csv.Writer, wg *sync.WaitGroup) {
t.Helper()
r1, r2, r3, r4, r5, r6 := SprintLengthReorgIndividual2Nodes(t, index, tt)
err := w.Write([]string{fmt.Sprint(r1), fmt.Sprint(r2), fmt.Sprint(r3), fmt.Sprint(r4), fmt.Sprint(r5), fmt.Sprint(r6)})
if err != nil {
panic(err)
}
w.Flush()
(*wg).Done()
}
// nolint: gocognit
func SetupValidatorsAndTest(t *testing.T, tt map[string]uint64) (uint64, uint64) {
t.Helper()
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
_, err := fdlimit.Raise(2048)
if err != nil {
panic(err)
}
// Generate a batch of accounts to seal and fund with
faucets := make([]*ecdsa.PrivateKey, 128)
for i := 0; i < len(faucets); i++ {
faucets[i], _ = crypto.GenerateKey()
}
// Create an Ethash network based off of the Ropsten config
// Generate a batch of accounts to seal and fund with
genesis := InitGenesisSprintLength(t, faucets, "./testdata/genesis_7val.json", tt["sprintSize"])
nodes := make([]*eth.Ethereum, len(keys_21val))
enodes := make([]*enode.Node, len(keys_21val))
stacks := make([]*node.Node, len(keys_21val))
pkeys_21val := make([]*ecdsa.PrivateKey, len(keys_21val))
for index, signerdata := range keys_21val {
pkeys_21val[index], _ = crypto.HexToECDSA(signerdata["priv_key"])
}
for i := 0; i < len(keys_21val); i++ {
// Start the node and wait until it's up
stack, ethBackend, err := InitMinerSprintLength(genesis, pkeys_21val[i], true)
if err != nil {
panic(err)
}
defer stack.Close()
for stack.Server().NodeInfo().Ports.Listener == 0 {
time.Sleep(250 * time.Millisecond)
}
// Connect the node to all the previous ones
for j, n := range enodes {
if j < i {
stack.Server().AddPeer(n)
}
}
// Start tracking the node and its enode
stacks[i] = stack
nodes[i] = ethBackend
enodes[i] = stack.Server().Self()
}
// Iterate over all the nodes and start mining
time.Sleep(3 * time.Second)
for _, node := range nodes {
if err := node.StartMining(1); err != nil {
panic(err)
}
}
chain2HeadChObserver := make(chan core.Chain2HeadEvent, 64)
chain2HeadChFaulty := make(chan core.Chain2HeadEvent, 64)
var observerOldChainLength, faultyOldChainLength uint64
faultyProducerIndex := tt["faultyNode"] // node causing reorg :: faulty ::
subscribedNodeIndex := 6 // node on different partition, produces 7th sprint but our testcase does not run till 7th sprint. :: observer ::
nodes[subscribedNodeIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChObserver)
nodes[faultyProducerIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChFaulty)
stacks[faultyProducerIndex].Server().NoDiscovery = true
for {
blockHeaderObserver := nodes[subscribedNodeIndex].BlockChain().CurrentHeader()
blockHeaderFaulty := nodes[faultyProducerIndex].BlockChain().CurrentHeader()
log.Warn("Current Observer block", "number", blockHeaderObserver.Number, "hash", blockHeaderObserver.Hash())
log.Warn("Current Faulty block", "number", blockHeaderFaulty.Number, "hash", blockHeaderFaulty.Hash())
if blockHeaderFaulty.Number.Uint64() == tt["startBlock"] {
stacks[faultyProducerIndex].Server().MaxPeers = 0
for _, enode := range enodes {
stacks[faultyProducerIndex].Server().RemovePeer(enode)
}
}
if blockHeaderObserver.Number.Uint64() >= tt["startBlock"] && blockHeaderObserver.Number.Uint64() < tt["startBlock"]+tt["reorgLength"] {
for _, enode := range enodes {
stacks[faultyProducerIndex].Server().RemovePeer(enode)
}
}
if blockHeaderObserver.Number.Uint64() == tt["startBlock"]+tt["reorgLength"] {
stacks[faultyProducerIndex].Server().NoDiscovery = false
stacks[faultyProducerIndex].Server().MaxPeers = 100
for _, enode := range enodes {
stacks[faultyProducerIndex].Server().AddPeer(enode)
}
}
if blockHeaderFaulty.Number.Uint64() >= 255 {
break
}
select {
case ev := <-chain2HeadChObserver:
if ev.Type == core.Chain2HeadReorgEvent {
if len(ev.OldChain) > 1 {
observerOldChainLength = uint64(len(ev.OldChain))
return observerOldChainLength, 0
}
}
case ev := <-chain2HeadChFaulty:
if ev.Type == core.Chain2HeadReorgEvent {
if len(ev.OldChain) > 1 {
faultyOldChainLength = uint64(len(ev.OldChain))
return 0, faultyOldChainLength
}
}
default:
time.Sleep(500 * time.Millisecond)
}
}
return 0, 0
}
// nolint: gocognit
func SetupValidatorsAndTest2Nodes(t *testing.T, tt map[string]interface{}) (uint64, uint64) {
t.Helper()
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
_, err := fdlimit.Raise(2048)
if err != nil {
panic(err)
}
// Generate a batch of accounts to seal and fund with
faucets := make([]*ecdsa.PrivateKey, 128)
for i := 0; i < len(faucets); i++ {
faucets[i], _ = crypto.GenerateKey()
}
// Create an Ethash network based off of the Ropsten config
// Generate a batch of accounts to seal and fund with
genesis := InitGenesisSprintLength(t, faucets, "./testdata/genesis_7val.json", tt["sprintSize"].(uint64))
nodes := make([]*eth.Ethereum, len(keys_21val))
enodes := make([]*enode.Node, len(keys_21val))
stacks := make([]*node.Node, len(keys_21val))
pkeys_21val := make([]*ecdsa.PrivateKey, len(keys_21val))
for index, signerdata := range keys_21val {
pkeys_21val[index], _ = crypto.HexToECDSA(signerdata["priv_key"])
}
for i := 0; i < len(keys_21val); i++ {
// Start the node and wait until it's up
stack, ethBackend, err := InitMinerSprintLength(genesis, pkeys_21val[i], true)
if err != nil {
panic(err)
}
defer stack.Close()
for stack.Server().NodeInfo().Ports.Listener == 0 {
time.Sleep(250 * time.Millisecond)
}
// Connect the node to all the previous ones
for j, n := range enodes {
if j < i {
stack.Server().AddPeer(n)
}
}
// Start tracking the node and its enode
stacks[i] = stack
nodes[i] = ethBackend
enodes[i] = stack.Server().Self()
}
// Iterate over all the nodes and start mining
time.Sleep(3 * time.Second)
for _, node := range nodes {
if err := node.StartMining(1); err != nil {
panic(err)
}
}
chain2HeadChObserver := make(chan core.Chain2HeadEvent, 64)
chain2HeadChFaulty := make(chan core.Chain2HeadEvent, 64)
var observerOldChainLength, faultyOldChainLength uint64
faultyProducerIndex := tt["faultyNodes"].([]uint64)[0] // node causing reorg :: faulty ::
subscribedNodeIndex := 6 // node on different partition, produces 7th sprint but our testcase does not run till 7th sprint. :: observer ::
nodes[subscribedNodeIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChObserver)
nodes[faultyProducerIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChFaulty)
stacks[faultyProducerIndex].Server().NoDiscovery = true
for {
blockHeaderObserver := nodes[subscribedNodeIndex].BlockChain().CurrentHeader()
blockHeaderFaulty := nodes[faultyProducerIndex].BlockChain().CurrentHeader()
log.Warn("Current Observer block", "number", blockHeaderObserver.Number, "hash", blockHeaderObserver.Hash())
log.Warn("Current Faulty block", "number", blockHeaderFaulty.Number, "hash", blockHeaderFaulty.Hash())
if blockHeaderObserver.Number.Uint64() >= tt["startBlock"].(uint64) && blockHeaderObserver.Number.Uint64() < tt["startBlock"].(uint64)+tt["reorgLength"].(uint64) {
for _, n := range tt["faultyNodes"].([]uint64) {
stacks[n].Server().MaxPeers = 1
for _, enode := range enodes {
stacks[n].Server().RemovePeer(enode)
}
for _, m := range tt["faultyNodes"].([]uint64) {
stacks[m].Server().AddPeer(enodes[n])
}
}
}
if blockHeaderObserver.Number.Uint64() == tt["startBlock"].(uint64)+tt["reorgLength"].(uint64) {
stacks[faultyProducerIndex].Server().NoDiscovery = false
stacks[faultyProducerIndex].Server().MaxPeers = 100
for _, enode := range enodes {
stacks[faultyProducerIndex].Server().AddPeer(enode)
}
}
if blockHeaderFaulty.Number.Uint64() >= 255 {
break
}
select {
case ev := <-chain2HeadChObserver:
if ev.Type == core.Chain2HeadReorgEvent {
if len(ev.OldChain) > 1 {
observerOldChainLength = uint64(len(ev.OldChain))
return observerOldChainLength, 0
}
}
case ev := <-chain2HeadChFaulty:
if ev.Type == core.Chain2HeadReorgEvent {
if len(ev.OldChain) > 1 {
faultyOldChainLength = uint64(len(ev.OldChain))
return 0, faultyOldChainLength
}
}
default:
time.Sleep(500 * time.Millisecond)
}
}
return 0, 0
}
func InitGenesisSprintLength(t *testing.T, faucets []*ecdsa.PrivateKey, fileLocation string, sprintSize uint64) *core.Genesis {
t.Helper()
// sprint size = 8 in genesis
genesisData, err := ioutil.ReadFile(fileLocation)
if err != nil {
t.Fatalf("%s", err)
}
genesis := &core.Genesis{}
if err := json.Unmarshal(genesisData, genesis); err != nil {
t.Fatalf("%s", err)
}
genesis.Config.ChainID = big.NewInt(15001)
genesis.Config.EIP150Hash = common.Hash{}
genesis.Config.Bor.Sprint["0"] = sprintSize
return genesis
}
func InitMinerSprintLength(genesis *core.Genesis, privKey *ecdsa.PrivateKey, withoutHeimdall bool) (*node.Node, *eth.Ethereum, error) {
// Define the basic configurations for the Ethereum node
datadir, _ := ioutil.TempDir("", "")
config := &node.Config{
Name: "geth",
Version: params.Version,
DataDir: datadir,
P2P: p2p.Config{
ListenAddr: "0.0.0.0:0",
NoDiscovery: true,
MaxPeers: 25,
},
UseLightweightKDF: true,
}
// Create the node and configure a full Ethereum node on it
stack, err := node.New(config)
if err != nil {
return nil, nil, err
}
ethBackend, err := eth.New(stack, &ethconfig.Config{
Genesis: genesis,
NetworkId: genesis.Config.ChainID.Uint64(),
SyncMode: downloader.FullSync,
DatabaseCache: 256,
DatabaseHandles: 256,
TxPool: core.DefaultTxPoolConfig,
GPO: ethconfig.Defaults.GPO,
Ethash: ethconfig.Defaults.Ethash,
Miner: miner.Config{
Etherbase: crypto.PubkeyToAddress(privKey.PublicKey),
GasCeil: genesis.GasLimit * 11 / 10,
GasPrice: big.NewInt(1),
Recommit: time.Second,
},
WithoutHeimdall: withoutHeimdall,
})
if err != nil {
return nil, nil, err
}
// register backend to account manager with keystore for signing
keydir := stack.KeyStoreDir()
n, p := keystore.StandardScryptN, keystore.StandardScryptP
kStore := keystore.NewKeyStore(keydir, n, p)
_, err = kStore.ImportECDSA(privKey, "")
if err != nil {
return nil, nil, err
}
acc := kStore.Accounts()[0]
err = kStore.Unlock(acc, "")
if err != nil {
return nil, nil, err
}
// proceed to authorize the local account manager in any case
ethBackend.AccountManager().AddBackend(kStore)
err = stack.Start()
return stack, ethBackend, err
}

View file

@ -1,21 +1,27 @@
//go:build integration
// +build integration
package bor
import (
"context"
"crypto/ecdsa"
"encoding/hex"
"io"
"math/big"
"os"
"sync"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/sha3"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/consensus/bor"
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
@ -26,11 +32,337 @@ import (
"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/eth"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/tests/bor/mocks"
)
var (
// addr1 = 0x71562b71999873DB5b286dF957af199Ec94617F7
pkey1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
// addr2 = 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
pkey2, _ = crypto.HexToECDSA("9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3")
)
func TestValidatorWentOffline(t *testing.T) {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
fdlimit.Raise(2048)
// Generate a batch of accounts to seal and fund with
faucets := make([]*ecdsa.PrivateKey, 128)
for i := 0; i < len(faucets); i++ {
faucets[i], _ = crypto.GenerateKey()
}
// Create an Ethash network based off of the Ropsten config
// Generate a batch of accounts to seal and fund with
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
var (
stacks []*node.Node
nodes []*eth.Ethereum
enodes []*enode.Node
)
for i := 0; i < 2; i++ {
// Start the node and wait until it's up
stack, ethBackend, err := InitMiner(genesis, keys[i], true)
if err != nil {
panic(err)
}
defer stack.Close()
for stack.Server().NodeInfo().Ports.Listener == 0 {
time.Sleep(250 * time.Millisecond)
}
// Connect the node to all the previous ones
for _, n := range enodes {
stack.Server().AddPeer(n)
}
// Start tracking the node and its enode
stacks = append(stacks, stack)
nodes = append(nodes, ethBackend)
enodes = append(enodes, stack.Server().Self())
}
// Iterate over all the nodes and start mining
time.Sleep(3 * time.Second)
for _, node := range nodes {
if err := node.StartMining(1); err != nil {
panic(err)
}
}
for {
// for block 1 to 8, the primary validator is node0
// for block 9 to 16, the primary validator is node1
// for block 17 to 24, the primary validator is node0
// for block 25 to 32, the primary validator is node1
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
// we remove peer connection between node0 and node1
if blockHeaderVal0.Number.Uint64() == 9 {
stacks[0].Server().RemovePeer(enodes[1])
}
// here, node1 is the primary validator, node0 will sign out-of-turn
// we add peer connection between node1 and node0
if blockHeaderVal0.Number.Uint64() == 14 {
stacks[0].Server().AddPeer(enodes[1])
}
// reorg happens here, node1 has higher difficulty, it will replace blocks by node0
if blockHeaderVal0.Number.Uint64() == 30 {
break
}
}
// check block 10 miner ; expected author is node1 signer
blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(10)
blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(10)
authorVal0, err := nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
log.Error("Error in getting author", "err", err)
}
authorVal1, err := nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
log.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 10
assert.Equal(t, authorVal0, authorVal1)
// check node0 has block mined by node1
assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0])
// check node1 has block mined by node1
assert.Equal(t, authorVal1, nodes[1].AccountManager().Accounts()[0])
// check block 11 miner ; expected author is node1 signer
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(11)
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(11)
authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
log.Error("Error in getting author", "err", err)
}
authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
log.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 11
assert.Equal(t, authorVal0, authorVal1)
// check node0 has block mined by node1
assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0])
// check node1 has block mined by node1
assert.Equal(t, authorVal1, nodes[1].AccountManager().Accounts()[0])
// check block 12 miner ; expected author is node1 signer
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(12)
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(12)
authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
log.Error("Error in getting author", "err", err)
}
authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
log.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 12
assert.Equal(t, authorVal0, authorVal1)
// check node0 has block mined by node1
assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0])
// check node1 has block mined by node1
assert.Equal(t, authorVal1, nodes[1].AccountManager().Accounts()[0])
// check block 17 miner ; expected author is node0 signer
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(17)
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(17)
authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
log.Error("Error in getting author", "err", err)
}
authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
log.Error("Error in getting author", "err", err)
}
// check both nodes have the same block 17
assert.Equal(t, authorVal0, authorVal1)
// check node0 has block mined by node1
assert.Equal(t, authorVal0, nodes[0].AccountManager().Accounts()[0])
// check node1 has block mined by node1
assert.Equal(t, authorVal1, nodes[0].AccountManager().Accounts()[0])
}
func TestForkWithBlockTime(t *testing.T) {
cases := []struct {
name string
sprint map[string]uint64
blockTime map[string]uint64
change uint64
producerDelay map[string]uint64
forkExpected bool
}{
{
name: "No fork after 2 sprints with producer delay = max block time",
sprint: map[string]uint64{
"0": 128,
},
blockTime: map[string]uint64{
"0": 5,
"128": 2,
"256": 8,
},
change: 2,
producerDelay: map[string]uint64{
"0": 8,
},
forkExpected: false,
},
{
name: "No Fork after 1 sprint producer delay = max block time",
sprint: map[string]uint64{
"0": 64,
},
blockTime: map[string]uint64{
"0": 5,
"64": 2,
},
change: 1,
producerDelay: map[string]uint64{
"0": 5,
},
forkExpected: false,
},
{
name: "Fork after 4 sprints with producer delay < max block time",
sprint: map[string]uint64{
"0": 16,
},
blockTime: map[string]uint64{
"0": 2,
"64": 5,
},
change: 4,
producerDelay: map[string]uint64{
"0": 4,
},
forkExpected: true,
},
}
// Create an Ethash network based off of the Ropsten config
// Generate a batch of accounts to seal and fund with
faucets := make([]*ecdsa.PrivateKey, 128)
for i := 0; i < len(faucets); i++ {
faucets[i], _ = crypto.GenerateKey()
}
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
genesis.Config.Bor.Sprint = test.sprint
genesis.Config.Bor.Period = test.blockTime
genesis.Config.Bor.BackupMultiplier = test.blockTime
genesis.Config.Bor.ProducerDelay = test.producerDelay
stacks, nodes, _ := setupMiner(t, 2, genesis)
defer func() {
for _, stack := range stacks {
stack.Close()
}
}()
// Iterate over all the nodes and start mining
for _, node := range nodes {
if err := node.StartMining(1); err != nil {
t.Fatal("Error occured while starting miner", "node", node, "error", err)
}
}
var wg sync.WaitGroup
blockHeaders := make([]*types.Header, 2)
ticker := time.NewTicker(time.Duration(test.blockTime["0"]) * time.Second)
defer ticker.Stop()
for i := 0; i < 2; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
for range ticker.C {
blockHeaders[i] = nodes[i].BlockChain().GetHeaderByNumber(test.sprint["0"]*test.change + 10)
if blockHeaders[i] != nil {
break
}
}
}(i)
}
wg.Wait()
// Before the end of sprint
blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(test.sprint["0"] - 1)
blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(test.sprint["0"] - 1)
assert.Equal(t, blockHeaderVal0.Hash(), blockHeaderVal1.Hash())
assert.Equal(t, blockHeaderVal0.Time, blockHeaderVal1.Time)
author0, err := nodes[0].Engine().Author(blockHeaderVal0)
if err != nil {
t.Error("Error occured while fetching author", "err", err)
}
author1, err := nodes[1].Engine().Author(blockHeaderVal1)
if err != nil {
t.Error("Error occured while fetching author", "err", err)
}
assert.Equal(t, author0, author1)
// After the end of sprint
author2, err := nodes[0].Engine().Author(blockHeaders[0])
if err != nil {
t.Error("Error occured while fetching author", "err", err)
}
author3, err := nodes[1].Engine().Author(blockHeaders[1])
if err != nil {
t.Error("Error occured while fetching author", "err", err)
}
if test.forkExpected {
assert.NotEqual(t, blockHeaders[0].Hash(), blockHeaders[1].Hash())
assert.NotEqual(t, blockHeaders[0].Time, blockHeaders[1].Time)
assert.NotEqual(t, author2, author3)
} else {
assert.Equal(t, blockHeaders[0].Hash(), blockHeaders[1].Hash())
assert.Equal(t, blockHeaders[0].Time, blockHeaders[1].Time)
assert.Equal(t, author2, author3)
}
})
}
}
func TestInsertingSpanSizeBlocks(t *testing.T) {
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
chain := init.ethereum.BlockChain()
@ -741,11 +1073,11 @@ func TestJaipurFork(t *testing.T) {
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators)
insertNewBlock(t, chain, block)
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock-1 {
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock.Uint64()-1 {
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.Uint64() {
require.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
}
}
@ -777,7 +1109,7 @@ func testEncodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig)
header.MixDigest,
header.Nonce,
}
if c.IsJaipur(header.Number.Uint64()) {
if c.IsJaipur(header.Number) {
if header.BaseFee != nil {
enc = append(enc, header.BaseFee)
}

View file

@ -88,7 +88,7 @@ func setupMiner(t *testing.T, n int, genesis *core.Genesis) ([]*node.Node, []*et
for i := 0; i < n; i++ {
// Start the node and wait until it's up
stack, ethBackend, err := initMiner(genesis, keys[i])
stack, ethBackend, err := InitMiner(genesis, keys[i], true)
if err != nil {
t.Fatal("Error occured while initialising miner", "error", err)
}
@ -109,84 +109,6 @@ func setupMiner(t *testing.T, n int, genesis *core.Genesis) ([]*node.Node, []*et
return stacks, nodes, enodes
}
func initMiner(genesis *core.Genesis, privKey *ecdsa.PrivateKey) (*node.Node, *eth.Ethereum, error) {
// Define the basic configurations for the Ethereum node
datadir, _ := ioutil.TempDir("", "")
config := &node.Config{
Name: "geth",
Version: params.Version,
DataDir: datadir,
P2P: p2p.Config{
ListenAddr: "0.0.0.0:0",
NoDiscovery: true,
MaxPeers: 25,
},
UseLightweightKDF: true,
}
// Create the node and configure a full Ethereum node on it
stack, err := node.New(config)
if err != nil {
return nil, nil, err
}
ethBackend, err := eth.New(stack, &ethconfig.Config{
Genesis: genesis,
NetworkId: genesis.Config.ChainID.Uint64(),
SyncMode: downloader.FullSync,
DatabaseCache: 256,
DatabaseHandles: 256,
TxPool: core.DefaultTxPoolConfig,
GPO: ethconfig.Defaults.GPO,
Ethash: ethconfig.Defaults.Ethash,
Miner: miner.Config{
Etherbase: crypto.PubkeyToAddress(privKey.PublicKey),
GasCeil: genesis.GasLimit * 11 / 10,
GasPrice: big.NewInt(1),
Recommit: time.Second,
},
WithoutHeimdall: true,
})
if err != nil {
return nil, nil, err
}
// register backend to account manager with keystore for signing
keydir := stack.KeyStoreDir()
n, p := keystore.StandardScryptN, keystore.StandardScryptP
kStore := keystore.NewKeyStore(keydir, n, p)
kStore.ImportECDSA(privKey, "")
acc := kStore.Accounts()[0]
kStore.Unlock(acc, "")
// proceed to authorize the local account manager in any case
ethBackend.AccountManager().AddBackend(kStore)
err = stack.Start()
return stack, ethBackend, err
}
func initGenesis(t *testing.T) *core.Genesis {
t.Helper()
// sprint size = 8 in genesis
genesisData, err := ioutil.ReadFile("./testdata/genesis_2val.json")
if err != nil {
t.Fatalf("%s", err)
}
genesis := &core.Genesis{}
if err := json.Unmarshal(genesisData, genesis); err != nil {
t.Fatalf("%s", err)
}
genesis.Config.ChainID = big.NewInt(15001)
genesis.Config.EIP150Hash = common.Hash{}
return genesis
}
func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
genesisData, err := ioutil.ReadFile("./testdata/genesis.json")
if err != nil {
@ -483,3 +405,95 @@ func IsSprintStart(number uint64) bool {
func IsSprintEnd(number uint64) bool {
return (number+1)%sprintSize == 0
}
func InitGenesis(t *testing.T, faucets []*ecdsa.PrivateKey, fileLocation string, sprintSize uint64) *core.Genesis {
t.Helper()
// sprint size = 8 in genesis
genesisData, err := ioutil.ReadFile(fileLocation)
if err != nil {
t.Fatalf("%s", err)
}
genesis := &core.Genesis{}
if err := json.Unmarshal(genesisData, genesis); err != nil {
t.Fatalf("%s", err)
}
genesis.Config.ChainID = big.NewInt(15001)
genesis.Config.EIP150Hash = common.Hash{}
genesis.Config.Bor.Sprint["0"] = sprintSize
return genesis
}
func InitMiner(genesis *core.Genesis, privKey *ecdsa.PrivateKey, withoutHeimdall bool) (*node.Node, *eth.Ethereum, error) {
// Define the basic configurations for the Ethereum node
datadir, _ := ioutil.TempDir("", "")
config := &node.Config{
Name: "geth",
Version: params.Version,
DataDir: datadir,
P2P: p2p.Config{
ListenAddr: "0.0.0.0:0",
NoDiscovery: true,
MaxPeers: 25,
},
UseLightweightKDF: true,
}
// Create the node and configure a full Ethereum node on it
stack, err := node.New(config)
if err != nil {
return nil, nil, err
}
ethBackend, err := eth.New(stack, &ethconfig.Config{
Genesis: genesis,
NetworkId: genesis.Config.ChainID.Uint64(),
SyncMode: downloader.FullSync,
DatabaseCache: 256,
DatabaseHandles: 256,
TxPool: core.DefaultTxPoolConfig,
GPO: ethconfig.Defaults.GPO,
Ethash: ethconfig.Defaults.Ethash,
Miner: miner.Config{
Etherbase: crypto.PubkeyToAddress(privKey.PublicKey),
GasCeil: genesis.GasLimit * 11 / 10,
GasPrice: big.NewInt(1),
Recommit: time.Second,
},
WithoutHeimdall: withoutHeimdall,
})
if err != nil {
return nil, nil, err
}
// register backend to account manager with keystore for signing
keydir := stack.KeyStoreDir()
n, p := keystore.StandardScryptN, keystore.StandardScryptP
kStore := keystore.NewKeyStore(keydir, n, p)
_, err = kStore.ImportECDSA(privKey, "")
if err != nil {
return nil, nil, err
}
acc := kStore.Accounts()[0]
err = kStore.Unlock(acc, "")
if err != nil {
return nil, nil, err
}
// proceed to authorize the local account manager in any case
ethBackend.AccountManager().AddBackend(kStore)
err = stack.Start()
return stack, ethBackend, err
}

View file

@ -15,11 +15,17 @@
"londonBlock": 1,
"bor": {
"jaipurBlock": 2,
"delhiBlock" :3,
"period": {
"0": 1
},
"producerDelay": 4,
"sprint": 4,
"producerDelay": {
"0": 6
},
"sprint": {
"0": 4,
"32": 2
},
"backupMultiplier": {
"0": 1
},

126
tests/bor/testdata/genesis_21val.json vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -15,11 +15,16 @@
"londonBlock": 1,
"bor": {
"jaipurBlock": 2,
"delhiBlock" :3,
"period": {
"0": 1
},
"producerDelay": 4,
"sprint": 8,
"producerDelay": {
"0": 4
},
"sprint": {
"0": 8
},
"backupMultiplier": {
"0": 1
},
@ -61,4 +66,3 @@
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}

83
tests/bor/testdata/genesis_7val.json vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long