github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/tests/bor/bor_test.go (about)

     1  package bor
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"io"
     7  	"math/big"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/ethereum/go-ethereum/common"
    12  	"github.com/ethereum/go-ethereum/consensus/bor"
    13  	"github.com/ethereum/go-ethereum/consensus/ethash"
    14  	"github.com/ethereum/go-ethereum/core"
    15  	"github.com/ethereum/go-ethereum/core/rawdb"
    16  	"github.com/ethereum/go-ethereum/core/types"
    17  	"github.com/ethereum/go-ethereum/core/vm"
    18  	"github.com/ethereum/go-ethereum/crypto"
    19  	"github.com/ethereum/go-ethereum/params"
    20  	"github.com/ethereum/go-ethereum/rlp"
    21  	"github.com/ethereum/go-ethereum/tests/bor/mocks"
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/mock"
    24  	"golang.org/x/crypto/sha3"
    25  )
    26  
    27  var (
    28  	spanPath         = "bor/span/1"
    29  	clerkPath        = "clerk/event-record/list"
    30  	clerkQueryParams = "from-time=%d&to-time=%d&page=%d&limit=50"
    31  )
    32  
    33  func TestInsertingSpanSizeBlocks(t *testing.T) {
    34  	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
    35  	chain := init.ethereum.BlockChain()
    36  	engine := init.ethereum.Engine()
    37  	_bor := engine.(*bor.Bor)
    38  	h, heimdallSpan := getMockedHeimdallClient(t)
    39  	_bor.SetHeimdallClient(h)
    40  
    41  	db := init.ethereum.ChainDb()
    42  	block := init.genesis.ToBlock(db)
    43  	// to := int64(block.Header().Time)
    44  
    45  	// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
    46  	for i := uint64(1); i <= spanSize; i++ {
    47  		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
    48  		insertNewBlock(t, chain, block)
    49  	}
    50  
    51  	assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
    52  	validators, err := _bor.GetCurrentValidators(block.Hash(), spanSize) // check validator set at the first block of new span
    53  	if err != nil {
    54  		t.Fatalf("%s", err)
    55  	}
    56  
    57  	assert.Equal(t, 3, len(validators))
    58  	for i, validator := range validators {
    59  		assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes())
    60  		assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower)
    61  	}
    62  }
    63  
    64  func TestFetchStateSyncEvents(t *testing.T) {
    65  	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
    66  	chain := init.ethereum.BlockChain()
    67  	engine := init.ethereum.Engine()
    68  	_bor := engine.(*bor.Bor)
    69  
    70  	// A. Insert blocks for 0th sprint
    71  	db := init.ethereum.ChainDb()
    72  	block := init.genesis.ToBlock(db)
    73  	// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
    74  	for i := uint64(1); i < sprintSize; i++ {
    75  		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
    76  		insertNewBlock(t, chain, block)
    77  	}
    78  
    79  	// B. Before inserting 1st block of the next sprint, mock heimdall deps
    80  	// B.1 Mock /bor/span/1
    81  	res, _ := loadSpanFromFile(t)
    82  	h := &mocks.IHeimdallClient{}
    83  	h.On("FetchWithRetry", spanPath, "").Return(res, nil)
    84  
    85  	// B.2 Mock State Sync events
    86  	fromID := uint64(1)
    87  	// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
    88  	to := int64(chain.GetHeaderByNumber(0).Time)
    89  	eventCount := 50
    90  
    91  	sample := getSampleEventRecord(t)
    92  	sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to
    93  	eventRecords := generateFakeStateSyncEvents(sample, eventCount)
    94  	h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
    95  	_bor.SetHeimdallClient(h)
    96  
    97  	block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
    98  	insertNewBlock(t, chain, block)
    99  
   100  	assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
   101  	assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
   102  }
   103  
   104  func TestFetchStateSyncEvents_2(t *testing.T) {
   105  	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
   106  	chain := init.ethereum.BlockChain()
   107  	engine := init.ethereum.Engine()
   108  	_bor := engine.(*bor.Bor)
   109  
   110  	// Mock /bor/span/1
   111  	res, _ := loadSpanFromFile(t)
   112  	h := &mocks.IHeimdallClient{}
   113  	h.On("FetchWithRetry", spanPath, "").Return(res, nil)
   114  
   115  	// Mock State Sync events
   116  	// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
   117  	fromID := uint64(1)
   118  	to := int64(chain.GetHeaderByNumber(0).Time)
   119  	sample := getSampleEventRecord(t)
   120  
   121  	// First query will be from [id=1, (block-sprint).Time]
   122  	// Insert 5 events in this time range
   123  	eventRecords := []*bor.EventRecordWithTime{
   124  		buildStateEvent(sample, 1, 3), // id = 1, time = 1
   125  		buildStateEvent(sample, 2, 1), // id = 2, time = 3
   126  		buildStateEvent(sample, 3, 2), // id = 3, time = 2
   127  		// event with id 5 is missing
   128  		buildStateEvent(sample, 4, 5), // id = 4, time = 5
   129  		buildStateEvent(sample, 6, 4), // id = 6, time = 4
   130  	}
   131  	h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
   132  	_bor.SetHeimdallClient(h)
   133  
   134  	// Insert blocks for 0th sprint
   135  	db := init.ethereum.ChainDb()
   136  	block := init.genesis.ToBlock(db)
   137  	for i := uint64(1); i <= sprintSize; i++ {
   138  		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
   139  		insertNewBlock(t, chain, block)
   140  	}
   141  	assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
   142  	assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
   143  	lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize)
   144  	// state 6 was not written
   145  	assert.Equal(t, uint64(4), lastStateID.Uint64())
   146  
   147  	//
   148  	fromID = uint64(5)
   149  	to = int64(chain.GetHeaderByNumber(sprintSize).Time)
   150  	eventRecords = []*bor.EventRecordWithTime{
   151  		buildStateEvent(sample, 5, 7),
   152  		buildStateEvent(sample, 6, 4),
   153  	}
   154  	h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
   155  	for i := sprintSize + 1; i <= spanSize; i++ {
   156  		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
   157  		insertNewBlock(t, chain, block)
   158  	}
   159  	assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
   160  	lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
   161  	assert.Equal(t, uint64(6), lastStateID.Uint64())
   162  }
   163  
   164  func TestOutOfTurnSigning(t *testing.T) {
   165  	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
   166  	chain := init.ethereum.BlockChain()
   167  	engine := init.ethereum.Engine()
   168  	_bor := engine.(*bor.Bor)
   169  	h, _ := getMockedHeimdallClient(t)
   170  	_bor.SetHeimdallClient(h)
   171  
   172  	db := init.ethereum.ChainDb()
   173  	block := init.genesis.ToBlock(db)
   174  
   175  	for i := uint64(1); i < spanSize; i++ {
   176  		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
   177  		insertNewBlock(t, chain, block)
   178  	}
   179  
   180  	// insert spanSize-th block
   181  	// This account is one the out-of-turn validators for 1st (0-indexed) span
   182  	signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
   183  	signerKey, _ := hex.DecodeString(signer)
   184  	key, _ = crypto.HexToECDSA(signer)
   185  	addr = crypto.PubkeyToAddress(key.PublicKey)
   186  	expectedSuccessionNumber := 2
   187  
   188  	block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
   189  	_, err := chain.InsertChain([]*types.Block{block})
   190  	assert.Equal(t,
   191  		*err.(*bor.BlockTooSoonError),
   192  		bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber})
   193  
   194  	expectedDifficulty := uint64(3 - expectedSuccessionNumber) // len(validators) - succession
   195  	header := block.Header()
   196  	header.Time += (bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) -
   197  		bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor))
   198  	sign(t, header, signerKey, init.genesis.Config.Bor)
   199  	block = types.NewBlockWithHeader(header)
   200  	_, err = chain.InsertChain([]*types.Block{block})
   201  	assert.Equal(t,
   202  		*err.(*bor.WrongDifficultyError),
   203  		bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()})
   204  
   205  	header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
   206  	sign(t, header, signerKey, init.genesis.Config.Bor)
   207  	block = types.NewBlockWithHeader(header)
   208  	_, err = chain.InsertChain([]*types.Block{block})
   209  	assert.Nil(t, err)
   210  }
   211  
   212  func TestSignerNotFound(t *testing.T) {
   213  	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
   214  	chain := init.ethereum.BlockChain()
   215  	engine := init.ethereum.Engine()
   216  	_bor := engine.(*bor.Bor)
   217  	h, _ := getMockedHeimdallClient(t)
   218  	_bor.SetHeimdallClient(h)
   219  
   220  	db := init.ethereum.ChainDb()
   221  	block := init.genesis.ToBlock(db)
   222  
   223  	// random signer account that is not a part of the validator set
   224  	signer := "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b"
   225  	signerKey, _ := hex.DecodeString(signer)
   226  	key, _ = crypto.HexToECDSA(signer)
   227  	addr = crypto.PubkeyToAddress(key.PublicKey)
   228  
   229  	block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
   230  	_, err := chain.InsertChain([]*types.Block{block})
   231  	assert.Equal(t,
   232  		*err.(*bor.UnauthorizedSignerError),
   233  		bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()})
   234  }
   235  
   236  func getMockedHeimdallClient(t *testing.T) (*mocks.IHeimdallClient, *bor.HeimdallSpan) {
   237  	res, heimdallSpan := loadSpanFromFile(t)
   238  	h := &mocks.IHeimdallClient{}
   239  	h.On("FetchWithRetry", "bor/span/1", "").Return(res, nil)
   240  	h.On(
   241  		"FetchStateSyncEvents",
   242  		mock.AnythingOfType("uint64"),
   243  		mock.AnythingOfType("int64")).Return([]*bor.EventRecordWithTime{getSampleEventRecord(t)}, nil)
   244  	return h, heimdallSpan
   245  }
   246  
   247  func generateFakeStateSyncEvents(sample *bor.EventRecordWithTime, count int) []*bor.EventRecordWithTime {
   248  	events := make([]*bor.EventRecordWithTime, count)
   249  	event := *sample
   250  	event.ID = 1
   251  	events[0] = &bor.EventRecordWithTime{}
   252  	*events[0] = event
   253  	for i := 1; i < count; i++ {
   254  		event.ID = uint64(i)
   255  		event.Time = event.Time.Add(1 * time.Second)
   256  		events[i] = &bor.EventRecordWithTime{}
   257  		*events[i] = event
   258  	}
   259  	return events
   260  }
   261  
   262  func buildStateEvent(sample *bor.EventRecordWithTime, id uint64, timeStamp int64) *bor.EventRecordWithTime {
   263  	event := *sample
   264  	event.ID = id
   265  	event.Time = time.Unix(timeStamp, 0)
   266  	return &event
   267  }
   268  
   269  func getSampleEventRecord(t *testing.T) *bor.EventRecordWithTime {
   270  	res := stateSyncEventsPayload(t)
   271  	var _eventRecords []*bor.EventRecordWithTime
   272  	if err := json.Unmarshal(res.Result, &_eventRecords); err != nil {
   273  		t.Fatalf("%s", err)
   274  	}
   275  	_eventRecords[0].Time = time.Unix(1, 0)
   276  	return _eventRecords[0]
   277  }
   278  
   279  // TestEIP1559Transition tests the following:
   280  //
   281  // 1. A transaction whose gasFeeCap is greater than the baseFee is valid.
   282  // 2. Gas accounting for access lists on EIP-1559 transactions is correct.
   283  // 3. Only the transaction's tip will be received by the coinbase.
   284  // 4. The transaction sender pays for both the tip and baseFee.
   285  // 5. The coinbase receives only the partially realized tip when
   286  //    gasFeeCap - gasTipCap < baseFee.
   287  // 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap).
   288  func TestEIP1559Transition(t *testing.T) {
   289  	var (
   290  		aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
   291  
   292  		// Generate a canonical chain to act as the main dataset
   293  		db     = rawdb.NewMemoryDatabase()
   294  		engine = ethash.NewFaker()
   295  
   296  		// A sender who makes transactions, has some funds
   297  		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   298  		key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   299  		key3, _ = crypto.HexToECDSA("225171aed3793cba1c029832886d69785b7e77a54a44211226b447aa2d16b058")
   300  
   301  		addr1 = crypto.PubkeyToAddress(key1.PublicKey)
   302  		addr2 = crypto.PubkeyToAddress(key2.PublicKey)
   303  		addr3 = crypto.PubkeyToAddress(key3.PublicKey)
   304  		funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
   305  		gspec = &core.Genesis{
   306  			Config: params.BorTestChainConfig,
   307  			Alloc: core.GenesisAlloc{
   308  				addr1: {Balance: funds},
   309  				addr2: {Balance: funds},
   310  				addr3: {Balance: funds},
   311  				// The address 0xAAAA sloads 0x00 and 0x01
   312  				aa: {
   313  					Code: []byte{
   314  						byte(vm.PC),
   315  						byte(vm.PC),
   316  						byte(vm.SLOAD),
   317  						byte(vm.SLOAD),
   318  					},
   319  					Nonce:   0,
   320  					Balance: big.NewInt(0),
   321  				},
   322  			},
   323  		}
   324  	)
   325  
   326  	gspec.Config.BerlinBlock = common.Big0
   327  	gspec.Config.LondonBlock = common.Big0
   328  	genesis := gspec.MustCommit(db)
   329  	signer := types.LatestSigner(gspec.Config)
   330  
   331  	blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) {
   332  		b.SetCoinbase(common.Address{1})
   333  		// One transaction to 0xAAAA
   334  		accesses := types.AccessList{types.AccessTuple{
   335  			Address:     aa,
   336  			StorageKeys: []common.Hash{{0}},
   337  		}}
   338  
   339  		txdata := &types.DynamicFeeTx{
   340  			ChainID:    gspec.Config.ChainID,
   341  			Nonce:      0,
   342  			To:         &aa,
   343  			Gas:        30000,
   344  			GasFeeCap:  newGwei(5),
   345  			GasTipCap:  big.NewInt(2),
   346  			AccessList: accesses,
   347  			Data:       []byte{},
   348  		}
   349  		tx := types.NewTx(txdata)
   350  		tx, _ = types.SignTx(tx, signer, key1)
   351  
   352  		b.AddTx(tx)
   353  	})
   354  
   355  	diskdb := rawdb.NewMemoryDatabase()
   356  	gspec.MustCommit(diskdb)
   357  
   358  	chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
   359  	if err != nil {
   360  		t.Fatalf("failed to create tester chain: %v", err)
   361  	}
   362  	if n, err := chain.InsertChain(blocks); err != nil {
   363  		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
   364  	}
   365  
   366  	block := chain.GetBlockByNumber(1)
   367  
   368  	// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage.
   369  	expectedGas := params.TxGas + params.TxAccessListAddressGas + params.TxAccessListStorageKeyGas +
   370  		vm.GasQuickStep*2 + params.WarmStorageReadCostEIP2929 + params.ColdSloadCostEIP2929
   371  	if block.GasUsed() != expectedGas {
   372  		t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed())
   373  	}
   374  
   375  	state, _ := chain.State()
   376  
   377  	// 3: Ensure that miner received only the tx's tip.
   378  	actual := state.GetBalance(block.Coinbase())
   379  	expected := new(big.Int).Add(
   380  		new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()),
   381  		ethash.ConstantinopleBlockReward,
   382  	)
   383  	if actual.Cmp(expected) != 0 {
   384  		t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
   385  	}
   386  
   387  	// check burnt contract balance
   388  	actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
   389  	expected = new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee())
   390  	burntContractBalance := expected
   391  	if actual.Cmp(expected) != 0 {
   392  		t.Fatalf("burnt contract balance incorrect: expected %d, got %d", expected, actual)
   393  	}
   394  
   395  	// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
   396  	actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
   397  	expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
   398  	if actual.Cmp(expected) != 0 {
   399  		t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
   400  	}
   401  
   402  	blocks, _ = core.GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *core.BlockGen) {
   403  		b.SetCoinbase(common.Address{2})
   404  
   405  		txdata := &types.LegacyTx{
   406  			Nonce:    0,
   407  			To:       &aa,
   408  			Gas:      30000,
   409  			GasPrice: newGwei(5),
   410  		}
   411  		tx := types.NewTx(txdata)
   412  		tx, _ = types.SignTx(tx, signer, key2)
   413  
   414  		b.AddTx(tx)
   415  	})
   416  
   417  	if n, err := chain.InsertChain(blocks); err != nil {
   418  		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
   419  	}
   420  
   421  	block = chain.GetBlockByNumber(2)
   422  	state, _ = chain.State()
   423  	effectiveTip := block.Transactions()[0].GasTipCap().Uint64() - block.BaseFee().Uint64()
   424  
   425  	// 6+5: Ensure that miner received only the tx's effective tip.
   426  	actual = state.GetBalance(block.Coinbase())
   427  	expected = new(big.Int).Add(
   428  		new(big.Int).SetUint64(block.GasUsed()*effectiveTip),
   429  		ethash.ConstantinopleBlockReward,
   430  	)
   431  	if actual.Cmp(expected) != 0 {
   432  		t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
   433  	}
   434  
   435  	// check burnt contract balance
   436  	actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
   437  	expected = new(big.Int).Add(burntContractBalance, new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee()))
   438  	burntContractBalance = expected
   439  	if actual.Cmp(expected) != 0 {
   440  		t.Fatalf("burnt contract balance incorrect: expected %d, got %d", expected, actual)
   441  	}
   442  
   443  	// 4: Ensure the tx sender paid for the gasUsed * (effectiveTip + block baseFee).
   444  	actual = new(big.Int).Sub(funds, state.GetBalance(addr2))
   445  	expected = new(big.Int).SetUint64(block.GasUsed() * (effectiveTip + block.BaseFee().Uint64()))
   446  	if actual.Cmp(expected) != 0 {
   447  		t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
   448  	}
   449  
   450  	blocks, _ = core.GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *core.BlockGen) {
   451  		b.SetCoinbase(common.Address{3})
   452  
   453  		txdata := &types.LegacyTx{
   454  			Nonce:    0,
   455  			To:       &aa,
   456  			Gas:      30000,
   457  			GasPrice: newGwei(5),
   458  		}
   459  		tx := types.NewTx(txdata)
   460  		tx, _ = types.SignTx(tx, signer, key3)
   461  
   462  		b.AddTx(tx)
   463  
   464  		accesses := types.AccessList{types.AccessTuple{
   465  			Address:     aa,
   466  			StorageKeys: []common.Hash{{0}},
   467  		}}
   468  
   469  		txdata2 := &types.DynamicFeeTx{
   470  			ChainID:    gspec.Config.ChainID,
   471  			Nonce:      1,
   472  			To:         &aa,
   473  			Gas:        30000,
   474  			GasFeeCap:  newGwei(5),
   475  			GasTipCap:  big.NewInt(2),
   476  			AccessList: accesses,
   477  			Data:       []byte{},
   478  		}
   479  		tx = types.NewTx(txdata2)
   480  		tx, _ = types.SignTx(tx, signer, key3)
   481  
   482  		b.AddTx(tx)
   483  
   484  	})
   485  
   486  	if n, err := chain.InsertChain(blocks); err != nil {
   487  		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
   488  	}
   489  
   490  	block = chain.GetBlockByNumber(3)
   491  	state, _ = chain.State()
   492  
   493  	// check burnt contract balance
   494  	actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
   495  	burntAmount := new(big.Int).Mul(
   496  		block.BaseFee(),
   497  		big.NewInt(int64(block.GasUsed())),
   498  	)
   499  	expected = new(big.Int).Add(burntContractBalance, burntAmount)
   500  	if actual.Cmp(expected) != 0 {
   501  		t.Fatalf("burnt contract balance incorrect: expected %d, got %d", expected, actual)
   502  	}
   503  }
   504  
   505  func newGwei(n int64) *big.Int {
   506  	return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei))
   507  }
   508  
   509  func TestJaipurFork(t *testing.T) {
   510  	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
   511  	chain := init.ethereum.BlockChain()
   512  	engine := init.ethereum.Engine()
   513  	_bor := engine.(*bor.Bor)
   514  	db := init.ethereum.ChainDb()
   515  	block := init.genesis.ToBlock(db)
   516  	for i := uint64(1); i < sprintSize; i++ {
   517  		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
   518  		insertNewBlock(t, chain, block)
   519  		if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock-1 {
   520  			assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
   521  		}
   522  		if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock {
   523  			assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
   524  		}
   525  	}
   526  }
   527  
   528  // SealHash returns the hash of a block prior to it being sealed.
   529  func testSealHash(header *types.Header, c *params.BorConfig) (hash common.Hash) {
   530  	hasher := sha3.NewLegacyKeccak256()
   531  	testEncodeSigHeader(hasher, header, c)
   532  	hasher.Sum(hash[:0])
   533  	return hash
   534  }
   535  
   536  func testEncodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) {
   537  	enc := []interface{}{
   538  		header.ParentHash,
   539  		header.UncleHash,
   540  		header.Coinbase,
   541  		header.Root,
   542  		header.TxHash,
   543  		header.ReceiptHash,
   544  		header.Bloom,
   545  		header.Difficulty,
   546  		header.Number,
   547  		header.GasLimit,
   548  		header.GasUsed,
   549  		header.Time,
   550  		header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
   551  		header.MixDigest,
   552  		header.Nonce,
   553  	}
   554  	if c.IsJaipur(header.Number.Uint64()) {
   555  		if header.BaseFee != nil {
   556  			enc = append(enc, header.BaseFee)
   557  		}
   558  	}
   559  	if err := rlp.Encode(w, enc); err != nil {
   560  		panic("can't encode: " + err.Error())
   561  	}
   562  }