mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +00:00
Merge branch 'develop' of https://github.com/maticnetwork/bor into raneet10/pos-535
This commit is contained in:
commit
dfa051483f
35 changed files with 1917 additions and 545 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -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
2
.gitignore
vendored
|
|
@ -53,3 +53,5 @@ profile.cov
|
|||
./bor-debug-*
|
||||
|
||||
dist
|
||||
|
||||
*.csv
|
||||
|
|
|
|||
|
|
@ -18,8 +18,12 @@
|
|||
"period": {
|
||||
"0": 2
|
||||
},
|
||||
"producerDelay": 6,
|
||||
"sprint": 64,
|
||||
"producerDelay": {
|
||||
"0": 6
|
||||
},
|
||||
"sprint": {
|
||||
"0": 64
|
||||
},
|
||||
"backupMultiplier": {
|
||||
"0": 2
|
||||
},
|
||||
|
|
|
|||
|
|
@ -19,8 +19,12 @@
|
|||
"0": 2,
|
||||
"25275000": 5
|
||||
},
|
||||
"producerDelay": 6,
|
||||
"sprint": 64,
|
||||
"producerDelay": {
|
||||
"0": 6
|
||||
},
|
||||
"sprint": {
|
||||
"0": 64
|
||||
},
|
||||
"backupMultiplier": {
|
||||
"0": 2,
|
||||
"25275000": 5
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
if IsSprintStart(headerNumber, c.config.Sprint) {
|
||||
if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) {
|
||||
ctx := context.Background()
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ func TestGenesisContractChange(t *testing.T) {
|
|||
|
||||
b := &Bor{
|
||||
config: ¶ms.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, ¶ms.BorConfig{JaipurBlock: 10})
|
||||
hash := SealHash(h, ¶ms.BorConfig{JaipurBlock: big.NewInt(10)})
|
||||
require.Equal(t, hash, hashWithoutBaseFee)
|
||||
|
||||
// Jaipur enabled (Jaipur=0) and BaseFee not set
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 0})
|
||||
hash = SealHash(h, ¶ms.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, ¶ms.BorConfig{JaipurBlock: 1})
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: common.Big1})
|
||||
require.Equal(t, hash, hashWithBaseFee)
|
||||
|
||||
// Jaipur NOT enabled and BaseFee set
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: big.NewInt(10)})
|
||||
require.Equal(t, hash, hashWithoutBaseFee)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -59,9 +59,10 @@ 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)
|
||||
parentGasTarget = parent.GasLimit / params.ElasticityMultiplier
|
||||
parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget)
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
backend Backend
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -29,12 +29,16 @@ var mainnetBor = &Chain{
|
|||
BerlinBlock: big.NewInt(14750000),
|
||||
LondonBlock: big.NewInt(23850000),
|
||||
Bor: ¶ms.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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -29,13 +29,17 @@ var mumbaiTestnet = &Chain{
|
|||
BerlinBlock: big.NewInt(13996000),
|
||||
LondonBlock: big.NewInt(22640000),
|
||||
Bor: ¶ms.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,
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,8 +452,10 @@ 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"}}}
|
||||
TestRules = TestChainConfig.Rules(new(big.Int), false)
|
||||
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)
|
||||
)
|
||||
|
||||
// TrustedCheckpoint represents a set of post-processed trie roots (CHT and
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -119,9 +119,11 @@ const (
|
|||
// Introduced in Tangerine Whistle (Eip 150)
|
||||
CreateBySelfdestructGas uint64 = 25000
|
||||
|
||||
BaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks.
|
||||
ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have.
|
||||
InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 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.
|
||||
|
||||
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,7 +43,8 @@ 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
|
||||
//
|
||||
// "1.8.13-unstable-21c059b6" for unstable releases
|
||||
func ArchiveVersion(gitCommit string) string {
|
||||
vsn := Version
|
||||
if VersionMeta != "stable" {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
855
tests/bor/bor_sprint_length_change_test.go
Normal file
855
tests/bor/bor_sprint_length_change_test.go
Normal 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, ðconfig.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
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
@ -341,13 +673,13 @@ func TestSignerNotFound(t *testing.T) {
|
|||
|
||||
// TestEIP1559Transition tests the following:
|
||||
//
|
||||
// 1. A transaction whose gasFeeCap is greater than the baseFee is valid.
|
||||
// 2. Gas accounting for access lists on EIP-1559 transactions is correct.
|
||||
// 3. Only the transaction's tip will be received by the coinbase.
|
||||
// 4. The transaction sender pays for both the tip and baseFee.
|
||||
// 5. The coinbase receives only the partially realized tip when
|
||||
// gasFeeCap - gasTipCap < baseFee.
|
||||
// 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap).
|
||||
// 1. A transaction whose gasFeeCap is greater than the baseFee is valid.
|
||||
// 2. Gas accounting for access lists on EIP-1559 transactions is correct.
|
||||
// 3. Only the transaction's tip will be received by the coinbase.
|
||||
// 4. The transaction sender pays for both the tip and baseFee.
|
||||
// 5. The coinbase receives only the partially realized tip when
|
||||
// gasFeeCap - gasTipCap < baseFee.
|
||||
// 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap).
|
||||
func TestEIP1559Transition(t *testing.T) {
|
||||
var (
|
||||
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, ðconfig.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, ðconfig.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
|
||||
}
|
||||
|
|
|
|||
10
tests/bor/testdata/genesis.json
vendored
10
tests/bor/testdata/genesis.json
vendored
|
|
@ -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
126
tests/bor/testdata/genesis_21val.json
vendored
Normal file
File diff suppressed because one or more lines are too long
10
tests/bor/testdata/genesis_2val.json
vendored
10
tests/bor/testdata/genesis_2val.json
vendored
|
|
@ -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
83
tests/bor/testdata/genesis_7val.json
vendored
Normal file
File diff suppressed because one or more lines are too long
69
tests/bor/testdata/genesis_sprint_length_change.json
vendored
Normal file
69
tests/bor/testdata/genesis_sprint_length_change.json
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue