Update terminal total difficulty handling (#992)

why:
  Testing against a replay unit test for Devnet4 made it necessary to
  adjust the TTD handling. Without updated, importing fails at block #5646
  which is the parent of the terminal PoW block. Similar considerations
  apply for Devnet5 and Kiln.
This commit is contained in:
Jordan Hrycaj 2022-03-15 17:21:41 +00:00 committed by GitHub
parent a4b70918ed
commit 534fb528a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 59 deletions

View File

@ -67,7 +67,6 @@ type
txEnv: TxChainPackerEnv ## Assorted parameters, tx packer environment txEnv: TxChainPackerEnv ## Assorted parameters, tx packer environment
# EIP-4399 and EIP-3675 # EIP-4399 and EIP-3675
ttdReached: bool ## Total Terminal Difficulty reached
prevRandao: Hash256 ## POS block randomness prevRandao: Hash256 ## POS block randomness
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -85,8 +84,7 @@ proc resetTxEnv(dh: TxChainRef; parent: BlockHeader; fee: Option[UInt256])
fee = fee, fee = fee,
prevRandao= dh.prevRandao, prevRandao= dh.prevRandao,
miner = dh.miner, miner = dh.miner,
chainDB = dh.db, chainDB = dh.db)
ttdReached= dh.ttdReached)
dh.txEnv.txRoot = BLANK_ROOT_HASH dh.txEnv.txRoot = BLANK_ROOT_HASH
dh.txEnv.stateRoot = dh.txEnv.vmState.parent.stateRoot dh.txEnv.stateRoot = dh.txEnv.vmState.parent.stateRoot
@ -309,10 +307,6 @@ proc `txRoot=`*(dh: TxChainRef; val: Hash256) =
## Setter ## Setter
dh.txEnv.txRoot = val dh.txEnv.txRoot = val
proc `ttdReached=`*(dh: TxChainRef; val: bool) =
## Setter
dh.ttdReached = val
proc `prevRandao=`*(dh: TxChainRef; val: Hash256) = proc `prevRandao=`*(dh: TxChainRef; val: Hash256) =
## Setter ## Setter
dh.prevRandao = val dh.prevRandao = val

View File

@ -40,9 +40,16 @@ template safeExecutor(info: string; code: untyped) =
let e = getCurrentException() let e = getCurrentException()
raise newException(VmStateError, info & "(): " & $e.name & " -- " & e.msg) raise newException(VmStateError, info & "(): " & $e.name & " -- " & e.msg)
proc getMinerAddress(chainDB: BaseChainDB; header: BlockHeader, ttdReached: bool): EthAddress proc isTtdReached(db: BaseChainDB; blockHash: Hash256): bool
{.gcsafe, raises: [Defect,RlpError].} =
## Returns `true` iff the stored sum of difficulties has reached the
## terminal total difficulty, see EIP3675.
if db.config.terminalTotalDifficulty.isSome:
return db.config.terminalTotalDifficulty.get <= db.getScore(blockHash)
proc getMinerAddress(chainDB: BaseChainDB; header: BlockHeader): EthAddress
{.gcsafe, raises: [Defect,CatchableError].} = {.gcsafe, raises: [Defect,CatchableError].} =
if not chainDB.config.poaEngine or ttdReached: if not chainDB.config.poaEngine or chainDB.isTtdReached(header.parentHash):
return header.coinbase return header.coinbase
let account = header.ecRecover let account = header.ecRecover
@ -91,7 +98,6 @@ proc init(
prevRandao: Hash256; prevRandao: Hash256;
miner: EthAddress; miner: EthAddress;
chainDB: BaseChainDB; chainDB: BaseChainDB;
ttdReached: bool;
tracerFlags: set[TracerFlags]) tracerFlags: set[TracerFlags])
{.gcsafe, raises: [Defect,CatchableError].} = {.gcsafe, raises: [Defect,CatchableError].} =
var tracer: TransactionTracer var tracer: TransactionTracer
@ -105,7 +111,7 @@ proc init(
prevRandao= prevRandao, prevRandao= prevRandao,
miner = miner, miner = miner,
chainDB = chainDB, chainDB = chainDB,
ttdReached= ttdReached, ttdReached= chainDB.isTtdReached(parent.blockHash),
tracer = tracer) tracer = tracer)
# -------------- # --------------
@ -128,7 +134,6 @@ proc new*(
prevRandao: Hash256; ## tx env: POS block randomness prevRandao: Hash256; ## tx env: POS block randomness
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA) miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
chainDB: BaseChainDB; ## block chain database chainDB: BaseChainDB; ## block chain database
ttdReached: bool; ## total terminal difficulty reached
tracerFlags: set[TracerFlags] = {}; tracerFlags: set[TracerFlags] = {};
pruneTrie: bool = true): T pruneTrie: bool = true): T
{.gcsafe, raises: [Defect,CatchableError].} = {.gcsafe, raises: [Defect,CatchableError].} =
@ -149,7 +154,6 @@ proc new*(
prevRandao = prevRandao, prevRandao = prevRandao,
miner = miner, miner = miner,
chainDB = chainDB, chainDB = chainDB,
ttdReached = ttdReached,
tracerFlags = tracerFlags) tracerFlags = tracerFlags)
proc reinit*(self: BaseVMState; ## Object descriptor proc reinit*(self: BaseVMState; ## Object descriptor
@ -159,7 +163,6 @@ proc reinit*(self: BaseVMState; ## Object descriptor
fee: Option[Uint256]; ## tx env: optional base fee fee: Option[Uint256]; ## tx env: optional base fee
prevRandao:Hash256; ## tx env: POS block randomness prevRandao:Hash256; ## tx env: POS block randomness
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA) miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
ttdReached:bool; ## total terminal difficulty reached
pruneTrie: bool = true): bool pruneTrie: bool = true): bool
{.gcsafe, raises: [Defect,CatchableError].} = {.gcsafe, raises: [Defect,CatchableError].} =
## Re-initialise state descriptor. The `AccountsCache` database is ## Re-initialise state descriptor. The `AccountsCache` database is
@ -186,7 +189,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
prevRandao = prevRandao, prevRandao = prevRandao,
miner = miner, miner = miner,
chainDB = db, chainDB = db,
ttdReached = ttdReached, ttdReached = db.isTtdReached(parent.blockHash),
tracer = tracer) tracer = tracer)
return true return true
# else: false # else: false
@ -202,17 +205,13 @@ proc reinit*(self: BaseVMState; ## Object descriptor
## ##
## It requires the `header` argument properly initalised so that for PoA ## It requires the `header` argument properly initalised so that for PoA
## networks, the miner address is retrievable via `ecRecover()`. ## networks, the miner address is retrievable via `ecRecover()`.
let ttdReached = self.chainDB.totalDifficulty + header.difficulty > self.chainDB.ttd result = self.reinit(
let miner = self.chainDB.getMinerAddress(header, ttdReached)
self.reinit(
parent = parent, parent = parent,
timestamp = header.timestamp, timestamp = header.timestamp,
gasLimit = header.gasLimit, gasLimit = header.gasLimit,
fee = header.fee, fee = header.fee,
prevRandao= header.prevRandao, prevRandao= header.prevRandao,
miner = miner, miner = self.chainDB.getMinerAddress(header),
ttdReached= ttdReached,
pruneTrie = pruneTrie) pruneTrie = pruneTrie)
proc reinit*(self: BaseVMState; ## Object descriptor proc reinit*(self: BaseVMState; ## Object descriptor
@ -243,18 +242,16 @@ proc init*(
## ##
## It requires the `header` argument properly initalised so that for PoA ## It requires the `header` argument properly initalised so that for PoA
## networks, the miner address is retrievable via `ecRecover()`. ## networks, the miner address is retrievable via `ecRecover()`.
let ttdReached = chainDB.totalDifficulty + header.difficulty > chainDB.ttd self.init(
let miner = chainDB.getMinerAddress(header, ttdReached) ac = AccountsCache.init(chainDB.db, parent.stateRoot, pruneTrie),
self.init(AccountsCache.init(chainDB.db, parent.stateRoot, pruneTrie), parent = parent,
parent, timestamp = header.timestamp,
header.timestamp, gasLimit = header.gasLimit,
header.gasLimit, fee = header.fee,
header.fee, prevRandao = header.prevRandao,
header.prevRandao, miner = chainDB.getMinerAddress(header),
miner, chainDB = chainDB,
chainDB, tracerFlags = tracerFlags)
ttdReached,
tracerFlags)
proc new*( proc new*(
T: type BaseVMState; T: type BaseVMState;

View File

@ -39,9 +39,16 @@ template safeExecutor(info: string; code: untyped) =
let e = getCurrentException() let e = getCurrentException()
raise newException(VmStateError, info & "(): " & $e.name & " -- " & e.msg) raise newException(VmStateError, info & "(): " & $e.name & " -- " & e.msg)
proc getMinerAddress(chainDB: BaseChainDB; header: BlockHeader, ttdReached: bool): EthAddress proc isTtdReached(db: BaseChainDB; blockHash: Hash256): bool
{.gcsafe, raises: [Defect,RlpError].} =
## Returns `true` iff the stored sum of difficulties has reached the
## terminal total difficulty, see EIP3675.
if db.config.terminalTotalDifficulty.isSome:
return db.config.terminalTotalDifficulty.get <= db.getScore(blockHash)
proc getMinerAddress(chainDB: BaseChainDB; header: BlockHeader): EthAddress
{.gcsafe, raises: [Defect,CatchableError].} = {.gcsafe, raises: [Defect,CatchableError].} =
if not chainDB.config.poaEngine or ttdReached: if not chainDB.config.poaEngine or chainDB.isTtdReached(header.parentHash):
return header.coinbase return header.coinbase
let account = header.ecRecover let account = header.ecRecover
@ -90,7 +97,6 @@ proc init(
prevRandao: Hash256; prevRandao: Hash256;
miner: EthAddress; miner: EthAddress;
chainDB: BaseChainDB; chainDB: BaseChainDB;
ttdReached: bool;
tracerFlags: set[TracerFlags]) tracerFlags: set[TracerFlags])
{.gcsafe, raises: [Defect,CatchableError].} = {.gcsafe, raises: [Defect,CatchableError].} =
var tracer: TransactionTracer var tracer: TransactionTracer
@ -104,7 +110,7 @@ proc init(
prevRandao= prevRandao, prevRandao= prevRandao,
miner = miner, miner = miner,
chainDB = chainDB, chainDB = chainDB,
ttdReached= ttdReached, ttdReached= chainDB.isTtdReached(parent.blockHash),
tracer = tracer) tracer = tracer)
# -------------- # --------------
@ -127,7 +133,6 @@ proc new*(
prevRandao: Hash256; ## tx env: POS block randomness prevRandao: Hash256; ## tx env: POS block randomness
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA) miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
chainDB: BaseChainDB; ## block chain database chainDB: BaseChainDB; ## block chain database
ttdReached: bool; ## total terminal difficulty reached
tracerFlags: set[TracerFlags] = {}; tracerFlags: set[TracerFlags] = {};
pruneTrie: bool = true): T pruneTrie: bool = true): T
{.gcsafe, raises: [Defect,CatchableError].} = {.gcsafe, raises: [Defect,CatchableError].} =
@ -148,7 +153,6 @@ proc new*(
prevRandao = prevRandao, prevRandao = prevRandao,
miner = miner, miner = miner,
chainDB = chainDB, chainDB = chainDB,
ttdReached = ttdReached,
tracerFlags = tracerFlags) tracerFlags = tracerFlags)
proc reinit*(self: BaseVMState; ## Object descriptor proc reinit*(self: BaseVMState; ## Object descriptor
@ -158,7 +162,6 @@ proc reinit*(self: BaseVMState; ## Object descriptor
fee: Option[Uint256]; ## tx env: optional base fee fee: Option[Uint256]; ## tx env: optional base fee
prevRandao:Hash256; ## tx env: POS block randomness prevRandao:Hash256; ## tx env: POS block randomness
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA) miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
ttdReached:bool; ## total terminal difficulty reached
pruneTrie: bool = true): bool pruneTrie: bool = true): bool
{.gcsafe, raises: [Defect,CatchableError].} = {.gcsafe, raises: [Defect,CatchableError].} =
## Re-initialise state descriptor. The `AccountsCache` database is ## Re-initialise state descriptor. The `AccountsCache` database is
@ -185,7 +188,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
prevRandao = prevRandao, prevRandao = prevRandao,
miner = miner, miner = miner,
chainDB = db, chainDB = db,
ttdReached = ttdReached, ttdReached = db.isTtdReached(parent.blockHash),
tracer = tracer) tracer = tracer)
return true return true
# else: false # else: false
@ -201,16 +204,13 @@ proc reinit*(self: BaseVMState; ## Object descriptor
## ##
## It requires the `header` argument properly initalised so that for PoA ## It requires the `header` argument properly initalised so that for PoA
## networks, the miner address is retrievable via `ecRecover()`. ## networks, the miner address is retrievable via `ecRecover()`.
let ttdReached = self.chainDB.totalDifficulty + header.difficulty > self.chainDB.ttd result = self.reinit(
let miner = self.chainDB.getMinerAddress(header, ttdReached)
self.reinit(
parent = parent, parent = parent,
timestamp = header.timestamp, timestamp = header.timestamp,
gasLimit = header.gasLimit, gasLimit = header.gasLimit,
fee = header.fee, fee = header.fee,
prevRandao= header.prevRandao, prevRandao= header.prevRandao,
miner = miner, miner = self.chainDB.getMinerAddress(header),
ttdReached= ttdReached,
pruneTrie = pruneTrie) pruneTrie = pruneTrie)
proc reinit*(self: BaseVMState; ## Object descriptor proc reinit*(self: BaseVMState; ## Object descriptor
@ -241,18 +241,16 @@ proc init*(
## ##
## It requires the `header` argument properly initalised so that for PoA ## It requires the `header` argument properly initalised so that for PoA
## networks, the miner address is retrievable via `ecRecover()`. ## networks, the miner address is retrievable via `ecRecover()`.
let ttdReached = chainDB.totalDifficulty + header.difficulty > chainDB.ttd self.init(
let miner = chainDB.getMinerAddress(header, ttdReached) ac = AccountsCache.init(chainDB.db, parent.stateRoot, pruneTrie),
self.init(AccountsCache.init(chainDB.db, parent.stateRoot, pruneTrie), parent = parent,
parent, timestamp = header.timestamp,
header.timestamp, gasLimit = header.gasLimit,
header.gasLimit, fee = header.fee,
header.fee, prevRandao = header.prevRandao,
header.prevRandao, miner = chainDB.getMinerAddress(header),
miner, chainDB = chainDB,
chainDB, tracerFlags = tracerFlags)
ttdReached,
tracerFlags)
proc new*( proc new*(
T: type BaseVMState; T: type BaseVMState;