Skip to content

Commit bba1a53

Browse files
authored
Merge pull request #166 from bane-labs/policy-basefee
systemcontracts: apply baseFee from policy contract for burning
2 parents 0a504f7 + 1636589 commit bba1a53

File tree

28 files changed

+324
-76
lines changed

28 files changed

+324
-76
lines changed

cmd/evm/internal/t8ntool/execution.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/ethereum/go-ethereum/core"
2929
"github.com/ethereum/go-ethereum/core/rawdb"
3030
"github.com/ethereum/go-ethereum/core/state"
31+
"github.com/ethereum/go-ethereum/core/systemcontracts"
3132
"github.com/ethereum/go-ethereum/core/types"
3233
"github.com/ethereum/go-ethereum/core/vm"
3334
"github.com/ethereum/go-ethereum/crypto"
@@ -156,9 +157,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
156157
GasLimit: pre.Env.GasLimit,
157158
GetHash: getHash,
158159
}
159-
// If currentBaseFee is defined, add it to the vmContext.
160+
// If currentBaseFee is defined, add it to the vmContext and to the state DB.
160161
if pre.Env.BaseFee != nil {
161162
vmContext.BaseFee = new(big.Int).Set(pre.Env.BaseFee)
163+
if chainConfig.IsNeoXBurn(vmContext.BlockNumber, vmContext.Time) {
164+
statedb.SetState(systemcontracts.PolicyProxyHash, systemcontracts.GetBaseFeeStateHash(), common.BigToHash(pre.Env.BaseFee))
165+
}
162166
}
163167
// If random is defined, add it to the vmContext.
164168
if pre.Env.Random != nil {

cmd/evm/internal/t8ntool/transition.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ func Transition(ctx *cli.Context) error {
174174
if err := applyLondonChecks(&prestate.Env, chainConfig); err != nil {
175175
return err
176176
}
177+
if err := applyNeoXBurnChecks(&prestate.Env, chainConfig); err != nil {
178+
return err
179+
}
177180
if err := applyShanghaiChecks(&prestate.Env, chainConfig); err != nil {
178181
return err
179182
}
@@ -194,6 +197,17 @@ func Transition(ctx *cli.Context) error {
194197
return dispatchOutput(ctx, baseDir, result, collector, body)
195198
}
196199

200+
func applyNeoXBurnChecks(env *stEnv, chainConfig *params.ChainConfig) error {
201+
if !chainConfig.IsNeoXBurn(big.NewInt(int64(env.Number)), env.Timestamp) {
202+
return nil
203+
}
204+
// Sanity check, to not `panic` in state_transition
205+
if env.BaseFee == nil {
206+
return NewError(ErrorConfig, errors.New("NeoXBurn config but missing 'currentBaseFee' in env section"))
207+
}
208+
return nil
209+
}
210+
197211
func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error {
198212
if !chainConfig.IsLondon(big.NewInt(int64(env.Number))) {
199213
return nil

consensus/dbft/chainreader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type ChainHeaderReader interface {
1717
HasBlock(hash common.Hash, number uint64) bool
1818
GetBlockByNumber(uint64) *types.Block
1919
VerifyBlock(block *types.Block) (*state.StateDB, types.Receipts, error)
20-
ProcessState(block *types.Block) (*state.StateDB, types.Receipts, []*types.Log, uint64, error)
20+
ProcessState(block *types.Block, statedb *state.StateDB) (*state.StateDB, types.Receipts, []*types.Log, uint64, error)
2121
}
2222

2323
// ChainHeaderWriter is a Blockchain API abstraction needed for proper blockQueue

consensus/dbft/dbft.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ func New(config *params.DBFTConfig, _ ethdb.Database) (*DBFT, error) {
426426
dbftBlock.transactions = c.sealingTransactions
427427
ethBlock := dbftBlock.ToEthBlock()
428428

429-
state, _, _, _, err := c.chain.ProcessState(ethBlock)
429+
state, _, _, _, err := c.chain.ProcessState(ethBlock, nil)
430430
if err != nil {
431431
log.Crit("failed to process state from proposal",
432432
"err", err,

consensus/misc/eip1559/eip1559.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"github.com/ethereum/go-ethereum/common"
2525
"github.com/ethereum/go-ethereum/common/math"
2626
"github.com/ethereum/go-ethereum/consensus/misc"
27+
"github.com/ethereum/go-ethereum/core/state"
28+
"github.com/ethereum/go-ethereum/core/systemcontracts"
2729
"github.com/ethereum/go-ethereum/core/types"
2830
"github.com/ethereum/go-ethereum/params"
2931
)
@@ -44,6 +46,11 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade
4446
if header.BaseFee == nil {
4547
return errors.New("header is missing baseFee")
4648
}
49+
// For NeoXBurn block BaseFee verification is performed by consensus nodes and hence
50+
// not included into the state-independent ordinary block verification rules.
51+
if config.IsNeoXBurn(parent.Number, parent.Time) {
52+
return nil
53+
}
4754
// Verify the baseFee is correct based on the parent header.
4855
expectedBaseFee := CalcBaseFee(config, parent)
4956
if header.BaseFee.Cmp(expectedBaseFee) != 0 {
@@ -93,3 +100,12 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
93100
return math.BigMax(baseFee, common.Big0)
94101
}
95102
}
103+
104+
// CalcBaseFeeDBFT calculates the basefee of the header.
105+
// if is neoXBurn fork, get basefee from Policy contract.
106+
func CalcBaseFeeDBFT(config *params.ChainConfig, parent *types.Header, state *state.StateDB) *big.Int {
107+
if !config.IsNeoXBurn(parent.Number, parent.Time) {
108+
return CalcBaseFee(config, parent)
109+
}
110+
return state.GetState(systemcontracts.PolicyProxyHash, systemcontracts.GetBaseFeeStateHash()).Big()
111+
}

core/blockchain.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/ethereum/go-ethereum/common/mclock"
3434
"github.com/ethereum/go-ethereum/common/prque"
3535
"github.com/ethereum/go-ethereum/consensus"
36+
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
3637
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
3738
"github.com/ethereum/go-ethereum/core/rawdb"
3839
"github.com/ethereum/go-ethereum/core/state"
@@ -2452,23 +2453,35 @@ func (bc *BlockChain) GetTrieFlushInterval() time.Duration {
24522453
return time.Duration(bc.flushInterval.Load())
24532454
}
24542455

2455-
// ProcessState processes the state changes according to the Ethereum rules by running
2456-
// the transaction messages using the statedb and applying any rewards to both
2457-
// the processor (coinbase) and any included uncles. It doesn't persist any data.
2458-
func (bc *BlockChain) ProcessState(block *types.Block) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) {
2456+
// getParentState retrieves statedb and parent header by hash or block number
2457+
func (bc *BlockChain) getParentState(block *types.Block) (*state.StateDB, *types.Header, error) {
24592458
parent := bc.GetBlockByHash(block.ParentHash())
24602459
if parent == nil {
24612460
log.Error("failed to retrieve parent by hash to process block state",
24622461
"parent number", block.NumberU64()-1,
24632462
"parent hash", block.ParentHash().String())
24642463
parent = bc.GetBlockByNumber(block.NumberU64() - 1)
24652464
if parent == nil {
2466-
return nil, nil, nil, 0, fmt.Errorf("failed to retrieve canonical parent by number to process block state (number %d, hash %s)", block.NumberU64()-1, block.ParentHash().String())
2465+
return nil, nil, fmt.Errorf("failed to retrieve canonical parent by number to process block state (number %d, hash %s)", block.NumberU64()-1, block.ParentHash().String())
24672466
}
24682467
}
24692468
statedb, err := bc.StateAt(parent.Root())
24702469
if err != nil {
2471-
return nil, nil, nil, 0, fmt.Errorf("failed to retrieve state at %d, %s: %w", parent.NumberU64(), parent.Root(), err)
2470+
return nil, parent.Header(), fmt.Errorf("failed to retrieve state at %d, %s: %w", parent.NumberU64(), parent.Root(), err)
2471+
}
2472+
return statedb, parent.Header(), nil
2473+
}
2474+
2475+
// ProcessState processes the state changes according to the Ethereum rules by running
2476+
// the transaction messages using the statedb (if given) and applying any rewards to both
2477+
// the processor (coinbase) and any included uncles. It doesn't persist any data.
2478+
func (bc *BlockChain) ProcessState(block *types.Block, statedb *state.StateDB) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) {
2479+
var err error
2480+
if statedb == nil {
2481+
statedb, _, err = bc.getParentState(block)
2482+
if err != nil {
2483+
return nil, nil, nil, 0, err
2484+
}
24722485
}
24732486

24742487
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
@@ -2485,7 +2498,18 @@ func (bc *BlockChain) VerifyBlock(block *types.Block) (*state.StateDB, types.Rec
24852498
return nil, nil, fmt.Errorf("failed to validate body: %w", err)
24862499
}
24872500

2488-
statedb, receipts, _, usedGas, err := bc.ProcessState(block)
2501+
statedb, parentHeader, err := bc.getParentState(block)
2502+
if err != nil {
2503+
return nil, nil, err
2504+
}
2505+
2506+
// verify baseFee
2507+
baseFee := eip1559.CalcBaseFeeDBFT(bc.chainConfig, parentHeader, statedb)
2508+
if block.BaseFee().Cmp(baseFee) != 0 {
2509+
return nil, nil, fmt.Errorf("failed to verify policy baseFee, expected: %v, current: %v", baseFee, block.BaseFee())
2510+
}
2511+
2512+
statedb, receipts, _, usedGas, err := bc.ProcessState(block, statedb)
24892513
if err != nil {
24902514
return nil, nil, fmt.Errorf("failed to process block state: %w", err)
24912515
}

core/state_transition.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -294,13 +294,6 @@ func (st *StateTransition) preCheck() error {
294294
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
295295
msg.From.Hex(), codeHash)
296296
}
297-
// Ensure the transaction is allowed by policy
298-
// Apply policy minimum gas tip cap
299-
var minGasTipCap = st.state.GetState(systemcontracts.PolicyProxyHash, systemcontracts.GetMinGasTipCapStateHash())
300-
if msg.GasTipCap.Cmp(minGasTipCap.Big()) < 0 {
301-
return fmt.Errorf("%w: address %v, gastipcap %v", ErrUnderpriced,
302-
msg.From.Hex(), msg.GasTipCap)
303-
}
304297
// Apply policy blacklist
305298
var blocked = st.state.GetState(systemcontracts.PolicyProxyHash, systemcontracts.GetBlackListStateHash(msg.From))
306299
if blocked != (common.Hash{}) {
@@ -331,6 +324,16 @@ func (st *StateTransition) preCheck() error {
331324
return fmt.Errorf("%w: address %v, maxFeePerGas: %s, baseFee: %s", ErrFeeCapTooLow,
332325
msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee)
333326
}
327+
// Ensure the transaction is allowed by policy, only for neoXBurn fork
328+
if st.evm.ChainConfig().IsNeoXBurn(st.evm.Context.BlockNumber, st.evm.Context.Time) {
329+
// Apply policy minimum gas tip cap
330+
// For LegacyTx, GasFeeCap and GasPrice are equal, so checking GasTipCap and GasFeeCap is enough
331+
var minGasTipCap = st.state.GetState(systemcontracts.PolicyProxyHash, systemcontracts.GetMinGasTipCapStateHash()).Big()
332+
if cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee)).Cmp(minGasTipCap) < 0 {
333+
return fmt.Errorf("%w: address %v, gasTipCap %v, gasFeeCap %v, policy minGasTipCap %v, baseFee %v ", ErrUnderpriced,
334+
msg.From.Hex(), msg.GasTipCap, msg.GasFeeCap, minGasTipCap, st.evm.Context.BaseFee)
335+
}
336+
}
334337
}
335338
}
336339
// Check the blob version validity

core/txpool/blobpool/blobpool.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Addr
399399
p.recheck(addr, nil)
400400
}
401401
var (
402-
basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), p.head))
402+
basefee = uint256.MustFromBig(eip1559.CalcBaseFeeDBFT(p.chain.Config(), p.head, p.state))
403403
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
404404
)
405405
if p.head.ExcessBlobGas != nil {
@@ -782,7 +782,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
782782
}
783783
// Reset the price heap for the new set of basefee/blobfee pairs
784784
var (
785-
basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), newHead))
785+
basefee = uint256.MustFromBig(eip1559.CalcBaseFeeDBFT(p.chain.Config(), newHead, p.state))
786786
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
787787
)
788788
if newHead.ExcessBlobGas != nil {

core/txpool/legacypool/legacypool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,7 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
13331333
pool.demoteUnexecutables()
13341334
if reset.newHead != nil {
13351335
if pool.chainconfig.IsLondon(new(big.Int).Add(reset.newHead.Number, big.NewInt(1))) {
1336-
pendingBaseFee := eip1559.CalcBaseFee(pool.chainconfig, reset.newHead)
1336+
pendingBaseFee := eip1559.CalcBaseFeeDBFT(pool.chainconfig, reset.newHead, pool.currentState)
13371337
pool.priced.SetBaseFee(pendingBaseFee)
13381338
} else {
13391339
pool.priced.Reheap()

core/txpool/validation.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"math/big"
2323

2424
"github.com/ethereum/go-ethereum/common"
25+
"github.com/ethereum/go-ethereum/common/math"
2526
"github.com/ethereum/go-ethereum/core"
2627
"github.com/ethereum/go-ethereum/core/state"
2728
"github.com/ethereum/go-ethereum/core/systemcontracts"
@@ -203,9 +204,12 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op
203204
}
204205
// Ensure the transaction is allowed by policy
205206
// Apply policy minimum gas tip cap
206-
var minGasTipCap = opts.State.GetState(systemcontracts.PolicyProxyHash, systemcontracts.GetMinGasTipCapStateHash())
207-
if tx.GasTipCap().Cmp(minGasTipCap.Big()) < 0 {
208-
return fmt.Errorf("%w: policy needed %v, tip permitted %v", ErrUnderpriced, minGasTipCap.Big(), tx.GasTipCap())
207+
// For LegacyTx, GasFeeCap and GasPrice are equal, so checking GasTipCap and GasFeeCap is enough
208+
var minGasTipCap = opts.State.GetState(systemcontracts.PolicyProxyHash, systemcontracts.GetMinGasTipCapStateHash()).Big()
209+
var baseFee = opts.State.GetState(systemcontracts.PolicyProxyHash, systemcontracts.GetBaseFeeStateHash()).Big()
210+
if math.BigMin(tx.GasTipCap(), new(big.Int).Sub(tx.GasFeeCap(), baseFee)).Cmp(minGasTipCap) < 0 {
211+
return fmt.Errorf("%w: policy minGasTipCap needed %v, baseFee needed %v, gasTipCap %v, gasFeeCap %v ",
212+
ErrUnderpriced, minGasTipCap, baseFee, tx.GasTipCap(), tx.GasFeeCap())
209213
}
210214
// Apply policy blacklist
211215
var blocked = opts.State.GetState(systemcontracts.PolicyProxyHash, systemcontracts.GetBlackListStateHash(from))

0 commit comments

Comments
 (0)