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 }