EIP-1559: Fee market change for ETH 1.0 chain
Transaction and BlockHeader already updated in nim-eth repo to support EIP-1559 EIP-1559 header validation and gasLimit validation already implemented in previous commit This commit deals with block validation: - Effective gasPrice per EIP-1559 - new miner reward based on priorityFee
This commit is contained in:
parent
7600046a11
commit
db8988fe64
|
@ -68,7 +68,8 @@ type
|
|||
mixHash* : Hash256
|
||||
coinbase* : EthAddress
|
||||
alloc* : GenesisAlloc
|
||||
|
||||
baseFeePerGas*: Option[UInt256]
|
||||
|
||||
GenesisAlloc* = Table[EthAddress, GenesisAccount]
|
||||
GenesisAccount* = object
|
||||
code* : seq[byte]
|
||||
|
|
|
@ -4,7 +4,7 @@ import
|
|||
chronicles, eth/trie/db,
|
||||
./db/[db_chain, state_db],
|
||||
./genesis_alloc, ./config, ./constants,
|
||||
./chain_config
|
||||
./chain_config, ./forks, ./p2p/gaslimit
|
||||
|
||||
proc defaultGenesisBlockForNetwork*(id: NetworkId): Genesis =
|
||||
result = case id
|
||||
|
@ -74,6 +74,11 @@ proc toBlock*(g: Genesis, db: BaseChainDB = nil): BlockHeader =
|
|||
ommersHash: EMPTY_UNCLE_HASH
|
||||
)
|
||||
|
||||
if g.baseFeePerGas.isSome:
|
||||
result.baseFee = g.baseFeePerGas.get()
|
||||
elif db.isNil.not and db.config.toFork(0.toBlockNumber) >= FkLondon:
|
||||
result.baseFee = EIP1559_INITIAL_BASE_FEE.u256
|
||||
|
||||
if g.gasLimit == 0:
|
||||
result.gasLimit = GENESIS_GAS_LIMIT
|
||||
|
||||
|
|
|
@ -6,6 +6,11 @@ import options, sets,
|
|||
./dao, ./validate, ../config, ../forks,
|
||||
../transaction/call_evm
|
||||
|
||||
proc eip1559TxNormalization(tx: Transaction): Transaction =
|
||||
result = tx
|
||||
if tx.txType < TxEip1559:
|
||||
result.maxPriorityFee = tx.gasPrice
|
||||
result.maxFee = tx.gasPrice
|
||||
|
||||
proc processTransaction*(tx: Transaction, sender: EthAddress, vmState: BaseVMState, fork: Fork): GasInt =
|
||||
## Process the transaction, write the results to db.
|
||||
|
@ -13,18 +18,33 @@ proc processTransaction*(tx: Transaction, sender: EthAddress, vmState: BaseVMSta
|
|||
trace "Sender", sender
|
||||
trace "txHash", rlpHash = tx.rlpHash
|
||||
|
||||
var tx = eip1559TxNormalization(tx)
|
||||
var priorityFee: GasInt
|
||||
if fork >= FkLondon:
|
||||
# priority fee is capped because the base fee is filled first
|
||||
let baseFee = vmState.blockHeader.baseFee.truncate(GasInt)
|
||||
priorityFee = min(tx.maxPriorityFee, tx.maxFee - baseFee)
|
||||
# signer pays both the priority fee and the base fee
|
||||
# tx.gasPrice now is the effective gasPrice
|
||||
tx.gasPrice = priorityFee + baseFee
|
||||
|
||||
let miner = vmState.coinbase()
|
||||
if validateTransaction(vmState, tx, sender, fork):
|
||||
result = txCallEvm(tx, sender, vmState, fork)
|
||||
|
||||
# miner fee
|
||||
if fork >= FkLondon:
|
||||
# miner only receives the priority fee;
|
||||
# note that the base fee is not given to anyone (it is burned)
|
||||
let txFee = result.u256 * priorityFee.u256
|
||||
vmState.accountDb.addBalance(miner, txFee)
|
||||
else:
|
||||
let txFee = result.u256 * tx.gasPrice.u256
|
||||
vmState.accountDb.addBalance(miner, txFee)
|
||||
|
||||
vmState.cumulativeGasUsed += result
|
||||
|
||||
let miner = vmState.coinbase()
|
||||
|
||||
vmState.mutateStateDB:
|
||||
# miner fee
|
||||
let txFee = result.u256 * tx.gasPrice.u256
|
||||
db.addBalance(miner, txFee)
|
||||
|
||||
for deletedAccount in vmState.selfDestructs:
|
||||
db.deleteAccount deletedAccount
|
||||
|
||||
|
@ -145,6 +165,12 @@ proc processBlock*(chainDB: BaseChainDB, header: BlockHeader, body: BlockBody, v
|
|||
return ValidationResult.Error
|
||||
vmState.receipts[txIndex] = makeReceipt(vmState, fork, tx.txType)
|
||||
|
||||
if vmState.cumulativeGasUsed != header.gasUsed:
|
||||
debug "gasUsed neq cumulativeGasUsed",
|
||||
gasUsed=header.gasUsed,
|
||||
cumulativeGasUsed=vmState.cumulativeGasUsed
|
||||
return ValidationResult.Error
|
||||
|
||||
if header.ommersHash != EMPTY_UNCLE_HASH:
|
||||
let h = chainDB.persistUncles(body.uncles)
|
||||
if h != header.ommersHash:
|
||||
|
|
|
@ -259,6 +259,10 @@ proc validateUncles(chainDB: BaseChainDB; header: BlockHeader;
|
|||
if result.isErr:
|
||||
return
|
||||
|
||||
result = chainDB.validateGasLimitOrBaseFee(uncle, uncleParent)
|
||||
if result.isErr:
|
||||
return
|
||||
|
||||
result = ok()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -270,6 +274,14 @@ proc validateTransaction*(vmState: BaseVMState, tx: Transaction,
|
|||
let balance = vmState.readOnlyStateDB.getBalance(sender)
|
||||
let nonce = vmState.readOnlyStateDB.getNonce(sender)
|
||||
|
||||
if tx.txType == TxEip2930 and fork < FkBerlin:
|
||||
debug "invalid tx: Eip2930 Tx type detected before Berlin"
|
||||
return
|
||||
|
||||
if tx.txType == TxEip1559 and fork < FkLondon:
|
||||
debug "invalid tx: Eip1559 Tx type detected before London"
|
||||
return
|
||||
|
||||
if vmState.cumulativeGasUsed + tx.gasLimit > vmState.blockHeader.gasLimit:
|
||||
debug "invalid tx: block header gasLimit reached",
|
||||
maxLimit=vmState.blockHeader.gasLimit,
|
||||
|
@ -277,6 +289,21 @@ proc validateTransaction*(vmState: BaseVMState, tx: Transaction,
|
|||
addition=tx.gasLimit
|
||||
return
|
||||
|
||||
# ensure that the user was willing to at least pay the base fee
|
||||
let baseFee = vmState.blockHeader.baseFee.truncate(GasInt)
|
||||
if tx.maxFee < baseFee:
|
||||
debug "invalid tx: maxFee is smaller than baseFee",
|
||||
maxFee=tx.maxFee,
|
||||
baseFee=baseFee
|
||||
return
|
||||
|
||||
# The total must be the larger of the two
|
||||
if tx.maxFee < tx.maxPriorityFee:
|
||||
debug "invalid tx: maxFee is smaller than maPriorityFee",
|
||||
maxFee=tx.maxFee,
|
||||
maxPriorityFee=tx.maxPriorityFee
|
||||
return
|
||||
|
||||
let gasCost = tx.gasLimit.u256 * tx.gasPrice.u256
|
||||
if gasCost > balance:
|
||||
debug "invalid tx: not enough cash for gas",
|
||||
|
|
|
@ -59,7 +59,7 @@ proc computeGasLimit*(parent: BlockHeader, gasLimitFloor: GasInt): GasInt =
|
|||
|
||||
proc generateHeaderFromParentHeader*(config: ChainConfig, parent: BlockHeader,
|
||||
coinbase: EthAddress, timestamp: Option[EthTime],
|
||||
gasLimit: Option[GasInt], extraData: Blob): BlockHeader =
|
||||
gasLimit: Option[GasInt], extraData: Blob, baseFee: Option[Uint256]): BlockHeader =
|
||||
|
||||
var lcTimestamp: EthTime
|
||||
if timestamp.isNone:
|
||||
|
@ -78,4 +78,5 @@ proc generateHeaderFromParentHeader*(config: ChainConfig, parent: BlockHeader,
|
|||
stateRoot: parent.stateRoot,
|
||||
coinbase: coinbase,
|
||||
extraData: extraData,
|
||||
fee: baseFee
|
||||
)
|
||||
|
|
|
@ -18,6 +18,7 @@ proc hostGetTxContextImpl(ctx: Computation): nimbus_tx_context {.cdecl.} =
|
|||
result.block_gas_limit = int64(vmstate.blockHeader.gasLimit)
|
||||
result.block_difficulty = toEvmc(vmstate.difficulty)
|
||||
result.chain_id = toEvmc(vmstate.chaindb.config.chainId.uint.u256)
|
||||
result.block_base_fee = toEvmc(vmstate.blockHeader.baseFee)
|
||||
|
||||
proc hostGetBlockHashImpl(ctx: Computation, number: int64): Hash256 {.cdecl.} =
|
||||
ctx.vmState.getAncestorHash(number.u256)
|
||||
|
|
|
@ -32,6 +32,7 @@ export
|
|||
vms.disableTracing,
|
||||
vms.enableTracing,
|
||||
vms.gasLimit,
|
||||
vms.baseFee,
|
||||
vms.generateWitness,
|
||||
vms.`generateWitness=`,
|
||||
vms.getAncestorHash,
|
||||
|
|
Loading…
Reference in New Issue