fix shanghai withdrawal validation

previously, the withdrawal validation is in process_block only,
but the one in persist block, which is also used in synchronizer
is not validated properly.
This commit is contained in:
jangko 2023-06-25 20:30:34 +07:00
parent f8c1a7f0a8
commit ff1a45e095
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
12 changed files with 58 additions and 67 deletions

View File

@ -226,7 +226,7 @@ jobs:
echo '```' >> release_notes.md
- name: Delete tag
uses: dev-drprasad/delete-tag-and-release@v0.2.0
uses: dev-drprasad/delete-tag-and-release@v1.0.1
with:
delete_release: true
tag_name: nightly

View File

@ -162,7 +162,7 @@ jobs:
cat windows_amd64_stat/* >> stat_notes.md
- name: Delete tag
uses: dev-drprasad/delete-tag-and-release@v0.2.0
uses: dev-drprasad/delete-tag-and-release@v1.0.1
with:
delete_release: true
tag_name: sim-stat

View File

@ -9,7 +9,7 @@
# according to those terms.
import
std/[json, strutils, options],
std/[json],
stew/byteutils,
../../../tools/common/helpers,
../../../nimbus/common/chain_config

View File

@ -94,6 +94,9 @@ proc toGenesisHeader*(
if g.difficulty.isZero and fork <= London:
result.difficulty = GENESIS_DIFFICULTY
if fork >= Shanghai:
result.withdrawalsRoot = some(EMPTY_ROOT_HASH)
proc toGenesisHeader*(
genesis: Genesis;
fork: HardFork;

View File

@ -14,8 +14,7 @@ import
../../common/common,
../../utils/utils,
../pow,
../clique,
../validate
../clique
export
common

View File

@ -109,8 +109,7 @@ proc persistBlocksImpl(c: ChainRef; headers: openArray[BlockHeader];
let res = c.com.validateHeaderAndKinship(
header,
body,
checkSealOK = false, # TODO: how to checkseal from here
pow = c.pow)
checkSealOK = false) # TODO: how to checkseal from here
if res.isErr:
debug "block validation error",
msg = res.error

View File

@ -85,20 +85,15 @@ proc procBlkPreamble(vmState: BaseVMState;
if vmState.determineFork >= FkShanghai:
if header.withdrawalsRoot.isNone:
raise ValidationError.newException("Post-Shanghai block header must have withdrawalsRoot")
elif body.withdrawals.isNone:
if body.withdrawals.isNone:
raise ValidationError.newException("Post-Shanghai block body must have withdrawals")
else:
if body.withdrawals.get.calcWithdrawalsRoot != header.withdrawalsRoot.get:
debug "Mismatched withdrawalsRoot",
blockNumber = header.blockNumber
return false
for withdrawal in body.withdrawals.get:
vmState.stateDB.addBalance(withdrawal.address, withdrawal.amount.gwei)
for withdrawal in body.withdrawals.get:
vmState.stateDB.addBalance(withdrawal.address, withdrawal.amount.gwei)
else:
if header.withdrawalsRoot.isSome:
raise ValidationError.newException("Pre-Shanghai block header must not have withdrawalsRoot")
elif body.withdrawals.isSome:
if body.withdrawals.isSome:
raise ValidationError.newException("Pre-Shanghai block body must not have withdrawals")
if vmState.cumulativeGasUsed != header.gasUsed:

View File

@ -10,7 +10,6 @@
import
std/[sequtils, sets, times, strutils],
../common/common,
../db/accounts_cache,
".."/[transaction, common/common],
".."/[errors],
@ -24,8 +23,6 @@ from stew/byteutils
import nil
export
pow.PowRef,
pow.new,
results
{.push raises: [].}
@ -73,8 +70,7 @@ proc validateSeal(pow: PowRef; header: BlockHeader): Result[void,string] =
ok()
proc validateHeader(com: CommonRef; header, parentHeader: BlockHeader;
txs: openArray[Transaction]; checkSealOK: bool;
pow: PowRef): Result[void,string] =
body: BlockBody; checkSealOK: bool): Result[void,string] =
template inDAOExtraRange(blockNumber: BlockNumber): bool =
# EIP-799
@ -88,7 +84,7 @@ proc validateHeader(com: CommonRef; header, parentHeader: BlockHeader;
if header.extraData.len > 32:
return err("BlockHeader.extraData larger than 32 bytes")
if header.gasUsed == 0 and 0 < txs.len:
if header.gasUsed == 0 and 0 < body.transactions.len:
return err("zero gasUsed but transactions present");
if header.gasUsed < 0 or header.gasUsed > header.gasLimit:
@ -123,10 +119,10 @@ proc validateHeader(com: CommonRef; header, parentHeader: BlockHeader;
return err("provided header difficulty is too low")
if checkSealOK:
return pow.validateSeal(header)
return com.pow.validateSeal(header)
? com.validateWithdrawals(header)
? com.validateEip4844Header(header, parentHeader, txs)
? com.validateWithdrawals(header, body)
? com.validateEip4844Header(header, parentHeader, body.transactions)
ok()
@ -148,8 +144,8 @@ func validateUncle(currBlock, uncle, uncleParent: BlockHeader):
proc validateUncles(com: CommonRef; header: BlockHeader;
uncles: openArray[BlockHeader]; checkSealOK: bool;
pow: PowRef): Result[void,string] =
uncles: openArray[BlockHeader];
checkSealOK: bool): Result[void,string] =
let hasUncles = uncles.len > 0
let shouldHaveUncles = header.ommersHash != EMPTY_UNCLE_HASH
@ -213,7 +209,7 @@ proc validateUncles(com: CommonRef; header: BlockHeader;
# Now perform VM level validation of the uncle
if checkSealOK:
result = pow.validateSeal(uncle)
result = com.pow.validateSeal(uncle)
if result.isErr:
return
@ -380,10 +376,8 @@ proc validateTransaction*(
proc validateHeaderAndKinship*(
com: CommonRef;
header: BlockHeader;
uncles: openArray[BlockHeader];
txs: openArray[Transaction];
checkSealOK: bool;
pow: PowRef): Result[void, string] =
body: BlockBody;
checkSealOK: bool): Result[void, string] =
if header.isGenesis:
if header.extraData.len > 32:
return err("BlockHeader.extraData larger than 32 bytes")
@ -396,41 +390,22 @@ proc validateHeaderAndKinship*(
return err("Failed to load block header from DB")
result = com.validateHeader(
header, parent, txs, checkSealOK, pow)
header, parent, body, checkSealOK)
if result.isErr:
return
if uncles.len > MAX_UNCLES:
if body.uncles.len > MAX_UNCLES:
return err("Number of uncles exceed limit.")
if not chainDB.exists(header.stateRoot):
return err("`state_root` was not found in the db.")
if com.consensus != ConsensusType.POS:
result = com.validateUncles(header, uncles, checkSealOK, pow)
result = com.validateUncles(header, body.uncles, checkSealOK)
if result.isOk:
result = com.validateGasLimitOrBaseFee(header, parent)
proc validateHeaderAndKinship*(
com: CommonRef;
header: BlockHeader;
body: BlockBody;
checkSealOK: bool;
pow: PowRef): Result[void, string] =
com.validateHeaderAndKinship(
header, body.uncles, body.transactions, checkSealOK, pow)
proc validateHeaderAndKinship*(
com: CommonRef;
ethBlock: EthBlock;
checkSealOK: bool;
pow: PowRef): Result[void,string] =
com.validateHeaderAndKinship(
ethBlock.header, ethBlock.uncles, ethBlock.txs,
checkSealOK, pow)
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------

View File

@ -15,9 +15,25 @@ import
{.push raises: [].}
# https://eips.ethereum.org/EIPS/eip-4895
func validateWithdrawals*(
com: CommonRef, header: BlockHeader
proc validateWithdrawals*(
com: CommonRef, header: BlockHeader, body: BlockBody
): Result[void, string] =
if header.withdrawalsRoot.isSome:
return err("Withdrawals not yet implemented")
if com.forkGTE(Shanghai):
if header.withdrawalsRoot.isNone:
return err("Post-Shanghai block header must have withdrawalsRoot")
elif body.withdrawals.isNone:
return err("Post-Shanghai block body must have withdrawals")
else:
try:
if body.withdrawals.get.calcWithdrawalsRoot != header.withdrawalsRoot.get:
return err("Mismatched withdrawalsRoot blockNumber =" & $header.blockNumber)
except RlpError as ex:
return err(ex.msg)
else:
if header.withdrawalsRoot.isSome:
return err("Pre-Shanghai block header must not have withdrawalsRoot")
elif body.withdrawals.isSome:
return err("Pre-Shanghai block body must not have withdrawals")
return ok()

View File

@ -9,7 +9,7 @@
# according to those terms.
import
std/[math, macros],
std/[macros],
stew/results,
"."/[types, blake2b_f, blscurve],
./interpreter/[gas_meter, gas_costs, utils/utils_numeric],

View File

@ -180,7 +180,7 @@ proc validateDifficulty(ctx: LegacySyncRef,
return false
proc validateHeader(ctx: LegacySyncRef, header: BlockHeader,
txs: openArray[Transaction],
body: BlockBody,
height = none(BlockNumber)): bool
{.raises: [CatchableError].} =
if header.parentHash == GENESIS_PARENT_HASH:
@ -237,13 +237,13 @@ proc validateHeader(ctx: LegacySyncRef, header: BlockHeader,
parentNumber=parentHeader.blockNumber
return false
res = com.validateWithdrawals(header)
res = com.validateWithdrawals(header, body)
if res.isErr:
trace "validate withdrawals error",
msg=res.error
return false
res = com.validateEip4844Header(header, parentHeader, txs)
res = com.validateEip4844Header(header, parentHeader, body.transactions)
if res.isErr:
trace "validate eip4844 error",
msg=res.error
@ -1053,7 +1053,13 @@ proc handleNewBlock(ctx: LegacySyncRef,
number=blk.header.blockNumber
return
if not ctx.validateHeader(blk.header, blk.txs):
let body = BlockBody(
transactions: blk.txs,
uncles: blk.uncles,
withdrawals: blk.withdrawals
)
if not ctx.validateHeader(blk.header, body):
error "invalid header from peer",
peer, hash=short(blk.header.blockHash)
return

View File

@ -49,8 +49,6 @@ type
network : string
postStateHash: Hash256
var pow = PowRef.new
proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = false, trace = false)
func normalizeNumber(n: JsonNode): JsonNode =
@ -206,7 +204,7 @@ proc importBlock(tester: var Tester, com: CommonRef,
if validation:
let rc = com.validateHeaderAndKinship(
tb.header, tb.body, checkSeal, pow)
tb.header, tb.body, checkSeal)
if rc.isErr:
raise newException(
ValidationError, "validateHeaderAndKinship: " & rc.error)
@ -259,7 +257,7 @@ proc runTester(tester: var Tester, com: CommonRef, testStatusIMPL: var TestStatu
# manually validating
let res = com.validateHeaderAndKinship(
tb.header, tb.body, checkSeal, pow)
tb.header, tb.body, checkSeal)
check res.isOk
when defined(noisy):
if res.isErr: