diff --git a/Makefile b/Makefile index 8a9fbaa0a2..0c6a502b90 100644 --- a/Makefile +++ b/Makefile @@ -47,8 +47,8 @@ ios: test: all # $(GORUN) build/ci.go test - go test github.com/ethereum/go-ethereum/consensus/bor - go test github.com/ethereum/go-ethereum/tests/bor + go test github.com/ethereum/go-ethereum/consensus/bor -v + go test github.com/ethereum/go-ethereum/tests/bor -v lint: ## Run linters. $(GORUN) build/ci.go lint diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index 51e7496559..94774d5032 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -182,12 +182,12 @@ func encodeSigHeader(w io.Writer, header *types.Header) { func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint64 { // 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.Period + delay := c.CalculatePeriod(number) if number%c.Sprint == 0 { delay = c.ProducerDelay } if succession > 0 { - delay += uint64(succession) * c.BackupMultiplier + delay += uint64(succession) * c.CalculateBackupMultiplier(number) } return delay } @@ -353,6 +353,11 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head return errInvalidDifficulty } } + // Verify that the gas limit is <= 2^63-1 + cap := uint64(0x7fffffffffffffff) + if header.GasLimit > cap { + return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) + } // If all checks passed, validate any special fields for hard forks if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { return err @@ -396,7 +401,24 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t return consensus.ErrUnknownAncestor } - if parent.Time+c.config.Period > header.Time { + // Verify that the gasUsed is <= gasLimit + if header.GasUsed > header.GasLimit { + return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) + } + if !chain.Config().IsLondon(header.Number) { + // Verify BaseFee not present before EIP-1559 fork. + if header.BaseFee != nil { + return fmt.Errorf("invalid baseFee before fork: have %d, want ", header.BaseFee) + } + if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil { + return err + } + } else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { + // Verify the header's EIP-1559 attributes. + return err + } + + if parent.Time+c.config.CalculatePeriod(number) > header.Time { return ErrInvalidTimestamp } @@ -791,7 +813,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result return errUnknownBlock } // For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing) - if c.config.Period == 0 && len(block.Transactions()) == 0 { + if c.config.CalculatePeriod(number) == 0 && len(block.Transactions()) == 0 { log.Info("Sealing paused, waiting for transactions") return nil } @@ -819,7 +841,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result // Sweet, the protocol permits us to sign the block, wait for our time delay := time.Unix(int64(header.Time), 0).Sub(time.Now()) // nolint: gosimple // wiggle was already accounted for in header.Time, this is just for logging - wiggle := time.Duration(successionNumber) * time.Duration(c.config.BackupMultiplier) * time.Second + wiggle := time.Duration(successionNumber) * time.Duration(c.config.CalculateBackupMultiplier(number)) * time.Second // Sign all the things! sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header)) diff --git a/core/state_transition.go b/core/state_transition.go index 4160c62253..f650922f2f 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -337,6 +337,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) } amount := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip) + if london { + burntContractAddress := common.HexToAddress(st.evm.ChainConfig().Bor.CalculateBurntContract(st.evm.Context.BlockNumber.Uint64())) + burnAmount := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.evm.Context.BaseFee) + st.state.AddBalance(burntContractAddress, burnAmount) + } st.state.AddBalance(st.evm.Context.Coinbase, amount) output1 := new(big.Int).SetBytes(input1.Bytes()) output2 := new(big.Int).SetBytes(input2.Bytes()) diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 731d13a532..d38d2b0581 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -174,7 +174,7 @@ func TestBlockSubscription(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewPublicFilterAPI(backend, false, deadline, false) genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) chain, _ = core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) chainEvents = []core.ChainEvent{} @@ -226,7 +226,7 @@ func TestPendingTxFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewPublicFilterAPI(backend, false, deadline, false) transactions = []*types.Transaction{ types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), @@ -281,7 +281,7 @@ func TestLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewPublicFilterAPI(backend, false, deadline, false) testCases = []struct { crit FilterCriteria @@ -325,7 +325,7 @@ func TestInvalidLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewPublicFilterAPI(backend, false, deadline, false) ) // different situations where log filter creation should fail. @@ -347,7 +347,7 @@ func TestInvalidGetLogsRequest(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewPublicFilterAPI(backend, false, deadline, false) blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") ) @@ -372,7 +372,7 @@ func TestLogFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewPublicFilterAPI(backend, false, deadline, false) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -486,7 +486,7 @@ func TestPendingLogsSubscription(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewPublicFilterAPI(backend, false, deadline, false) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -670,7 +670,7 @@ func TestPendingTxFilterDeadlock(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, timeout) + api = NewPublicFilterAPI(backend, false, timeout, false) done = make(chan struct{}) ) diff --git a/internal/ethapi/bor_api.go b/internal/ethapi/bor_api.go index 3796047c8f..2a953e5d9d 100644 --- a/internal/ethapi/bor_api.go +++ b/internal/ethapi/bor_api.go @@ -31,7 +31,7 @@ func (s *PublicBlockChainAPI) appendRPCMarshalBorTransaction(ctx context.Context if borTx != nil { formattedTxs := fields["transactions"].([]interface{}) if fullTx { - marshalledTx := newRPCTransaction(borTx, blockHash, blockNumber, txIndex, nil, s.b.ChainConfig()) + marshalledTx := newRPCTransaction(borTx, blockHash, blockNumber, txIndex, block.BaseFee(), s.b.ChainConfig()) // newRPCTransaction calculates hash based on RLP of the transaction data. // In case of bor block tx, we need simple derived tx hash (same as function argument) instead of RLP hash marshalledTx.Hash = txHash diff --git a/params/config.go b/params/config.go index ca25bb2536..f3a83530b9 100644 --- a/params/config.go +++ b/params/config.go @@ -20,6 +20,8 @@ import ( "encoding/binary" "fmt" "math/big" + "sort" + "strconv" "github.com/ethereum/go-ethereum/common" "golang.org/x/crypto/sha3" @@ -222,6 +224,40 @@ var ( Threshold: 2, } + // BorTestChainConfig contains the chain parameters to run a node on the Test network. + BorTestChainConfig = &ChainConfig{ + ChainID: big.NewInt(80001), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Hash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + Bor: &BorConfig{ + Period: map[string]uint64{ + "0": 2, + }, + ProducerDelay: 6, + Sprint: 64, + BackupMultiplier: map[string]uint64{ + "0": 2, + }, + ValidatorContract: "0x0000000000000000000000000000000000001000", + StateReceiverContract: "0x0000000000000000000000000000000000001001", + BurntContract: map[string]string{ + "0": "0x00000000000000000000000000000000000000000", + }, + }, + } + // MumbaiChainConfig contains the chain parameters to run a node on the Mumbai test network. MumbaiChainConfig = &ChainConfig{ ChainID: big.NewInt(80001), @@ -238,13 +274,21 @@ var ( IstanbulBlock: big.NewInt(2722000), MuirGlacierBlock: big.NewInt(2722000), BerlinBlock: big.NewInt(13996000), + LondonBlock: big.NewInt(22640000), Bor: &BorConfig{ - Period: 2, - ProducerDelay: 6, - Sprint: 64, - BackupMultiplier: 2, + Period: map[string]uint64{ + "0": 2, + }, + ProducerDelay: 6, + Sprint: 64, + BackupMultiplier: map[string]uint64{ + "0": 2, + }, ValidatorContract: "0x0000000000000000000000000000000000001000", StateReceiverContract: "0x0000000000000000000000000000000000001001", + BurntContract: map[string]string{ + "22640000": "0x70bcA57F4579f58670aB2d18Ef16e02C17553C38", + }, BlockAlloc: map[string]interface{}{ // write as interface since that is how it is decoded in genesis "22244000": map[string]interface{}{ @@ -272,11 +316,16 @@ var ( IstanbulBlock: big.NewInt(3395000), MuirGlacierBlock: big.NewInt(3395000), BerlinBlock: big.NewInt(14750000), + LondonBlock: big.NewInt(0), // TODO - Add london fork block Bor: &BorConfig{ - Period: 2, - ProducerDelay: 6, - Sprint: 64, - BackupMultiplier: 2, + Period: map[string]uint64{ + "0": 2, + }, + ProducerDelay: 6, + Sprint: 64, + BackupMultiplier: map[string]uint64{ + "0": 2, + }, ValidatorContract: "0x0000000000000000000000000000000000001000", StateReceiverContract: "0x0000000000000000000000000000000000001001", OverrideStateSyncRecords: map[string]int{ @@ -290,6 +339,9 @@ var ( "14953792": 0, "14953856": 0, }, + BurntContract: map[string]string{ + "0": "0x0000000000000000000000000000000000000000", + }, // TODO add london fork contract and block BlockAlloc: map[string]interface{}{ // write as interface since that is how it is decoded in genesis "22156660": map[string]interface{}{ @@ -426,15 +478,15 @@ func (c *CliqueConfig) String() string { // BorConfig is the consensus engine configs for Matic bor based sealing. type BorConfig struct { - Period 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 - BackupMultiplier uint64 `json:"backupMultiplier"` // Backup multiplier to determine the wiggle time - ValidatorContract string `json:"validatorContract"` // Validator set contract - StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract - + 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 + 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 } // String implements the stringer interface, returning the consensus engine details. @@ -442,6 +494,46 @@ func (b *BorConfig) String() string { return "bor" } +func (c *BorConfig) CalculateBackupMultiplier(number uint64) uint64 { + return c.calculateBorConfigHelper(c.BackupMultiplier, number) +} + +func (c *BorConfig) CalculatePeriod(number uint64) uint64 { + return c.calculateBorConfigHelper(c.Period, number) +} + +func (c *BorConfig) calculateBorConfigHelper(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 { + 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 c.BurntContract[keys[i]] + } + } + return c.BurntContract[keys[len(keys)-1]] +} + // String implements the fmt.Stringer interface. func (c *ChainConfig) String() string { var engine interface{} diff --git a/params/version.go b/params/version.go index c2362ca76f..26eaaa8fb6 100644 --- a/params/version.go +++ b/params/version.go @@ -23,8 +23,8 @@ import ( const ( VersionMajor = 0 // Major version component of the current release VersionMinor = 2 // Minor version component of the current release - VersionPatch = 12 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionPatch = 13 // Patch version component of the current release + VersionMeta = "beta" // Version metadata to append to the version string ) // Version holds the textual version string. diff --git a/tests/bor/bor_test.go b/tests/bor/bor_test.go index 979a8dc044..850d4fda6c 100644 --- a/tests/bor/bor_test.go +++ b/tests/bor/bor_test.go @@ -7,14 +7,18 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/bor" + "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/tests/bor/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) var ( @@ -268,3 +272,233 @@ func getSampleEventRecord(t *testing.T) *bor.EventRecordWithTime { _eventRecords[0].Time = time.Unix(1, 0) return _eventRecords[0] } + +// 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)) +} diff --git a/tests/bor/testdata/genesis.json b/tests/bor/testdata/genesis.json index 7c3e34bf35..584f7fc912 100644 --- a/tests/bor/testdata/genesis.json +++ b/tests/bor/testdata/genesis.json @@ -8,13 +8,25 @@ "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 10, "bor": { - "period": 1, + "period": { + "0": 1 + }, "producerDelay": 4, "sprint": 4, - "backupMultiplier": 1, + "backupMultiplier": { + "0": 1 + }, "validatorContract": "0x0000000000000000000000000000000000001000", - "stateReceiverContract": "0x0000000000000000000000000000000000001001" + "stateReceiverContract": "0x0000000000000000000000000000000000001001", + "burntContract": { + "0": "0x0000000000000000000000000000000000000000" + } } }, "nonce": "0x0",