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,6 +68,7 @@ type
|
||||||
mixHash* : Hash256
|
mixHash* : Hash256
|
||||||
coinbase* : EthAddress
|
coinbase* : EthAddress
|
||||||
alloc* : GenesisAlloc
|
alloc* : GenesisAlloc
|
||||||
|
baseFeePerGas*: Option[UInt256]
|
||||||
|
|
||||||
GenesisAlloc* = Table[EthAddress, GenesisAccount]
|
GenesisAlloc* = Table[EthAddress, GenesisAccount]
|
||||||
GenesisAccount* = object
|
GenesisAccount* = object
|
||||||
|
|
|
@ -4,7 +4,7 @@ import
|
||||||
chronicles, eth/trie/db,
|
chronicles, eth/trie/db,
|
||||||
./db/[db_chain, state_db],
|
./db/[db_chain, state_db],
|
||||||
./genesis_alloc, ./config, ./constants,
|
./genesis_alloc, ./config, ./constants,
|
||||||
./chain_config
|
./chain_config, ./forks, ./p2p/gaslimit
|
||||||
|
|
||||||
proc defaultGenesisBlockForNetwork*(id: NetworkId): Genesis =
|
proc defaultGenesisBlockForNetwork*(id: NetworkId): Genesis =
|
||||||
result = case id
|
result = case id
|
||||||
|
@ -74,6 +74,11 @@ proc toBlock*(g: Genesis, db: BaseChainDB = nil): BlockHeader =
|
||||||
ommersHash: EMPTY_UNCLE_HASH
|
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:
|
if g.gasLimit == 0:
|
||||||
result.gasLimit = GENESIS_GAS_LIMIT
|
result.gasLimit = GENESIS_GAS_LIMIT
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,11 @@ import options, sets,
|
||||||
./dao, ./validate, ../config, ../forks,
|
./dao, ./validate, ../config, ../forks,
|
||||||
../transaction/call_evm
|
../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 =
|
proc processTransaction*(tx: Transaction, sender: EthAddress, vmState: BaseVMState, fork: Fork): GasInt =
|
||||||
## Process the transaction, write the results to db.
|
## Process the transaction, write the results to db.
|
||||||
|
@ -13,18 +18,33 @@ proc processTransaction*(tx: Transaction, sender: EthAddress, vmState: BaseVMSta
|
||||||
trace "Sender", sender
|
trace "Sender", sender
|
||||||
trace "txHash", rlpHash = tx.rlpHash
|
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):
|
if validateTransaction(vmState, tx, sender, fork):
|
||||||
result = txCallEvm(tx, sender, vmState, 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
|
vmState.cumulativeGasUsed += result
|
||||||
|
|
||||||
let miner = vmState.coinbase()
|
|
||||||
|
|
||||||
vmState.mutateStateDB:
|
vmState.mutateStateDB:
|
||||||
# miner fee
|
|
||||||
let txFee = result.u256 * tx.gasPrice.u256
|
|
||||||
db.addBalance(miner, txFee)
|
|
||||||
|
|
||||||
for deletedAccount in vmState.selfDestructs:
|
for deletedAccount in vmState.selfDestructs:
|
||||||
db.deleteAccount deletedAccount
|
db.deleteAccount deletedAccount
|
||||||
|
|
||||||
|
@ -145,6 +165,12 @@ proc processBlock*(chainDB: BaseChainDB, header: BlockHeader, body: BlockBody, v
|
||||||
return ValidationResult.Error
|
return ValidationResult.Error
|
||||||
vmState.receipts[txIndex] = makeReceipt(vmState, fork, tx.txType)
|
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:
|
if header.ommersHash != EMPTY_UNCLE_HASH:
|
||||||
let h = chainDB.persistUncles(body.uncles)
|
let h = chainDB.persistUncles(body.uncles)
|
||||||
if h != header.ommersHash:
|
if h != header.ommersHash:
|
||||||
|
|
|
@ -259,6 +259,10 @@ proc validateUncles(chainDB: BaseChainDB; header: BlockHeader;
|
||||||
if result.isErr:
|
if result.isErr:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
result = chainDB.validateGasLimitOrBaseFee(uncle, uncleParent)
|
||||||
|
if result.isErr:
|
||||||
|
return
|
||||||
|
|
||||||
result = ok()
|
result = ok()
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -270,6 +274,14 @@ proc validateTransaction*(vmState: BaseVMState, tx: Transaction,
|
||||||
let balance = vmState.readOnlyStateDB.getBalance(sender)
|
let balance = vmState.readOnlyStateDB.getBalance(sender)
|
||||||
let nonce = vmState.readOnlyStateDB.getNonce(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:
|
if vmState.cumulativeGasUsed + tx.gasLimit > vmState.blockHeader.gasLimit:
|
||||||
debug "invalid tx: block header gasLimit reached",
|
debug "invalid tx: block header gasLimit reached",
|
||||||
maxLimit=vmState.blockHeader.gasLimit,
|
maxLimit=vmState.blockHeader.gasLimit,
|
||||||
|
@ -277,6 +289,21 @@ proc validateTransaction*(vmState: BaseVMState, tx: Transaction,
|
||||||
addition=tx.gasLimit
|
addition=tx.gasLimit
|
||||||
return
|
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
|
let gasCost = tx.gasLimit.u256 * tx.gasPrice.u256
|
||||||
if gasCost > balance:
|
if gasCost > balance:
|
||||||
debug "invalid tx: not enough cash for gas",
|
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,
|
proc generateHeaderFromParentHeader*(config: ChainConfig, parent: BlockHeader,
|
||||||
coinbase: EthAddress, timestamp: Option[EthTime],
|
coinbase: EthAddress, timestamp: Option[EthTime],
|
||||||
gasLimit: Option[GasInt], extraData: Blob): BlockHeader =
|
gasLimit: Option[GasInt], extraData: Blob, baseFee: Option[Uint256]): BlockHeader =
|
||||||
|
|
||||||
var lcTimestamp: EthTime
|
var lcTimestamp: EthTime
|
||||||
if timestamp.isNone:
|
if timestamp.isNone:
|
||||||
|
@ -78,4 +78,5 @@ proc generateHeaderFromParentHeader*(config: ChainConfig, parent: BlockHeader,
|
||||||
stateRoot: parent.stateRoot,
|
stateRoot: parent.stateRoot,
|
||||||
coinbase: coinbase,
|
coinbase: coinbase,
|
||||||
extraData: extraData,
|
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_gas_limit = int64(vmstate.blockHeader.gasLimit)
|
||||||
result.block_difficulty = toEvmc(vmstate.difficulty)
|
result.block_difficulty = toEvmc(vmstate.difficulty)
|
||||||
result.chain_id = toEvmc(vmstate.chaindb.config.chainId.uint.u256)
|
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.} =
|
proc hostGetBlockHashImpl(ctx: Computation, number: int64): Hash256 {.cdecl.} =
|
||||||
ctx.vmState.getAncestorHash(number.u256)
|
ctx.vmState.getAncestorHash(number.u256)
|
||||||
|
|
|
@ -32,6 +32,7 @@ export
|
||||||
vms.disableTracing,
|
vms.disableTracing,
|
||||||
vms.enableTracing,
|
vms.enableTracing,
|
||||||
vms.gasLimit,
|
vms.gasLimit,
|
||||||
|
vms.baseFee,
|
||||||
vms.generateWitness,
|
vms.generateWitness,
|
||||||
vms.`generateWitness=`,
|
vms.`generateWitness=`,
|
||||||
vms.getAncestorHash,
|
vms.getAncestorHash,
|
||||||
|
|
Loading…
Reference in New Issue