handle PoA block difficulty during block creation

- in vmState
- in txpool
- in sealing engine

fix #1105
This commit is contained in:
jangko 2022-06-14 13:01:51 +07:00
parent 6325712aa6
commit 77be2f66d2
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
9 changed files with 65 additions and 22 deletions

View File

@ -12,8 +12,6 @@
## Mining Support for Clique PoA Consensus Protocol
## ================================================
##
## Note that mining in currently unsupported by `NIMBUS`
##
## For details see
## `EIP-225 <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-225.md>`_
## and
@ -322,7 +320,7 @@ proc seal*(c: Clique; ethBlock: var EthBlock):
ok()
# clique/clique.go(673): func (c *Clique) CalcDifficulty(chain [..]
proc calcDifficulty(c: Clique;
proc calcDifficulty*(c: Clique;
parent: BlockHeader): Result[DifficultyInt,CliqueError]
{.gcsafe, raises: [Defect,CatchableError].} =
## For the Consensus Engine, `calcDifficulty()` is the difficulty adjustment

View File

@ -126,8 +126,6 @@ proc generateBlock(engine: SealingEngineRef,
timestamp = getTime(),
prevRandao = Hash256()): Result[void, string] =
# deviation from standard block generator
# - no local and remote transactions inclusion(need tx pool)
# - no receipts from tx
# - no DAO hard fork
# - no local and remote uncles inclusion
@ -188,6 +186,20 @@ proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} =
clique.authorize(engine.signer, signerFunc)
proc diffCalculator(timeStamp: EthTime, parent: BlockHeader): DifficultyInt {.gcsafe, raises:[].} =
# pesky Nim effect system
try:
discard timestamp
let rc = clique.calcDifficulty(parent)
if rc.isErr:
return 0.u256
rc.get()
except:
0.u256
# switch to PoA difficulty calculator
engine.txPool.calcDifficulty = diffCalculator
# convert times.Duration to chronos.Duration
let period = chronos.seconds(clique.cfg.period.inSeconds)

View File

@ -772,6 +772,11 @@ proc `feeRecipient=`*(xp: TxPoolRef; beneficiary: EthAddress) =
## a.k.a miner in PoW chain or coinbase
xp.chain.miner = beneficiary
proc `calcDifficulty=`*(xp: TxPoolRef; val: DifficultyCalculator) =
## Setter, either PoW or PoA difficulty calculator
## PoS difficulty always zero
xp.chain.calcDifficulty = val
# ------------------------------------------------------------------------------
# Public functions, per-tx-item operations
# ------------------------------------------------------------------------------

View File

@ -20,6 +20,7 @@ import
../../forks,
../../p2p/executor,
../../utils,
../../utils/difficulty,
../../vm_state,
../../vm_types,
./tx_chain/[tx_basefee, tx_gaslimits],
@ -53,6 +54,8 @@ type
txRoot: Hash256 ## `rootHash` after packing
stateRoot: Hash256 ## `stateRoot` after packing
DifficultyCalculator* = proc(timeStamp: EthTime, parent: BlockHeader): DifficultyInt {.gcsafe, raises:[].}
TxChainRef* = ref object ##\
## State cache of the transaction environment for creating a new\
## block. This state is typically synchrionised with the canonical\
@ -69,6 +72,9 @@ type
# EIP-4399 and EIP-3675
prevRandao: Hash256 ## PoS block randomness
# overrideable difficulty calculator
calcDifficulty: DifficultyCalculator
# ------------------------------------------------------------------------------
# Private functions
# ------------------------------------------------------------------------------
@ -77,12 +83,16 @@ proc resetTxEnv(dh: TxChainRef; parent: BlockHeader; fee: Option[UInt256])
{.gcsafe,raises: [Defect,CatchableError].} =
dh.txEnv.reset
let timestamp = getTime().utc.toTime
# we don't consider PoS difficulty here
# because that is handled in vmState
dh.txEnv.vmState = BaseVMState.new(
parent = parent,
timestamp = getTime().utc.toTime,
timestamp = timestamp,
gasLimit = (if dh.maxMode: dh.limits.maxLimit else: dh.limits.trgLimit),
fee = fee,
prevRandao= dh.prevRandao,
difficulty= dh.calcDifficulty(timestamp, parent),
miner = dh.miner,
chainDB = dh.db)
@ -118,6 +128,12 @@ proc new*(T: type TxChainRef; db: BaseChainDB; miner: EthAddress): T
result.miner = miner
result.lhwm.lwmTrg = TRG_THRESHOLD_PER_CENT
result.lhwm.hwmMax = MAX_THRESHOLD_PER_CENT
result.calcDifficulty = proc(timeStamp: EthTime, parent: BlockHeader):
DifficultyInt {.gcsafe, raises:[].} =
try:
db.config.calcDifficulty(timestamp, parent)
except:
0.u256
result.update(db.getCanonicalHead)
# ------------------------------------------------------------------------------
@ -311,6 +327,10 @@ proc `prevRandao=`*(dh: TxChainRef; val: Hash256) =
## Setter
dh.prevRandao = val
proc `calcDifficulty=`*(dh: TxChainRef; val: DifficultyCalculator) =
## Setter
dh.calcDifficulty = val
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------

View File

@ -67,6 +67,7 @@ proc init(
gasLimit: GasInt;
fee: Option[UInt256];
prevRandao: Hash256;
difficulty: UInt256;
miner: EthAddress;
chainDB: BaseChainDB;
ttdReached: bool;
@ -80,6 +81,7 @@ proc init(
self.gasLimit = gasLimit
self.fee = fee
self.prevRandao = prevRandao
self.blockDifficulty = difficulty
self.chainDB = chainDB
self.ttdReached = ttdReached
self.tracer = tracer
@ -96,6 +98,7 @@ proc init(
gasLimit: GasInt;
fee: Option[UInt256];
prevRandao: Hash256;
difficulty: UInt256;
miner: EthAddress;
chainDB: BaseChainDB;
tracerFlags: set[TracerFlags])
@ -109,6 +112,7 @@ proc init(
gasLimit = gasLimit,
fee = fee,
prevRandao= prevRandao,
difficulty= difficulty,
miner = miner,
chainDB = chainDB,
ttdReached= chainDB.isTtdReached(parent.blockHash),
@ -132,6 +136,7 @@ proc new*(
gasLimit: GasInt; ## tx env: gas limit
fee: Option[UInt256]; ## tx env: optional base fee
prevRandao: Hash256; ## tx env: POS block randomness
difficulty: UInt256, ## tx env: difficulty
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
chainDB: BaseChainDB; ## block chain database
tracerFlags: set[TracerFlags] = {};
@ -152,6 +157,7 @@ proc new*(
gasLimit = gasLimit,
fee = fee,
prevRandao = prevRandao,
difficulty = difficulty,
miner = miner,
chainDB = chainDB,
tracerFlags = tracerFlags)
@ -162,6 +168,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
gasLimit: GasInt; ## tx env: gas limit
fee: Option[UInt256]; ## tx env: optional base fee
prevRandao:Hash256; ## tx env: POS block randomness
difficulty:UInt256, ## tx env: difficulty
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
pruneTrie: bool = true): bool
{.gcsafe, raises: [Defect,CatchableError].} =
@ -187,6 +194,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
gasLimit = gasLimit,
fee = fee,
prevRandao = prevRandao,
difficulty = difficulty,
miner = miner,
chainDB = db,
ttdReached = db.isTtdReached(parent.blockHash),
@ -211,6 +219,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
gasLimit = header.gasLimit,
fee = header.fee,
prevRandao= header.prevRandao,
difficulty= header.difficulty,
miner = self.chainDB.getMinerAddress(header),
pruneTrie = pruneTrie)
@ -249,6 +258,7 @@ proc init*(
gasLimit = header.gasLimit,
fee = header.fee,
prevRandao = header.prevRandao,
difficulty = header.difficulty,
miner = chainDB.getMinerAddress(header),
chainDB = chainDB,
tracerFlags = tracerFlags)
@ -305,12 +315,6 @@ proc setupTxContext*(vmState: BaseVMState, origin: EthAddress, gasPrice: GasInt,
vmState.chainDB.config.toFork(vmState.parent.blockNumber + 1)
vmState.gasCosts = vmState.fork.forkToSchedule
proc consensusEnginePoA*(vmState: BaseVMState): bool =
# PoA consensus engine have no reward for miner
# TODO: this need to be fixed somehow
# using `real` engine configuration
vmState.chainDB.config.poaEngine
method coinbase*(vmState: BaseVMState): EthAddress {.base, gcsafe.} =
vmState.minerAddress
@ -324,7 +328,7 @@ method difficulty*(vmState: BaseVMState): UInt256 {.base, gcsafe.} =
# EIP-4399/EIP-3675
UInt256.fromBytesBE(vmState.prevRandao.data, allowPadding = false)
else:
vmState.chainDB.config.calcDifficulty(vmState.timestamp, vmState.parent)
vmState.blockDifficulty
method baseFee*(vmState: BaseVMState): UInt256 {.base, gcsafe.} =
if vmState.fee.isSome:

View File

@ -39,6 +39,7 @@ type
gasLimit* : GasInt
fee* : Option[UInt256]
prevRandao* : Hash256
blockDifficulty*: UInt256
ttdReached* : bool
name* : string
flags* : set[VMFlag]

View File

@ -65,6 +65,7 @@ proc init(
gasLimit: GasInt;
fee: Option[UInt256];
prevRandao: Hash256;
difficulty: UInt256;
miner: EthAddress;
chainDB: BaseChainDB;
ttdReached: bool;
@ -78,6 +79,7 @@ proc init(
self.gasLimit = gasLimit
self.fee = fee
self.prevRandao = prevRandao
self.blockDifficulty = difficulty
self.chainDB = chainDB
self.ttdReached = ttdReached
self.tracer = tracer
@ -94,6 +96,7 @@ proc init(
gasLimit: GasInt;
fee: Option[UInt256];
prevRandao: Hash256;
difficulty: UInt256;
miner: EthAddress;
chainDB: BaseChainDB;
tracerFlags: set[TracerFlags])
@ -107,6 +110,7 @@ proc init(
gasLimit = gasLimit,
fee = fee,
prevRandao= prevRandao,
difficulty= difficulty,
miner = miner,
chainDB = chainDB,
ttdReached= chainDB.isTtdReached(parent.blockHash),
@ -130,6 +134,7 @@ proc new*(
gasLimit: GasInt; ## tx env: gas limit
fee: Option[UInt256]; ## tx env: optional base fee
prevRandao: Hash256; ## tx env: POS block randomness
difficulty: UInt256, ## tx env: difficulty
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
chainDB: BaseChainDB; ## block chain database
tracerFlags: set[TracerFlags] = {};
@ -150,6 +155,7 @@ proc new*(
gasLimit = gasLimit,
fee = fee,
prevRandao = prevRandao,
difficulty = difficulty,
miner = miner,
chainDB = chainDB,
tracerFlags = tracerFlags)
@ -160,6 +166,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
gasLimit: GasInt; ## tx env: gas limit
fee: Option[UInt256]; ## tx env: optional base fee
prevRandao:Hash256; ## tx env: POS block randomness
difficulty:UInt256, ## tx env: difficulty
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
pruneTrie: bool = true): bool
{.gcsafe, raises: [Defect,CatchableError].} =
@ -185,6 +192,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
gasLimit = gasLimit,
fee = fee,
prevRandao = prevRandao,
difficulty = difficulty,
miner = miner,
chainDB = db,
ttdReached = db.isTtdReached(parent.blockHash),
@ -209,6 +217,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
gasLimit = header.gasLimit,
fee = header.fee,
prevRandao= header.prevRandao,
difficulty= header.difficulty,
miner = self.chainDB.getMinerAddress(header),
pruneTrie = pruneTrie)
@ -247,6 +256,7 @@ proc init*(
gasLimit = header.gasLimit,
fee = header.fee,
prevRandao = header.prevRandao,
difficulty = header.difficulty,
miner = chainDB.getMinerAddress(header),
chainDB = chainDB,
tracerFlags = tracerFlags)
@ -290,13 +300,6 @@ proc new*(
tracerFlags = tracerFlags,
pruneTrie = pruneTrie)
proc consensusEnginePoA*(vmState: BaseVMState): bool =
# PoA consensus engine have no reward for miner
# TODO: this need to be fixed somehow
# using `real` engine configuration
vmState.chainDB.config.poaEngine
method coinbase*(vmState: BaseVMState): EthAddress {.base, gcsafe.} =
vmState.minerAddress
@ -310,7 +313,7 @@ method difficulty*(vmState: BaseVMState): UInt256 {.base, gcsafe.} =
# EIP-4399/EIP-3675
UInt256.fromBytesBE(vmState.prevRandao.data, allowPadding = false)
else:
vmState.chainDB.config.calcDifficulty(vmState.timestamp, vmState.parent)
vmState.blockDifficulty
method baseFee*(vmState: BaseVMState): UInt256 {.base, gcsafe.} =
if vmState.fee.isSome:

View File

@ -30,6 +30,7 @@ type
gasLimit* : GasInt
fee* : Option[UInt256]
prevRandao* : Hash256
blockDifficulty*: UInt256
ttdReached* : bool
name* : string
flags* : set[VMFlag]

View File

@ -26,7 +26,6 @@ export
vms.blockNumber,
vms.buildWitness,
vms.coinbase,
vms.consensusEnginePoA,
vms.difficulty,
vms.disableTracing,
vms.enableTracing,