mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
* added HTTPTimeouts, and TrieTimeout flag in new tol, from old toml * added RAW fields for these time.Duration flags * updated the conversion script to support these extra 4 flags * removed hcl and json config tests as we are only supporting toml config files * updated toml files with cache.timeout field * updated toml files with jsonrpc.timeouts field * tests/bor: expect a call for latest checkpoint * tests/bor: expect a call for latest checkpoint * packaging/templates: update cache values for archive nodes Co-authored-by: Manav Darji <manavdarji.india@gmail.com>
620 lines
20 KiB
Go
620 lines
20 KiB
Go
//go:build integration
|
|
// +build integration
|
|
|
|
package bor
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"io"
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/stretchr/testify/assert"
|
|
"golang.org/x/crypto/sha3"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
"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/params"
|
|
"github.com/ethereum/go-ethereum/rlp"
|
|
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
|
)
|
|
|
|
func TestInsertingSpanSizeBlocks(t *testing.T) {
|
|
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
|
chain := init.ethereum.BlockChain()
|
|
engine := init.ethereum.Engine()
|
|
_bor := engine.(*bor.Bor)
|
|
|
|
defer _bor.Close()
|
|
|
|
h, heimdallSpan, ctrl := getMockedHeimdallClient(t)
|
|
defer ctrl.Finish()
|
|
|
|
_, span := loadSpanFromFile(t)
|
|
|
|
h.EXPECT().Close().AnyTimes()
|
|
h.EXPECT().FetchLatestCheckpoint().Return(&checkpoint.Checkpoint{
|
|
Proposer: span.SelectedProducers[0].Address,
|
|
StartBlock: big.NewInt(0),
|
|
EndBlock: big.NewInt(int64(spanSize)),
|
|
}, nil).AnyTimes()
|
|
|
|
_bor.SetHeimdallClient(h)
|
|
|
|
db := init.ethereum.ChainDb()
|
|
block := init.genesis.ToBlock(db)
|
|
// to := int64(block.Header().Time)
|
|
|
|
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
|
for i := uint64(1); i <= spanSize; i++ {
|
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
|
insertNewBlock(t, chain, block)
|
|
}
|
|
|
|
validators, err := _bor.GetCurrentValidators(block.Hash(), spanSize) // check validator set at the first block of new span
|
|
if err != nil {
|
|
t.Fatalf("%s", err)
|
|
}
|
|
|
|
assert.Equal(t, 3, len(validators))
|
|
for i, validator := range validators {
|
|
assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes())
|
|
assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower)
|
|
}
|
|
}
|
|
|
|
func TestFetchStateSyncEvents(t *testing.T) {
|
|
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
|
chain := init.ethereum.BlockChain()
|
|
engine := init.ethereum.Engine()
|
|
_bor := engine.(*bor.Bor)
|
|
|
|
defer _bor.Close()
|
|
|
|
// A. Insert blocks for 0th sprint
|
|
db := init.ethereum.ChainDb()
|
|
block := init.genesis.ToBlock(db)
|
|
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
|
for i := uint64(1); i < sprintSize; i++ {
|
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
|
insertNewBlock(t, chain, block)
|
|
}
|
|
|
|
// B. Before inserting 1st block of the next sprint, mock heimdall deps
|
|
// B.1 Mock /bor/span/1
|
|
res, _ := loadSpanFromFile(t)
|
|
|
|
ctrl := gomock.NewController(t)
|
|
defer ctrl.Finish()
|
|
|
|
h := mocks.NewMockIHeimdallClient(ctrl)
|
|
h.EXPECT().Close().AnyTimes()
|
|
h.EXPECT().Span(uint64(1)).Return(&res.Result, nil).AnyTimes()
|
|
h.EXPECT().FetchLatestCheckpoint().Return(&checkpoint.Checkpoint{
|
|
StartBlock: big.NewInt(1),
|
|
EndBlock: big.NewInt(2),
|
|
RootHash: common.Hash{},
|
|
}, nil).AnyTimes()
|
|
|
|
// B.2 Mock State Sync events
|
|
fromID := uint64(1)
|
|
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
|
to := int64(chain.GetHeaderByNumber(0).Time)
|
|
eventCount := 50
|
|
|
|
sample := getSampleEventRecord(t)
|
|
sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to
|
|
eventRecords := generateFakeStateSyncEvents(sample, eventCount)
|
|
|
|
h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes()
|
|
_bor.SetHeimdallClient(h)
|
|
|
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
|
insertNewBlock(t, chain, block)
|
|
}
|
|
|
|
func TestFetchStateSyncEvents_2(t *testing.T) {
|
|
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
|
chain := init.ethereum.BlockChain()
|
|
engine := init.ethereum.Engine()
|
|
_bor := engine.(*bor.Bor)
|
|
|
|
defer _bor.Close()
|
|
|
|
// Mock /bor/span/1
|
|
res, _ := loadSpanFromFile(t)
|
|
|
|
ctrl := gomock.NewController(t)
|
|
defer ctrl.Finish()
|
|
|
|
h := mocks.NewMockIHeimdallClient(ctrl)
|
|
h.EXPECT().Close().AnyTimes()
|
|
h.EXPECT().Span(uint64(1)).Return(&res.Result, nil).AnyTimes()
|
|
h.EXPECT().FetchLatestCheckpoint().Return(&checkpoint.Checkpoint{
|
|
StartBlock: big.NewInt(1),
|
|
EndBlock: big.NewInt(2),
|
|
RootHash: common.Hash{},
|
|
}, nil).AnyTimes()
|
|
|
|
// Mock State Sync events
|
|
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
|
fromID := uint64(1)
|
|
to := int64(chain.GetHeaderByNumber(0).Time)
|
|
sample := getSampleEventRecord(t)
|
|
|
|
// First query will be from [id=1, (block-sprint).Time]
|
|
// Insert 5 events in this time range
|
|
eventRecords := []*clerk.EventRecordWithTime{
|
|
buildStateEvent(sample, 1, 3), // id = 1, time = 1
|
|
buildStateEvent(sample, 2, 1), // id = 2, time = 3
|
|
buildStateEvent(sample, 3, 2), // id = 3, time = 2
|
|
// event with id 5 is missing
|
|
buildStateEvent(sample, 4, 5), // id = 4, time = 5
|
|
buildStateEvent(sample, 6, 4), // id = 6, time = 4
|
|
}
|
|
|
|
h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes()
|
|
_bor.SetHeimdallClient(h)
|
|
|
|
// Insert blocks for 0th sprint
|
|
db := init.ethereum.ChainDb()
|
|
block := init.genesis.ToBlock(db)
|
|
for i := uint64(1); i <= sprintSize; i++ {
|
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
|
insertNewBlock(t, chain, block)
|
|
}
|
|
|
|
lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize)
|
|
|
|
// state 6 was not written
|
|
assert.Equal(t, uint64(4), lastStateID.Uint64())
|
|
|
|
//
|
|
fromID = uint64(5)
|
|
to = int64(chain.GetHeaderByNumber(sprintSize).Time)
|
|
|
|
eventRecords = []*clerk.EventRecordWithTime{
|
|
buildStateEvent(sample, 5, 7),
|
|
buildStateEvent(sample, 6, 4),
|
|
}
|
|
h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes()
|
|
|
|
for i := sprintSize + 1; i <= spanSize; i++ {
|
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
|
insertNewBlock(t, chain, block)
|
|
}
|
|
|
|
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
|
|
assert.Equal(t, uint64(6), lastStateID.Uint64())
|
|
}
|
|
|
|
func TestOutOfTurnSigning(t *testing.T) {
|
|
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
|
chain := init.ethereum.BlockChain()
|
|
engine := init.ethereum.Engine()
|
|
_bor := engine.(*bor.Bor)
|
|
|
|
defer _bor.Close()
|
|
|
|
h, _, ctrl := getMockedHeimdallClient(t)
|
|
defer ctrl.Finish()
|
|
|
|
h.EXPECT().Close().AnyTimes()
|
|
_bor.SetHeimdallClient(h)
|
|
|
|
db := init.ethereum.ChainDb()
|
|
block := init.genesis.ToBlock(db)
|
|
|
|
for i := uint64(1); i < spanSize; i++ {
|
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
|
insertNewBlock(t, chain, block)
|
|
}
|
|
|
|
// insert spanSize-th block
|
|
// This account is one the out-of-turn validators for 1st (0-indexed) span
|
|
signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
|
|
signerKey, _ := hex.DecodeString(signer)
|
|
key, _ = crypto.HexToECDSA(signer)
|
|
addr = crypto.PubkeyToAddress(key.PublicKey)
|
|
expectedSuccessionNumber := 2
|
|
|
|
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
|
|
_, err := chain.InsertChain([]*types.Block{block})
|
|
assert.Equal(t,
|
|
*err.(*bor.BlockTooSoonError),
|
|
bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber})
|
|
|
|
expectedDifficulty := uint64(3 - expectedSuccessionNumber) // len(validators) - succession
|
|
header := block.Header()
|
|
header.Time += (bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) -
|
|
bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor))
|
|
sign(t, header, signerKey, init.genesis.Config.Bor)
|
|
block = types.NewBlockWithHeader(header)
|
|
|
|
_, err = chain.InsertChain([]*types.Block{block})
|
|
assert.Equal(t,
|
|
*err.(*bor.WrongDifficultyError),
|
|
bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()})
|
|
|
|
header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
|
|
sign(t, header, signerKey, init.genesis.Config.Bor)
|
|
block = types.NewBlockWithHeader(header)
|
|
|
|
_, err = chain.InsertChain([]*types.Block{block})
|
|
assert.Nil(t, err)
|
|
}
|
|
|
|
func TestSignerNotFound(t *testing.T) {
|
|
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
|
chain := init.ethereum.BlockChain()
|
|
engine := init.ethereum.Engine()
|
|
_bor := engine.(*bor.Bor)
|
|
|
|
defer _bor.Close()
|
|
|
|
h, _, ctrl := getMockedHeimdallClient(t)
|
|
defer ctrl.Finish()
|
|
|
|
h.EXPECT().Close().AnyTimes()
|
|
|
|
_bor.SetHeimdallClient(h)
|
|
|
|
db := init.ethereum.ChainDb()
|
|
block := init.genesis.ToBlock(db)
|
|
|
|
// random signer account that is not a part of the validator set
|
|
signer := "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b"
|
|
signerKey, _ := hex.DecodeString(signer)
|
|
key, _ = crypto.HexToECDSA(signer)
|
|
addr = crypto.PubkeyToAddress(key.PublicKey)
|
|
|
|
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
|
|
_, err := chain.InsertChain([]*types.Block{block})
|
|
assert.Equal(t,
|
|
*err.(*bor.UnauthorizedSignerError),
|
|
bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()})
|
|
}
|
|
|
|
func getMockedHeimdallClient(t *testing.T) (*mocks.MockIHeimdallClient, *span.HeimdallSpan, *gomock.Controller) {
|
|
ctrl := gomock.NewController(t)
|
|
h := mocks.NewMockIHeimdallClient(ctrl)
|
|
|
|
_, heimdallSpan := loadSpanFromFile(t)
|
|
|
|
h.EXPECT().Span(uint64(1)).Return(heimdallSpan, nil).AnyTimes()
|
|
|
|
h.EXPECT().StateSyncEvents(gomock.Any(), gomock.Any()).
|
|
Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes()
|
|
|
|
// h.EXPECT().FetchLatestCheckpoint().Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes()
|
|
|
|
return h, heimdallSpan, ctrl
|
|
}
|
|
|
|
func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime {
|
|
events := make([]*clerk.EventRecordWithTime, count)
|
|
event := *sample
|
|
event.ID = 1
|
|
events[0] = &clerk.EventRecordWithTime{}
|
|
*events[0] = event
|
|
for i := 1; i < count; i++ {
|
|
event.ID = uint64(i)
|
|
event.Time = event.Time.Add(1 * time.Second)
|
|
events[i] = &clerk.EventRecordWithTime{}
|
|
*events[i] = event
|
|
}
|
|
return events
|
|
}
|
|
|
|
func buildStateEvent(sample *clerk.EventRecordWithTime, id uint64, timeStamp int64) *clerk.EventRecordWithTime {
|
|
event := *sample
|
|
event.ID = id
|
|
event.Time = time.Unix(timeStamp, 0)
|
|
return &event
|
|
}
|
|
|
|
func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime {
|
|
eventRecords := stateSyncEventsPayload(t)
|
|
eventRecords.Result[0].Time = time.Unix(1, 0)
|
|
return eventRecords.Result[0]
|
|
}
|
|
|
|
func getEventRecords(t *testing.T) []*clerk.EventRecordWithTime {
|
|
return stateSyncEventsPayload(t).Result
|
|
}
|
|
|
|
// TestEIP1559Transition tests the following:
|
|
//
|
|
// 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")
|
|
|
|
// Generate a canonical chain to act as the main dataset
|
|
db = rawdb.NewMemoryDatabase()
|
|
engine = ethash.NewFaker()
|
|
|
|
// A sender who makes transactions, has some funds
|
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
|
key3, _ = crypto.HexToECDSA("225171aed3793cba1c029832886d69785b7e77a54a44211226b447aa2d16b058")
|
|
|
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
|
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
|
gspec = &core.Genesis{
|
|
Config: params.BorTestChainConfig,
|
|
Alloc: core.GenesisAlloc{
|
|
addr1: {Balance: funds},
|
|
addr2: {Balance: funds},
|
|
addr3: {Balance: funds},
|
|
// The address 0xAAAA sloads 0x00 and 0x01
|
|
aa: {
|
|
Code: []byte{
|
|
byte(vm.PC),
|
|
byte(vm.PC),
|
|
byte(vm.SLOAD),
|
|
byte(vm.SLOAD),
|
|
},
|
|
Nonce: 0,
|
|
Balance: big.NewInt(0),
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
gspec.Config.BerlinBlock = common.Big0
|
|
gspec.Config.LondonBlock = common.Big0
|
|
genesis := gspec.MustCommit(db)
|
|
signer := types.LatestSigner(gspec.Config)
|
|
|
|
blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) {
|
|
b.SetCoinbase(common.Address{1})
|
|
// One transaction to 0xAAAA
|
|
accesses := types.AccessList{types.AccessTuple{
|
|
Address: aa,
|
|
StorageKeys: []common.Hash{{0}},
|
|
}}
|
|
|
|
txdata := &types.DynamicFeeTx{
|
|
ChainID: gspec.Config.ChainID,
|
|
Nonce: 0,
|
|
To: &aa,
|
|
Gas: 30000,
|
|
GasFeeCap: newGwei(5),
|
|
GasTipCap: big.NewInt(2),
|
|
AccessList: accesses,
|
|
Data: []byte{},
|
|
}
|
|
tx := types.NewTx(txdata)
|
|
tx, _ = types.SignTx(tx, signer, key1)
|
|
|
|
b.AddTx(tx)
|
|
})
|
|
|
|
diskdb := rawdb.NewMemoryDatabase()
|
|
gspec.MustCommit(diskdb)
|
|
|
|
chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to create tester chain: %v", err)
|
|
}
|
|
if n, err := chain.InsertChain(blocks); err != nil {
|
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
|
}
|
|
|
|
block := chain.GetBlockByNumber(1)
|
|
|
|
// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage.
|
|
expectedGas := params.TxGas + params.TxAccessListAddressGas + params.TxAccessListStorageKeyGas +
|
|
vm.GasQuickStep*2 + params.WarmStorageReadCostEIP2929 + params.ColdSloadCostEIP2929
|
|
if block.GasUsed() != expectedGas {
|
|
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed())
|
|
}
|
|
|
|
state, _ := chain.State()
|
|
|
|
// 3: Ensure that miner received only the tx's tip.
|
|
actual := state.GetBalance(block.Coinbase())
|
|
expected := new(big.Int).Add(
|
|
new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()),
|
|
ethash.ConstantinopleBlockReward,
|
|
)
|
|
if actual.Cmp(expected) != 0 {
|
|
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
|
}
|
|
|
|
// check burnt contract balance
|
|
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
|
expected = new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee())
|
|
burntContractBalance := expected
|
|
if actual.Cmp(expected) != 0 {
|
|
t.Fatalf("burnt contract balance incorrect: expected %d, got %d", expected, actual)
|
|
}
|
|
|
|
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
|
|
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
|
|
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
|
|
if actual.Cmp(expected) != 0 {
|
|
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
|
}
|
|
|
|
blocks, _ = core.GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *core.BlockGen) {
|
|
b.SetCoinbase(common.Address{2})
|
|
|
|
txdata := &types.LegacyTx{
|
|
Nonce: 0,
|
|
To: &aa,
|
|
Gas: 30000,
|
|
GasPrice: newGwei(5),
|
|
}
|
|
tx := types.NewTx(txdata)
|
|
tx, _ = types.SignTx(tx, signer, key2)
|
|
|
|
b.AddTx(tx)
|
|
})
|
|
|
|
if n, err := chain.InsertChain(blocks); err != nil {
|
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
|
}
|
|
|
|
block = chain.GetBlockByNumber(2)
|
|
state, _ = chain.State()
|
|
effectiveTip := block.Transactions()[0].GasTipCap().Uint64() - block.BaseFee().Uint64()
|
|
|
|
// 6+5: Ensure that miner received only the tx's effective tip.
|
|
actual = state.GetBalance(block.Coinbase())
|
|
expected = new(big.Int).Add(
|
|
new(big.Int).SetUint64(block.GasUsed()*effectiveTip),
|
|
ethash.ConstantinopleBlockReward,
|
|
)
|
|
if actual.Cmp(expected) != 0 {
|
|
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
|
}
|
|
|
|
// check burnt contract balance
|
|
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
|
expected = new(big.Int).Add(burntContractBalance, new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee()))
|
|
burntContractBalance = expected
|
|
if actual.Cmp(expected) != 0 {
|
|
t.Fatalf("burnt contract balance incorrect: expected %d, got %d", expected, actual)
|
|
}
|
|
|
|
// 4: Ensure the tx sender paid for the gasUsed * (effectiveTip + block baseFee).
|
|
actual = new(big.Int).Sub(funds, state.GetBalance(addr2))
|
|
expected = new(big.Int).SetUint64(block.GasUsed() * (effectiveTip + block.BaseFee().Uint64()))
|
|
if actual.Cmp(expected) != 0 {
|
|
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
|
}
|
|
|
|
blocks, _ = core.GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *core.BlockGen) {
|
|
b.SetCoinbase(common.Address{3})
|
|
|
|
txdata := &types.LegacyTx{
|
|
Nonce: 0,
|
|
To: &aa,
|
|
Gas: 30000,
|
|
GasPrice: newGwei(5),
|
|
}
|
|
tx := types.NewTx(txdata)
|
|
tx, _ = types.SignTx(tx, signer, key3)
|
|
|
|
b.AddTx(tx)
|
|
|
|
accesses := types.AccessList{types.AccessTuple{
|
|
Address: aa,
|
|
StorageKeys: []common.Hash{{0}},
|
|
}}
|
|
|
|
txdata2 := &types.DynamicFeeTx{
|
|
ChainID: gspec.Config.ChainID,
|
|
Nonce: 1,
|
|
To: &aa,
|
|
Gas: 30000,
|
|
GasFeeCap: newGwei(5),
|
|
GasTipCap: big.NewInt(2),
|
|
AccessList: accesses,
|
|
Data: []byte{},
|
|
}
|
|
tx = types.NewTx(txdata2)
|
|
tx, _ = types.SignTx(tx, signer, key3)
|
|
|
|
b.AddTx(tx)
|
|
|
|
})
|
|
|
|
if n, err := chain.InsertChain(blocks); err != nil {
|
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
|
}
|
|
|
|
block = chain.GetBlockByNumber(3)
|
|
state, _ = chain.State()
|
|
|
|
// check burnt contract balance
|
|
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
|
burntAmount := new(big.Int).Mul(
|
|
block.BaseFee(),
|
|
big.NewInt(int64(block.GasUsed())),
|
|
)
|
|
expected = new(big.Int).Add(burntContractBalance, burntAmount)
|
|
if actual.Cmp(expected) != 0 {
|
|
t.Fatalf("burnt contract balance incorrect: expected %d, got %d", expected, actual)
|
|
}
|
|
}
|
|
|
|
func newGwei(n int64) *big.Int {
|
|
return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei))
|
|
}
|
|
|
|
func TestJaipurFork(t *testing.T) {
|
|
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
|
chain := init.ethereum.BlockChain()
|
|
engine := init.ethereum.Engine()
|
|
_bor := engine.(*bor.Bor)
|
|
db := init.ethereum.ChainDb()
|
|
block := init.genesis.ToBlock(db)
|
|
for i := uint64(1); i < sprintSize; i++ {
|
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
|
insertNewBlock(t, chain, block)
|
|
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock-1 {
|
|
assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
|
}
|
|
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock {
|
|
assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
|
}
|
|
}
|
|
}
|
|
|
|
// SealHash returns the hash of a block prior to it being sealed.
|
|
func testSealHash(header *types.Header, c *params.BorConfig) (hash common.Hash) {
|
|
hasher := sha3.NewLegacyKeccak256()
|
|
testEncodeSigHeader(hasher, header, c)
|
|
hasher.Sum(hash[:0])
|
|
return hash
|
|
}
|
|
|
|
func testEncodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) {
|
|
enc := []interface{}{
|
|
header.ParentHash,
|
|
header.UncleHash,
|
|
header.Coinbase,
|
|
header.Root,
|
|
header.TxHash,
|
|
header.ReceiptHash,
|
|
header.Bloom,
|
|
header.Difficulty,
|
|
header.Number,
|
|
header.GasLimit,
|
|
header.GasUsed,
|
|
header.Time,
|
|
header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
|
|
header.MixDigest,
|
|
header.Nonce,
|
|
}
|
|
if c.IsJaipur(header.Number.Uint64()) {
|
|
if header.BaseFee != nil {
|
|
enc = append(enc, header.BaseFee)
|
|
}
|
|
}
|
|
if err := rlp.Encode(w, enc); err != nil {
|
|
panic("can't encode: " + err.Error())
|
|
}
|
|
}
|