mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-23 02:29:26 +00:00
#768 Moved/re-implemented ecRecover() from Clique sources to utils/ec_recover
why: The same functionality was differently implemented in one or the other form. details: Caching and non-caching variants available
This commit is contained in:
parent
9aea669363
commit
4713bd4cf4
@ -69,3 +69,11 @@ const
|
||||
|
||||
# EIP
|
||||
MaxPrecompilesAddr* = 0xFFFF
|
||||
|
||||
EXTRA_SEAL* = ##\
|
||||
## Fixed number of suffix bytes reserved for signer seal of the `extraData`
|
||||
## header field. The 65 bytes constant value is for signatures based on the
|
||||
## standard secp256k1 curve.
|
||||
65
|
||||
|
||||
# End
|
||||
|
@ -21,7 +21,7 @@
|
||||
import
|
||||
std/[random, sequtils, strutils, times],
|
||||
../../db/db_chain,
|
||||
./clique_cfg/ec_recover,
|
||||
../../utils/ec_recover,
|
||||
./clique_defs,
|
||||
eth/common,
|
||||
ethash,
|
||||
@ -117,7 +117,7 @@ proc newCliqueCfg*(db: BaseChainDB): CliqueCfg =
|
||||
# clique/clique.go(145): func ecrecover(header [..]
|
||||
proc ecRecover*(cfg: CliqueCfg; header: BlockHeader): auto
|
||||
{.gcsafe, raises: [Defect,CatchableError].} =
|
||||
cfg.signatures.getEcRecover(header)
|
||||
cfg.signatures.ecRecover(header)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public setters
|
||||
|
@ -1,103 +0,0 @@
|
||||
# Nimbus
|
||||
# Copyright (c) 2018 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0)
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
# http://opensource.org/licenses/MIT)
|
||||
# at your option. This file may not be copied, modified, or distributed except
|
||||
# according to those terms.
|
||||
|
||||
##
|
||||
## Address Cache for Clique PoA Consensus Protocol
|
||||
## ===============================================
|
||||
##
|
||||
## For details see
|
||||
## `EIP-225 <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-225.md>`_
|
||||
## and
|
||||
## `go-ethereum <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-225.md>`_
|
||||
##
|
||||
|
||||
import
|
||||
../../../utils/lru_cache,
|
||||
../clique_defs,
|
||||
../clique_helpers,
|
||||
eth/[common, keys, rlp],
|
||||
stint
|
||||
|
||||
type
|
||||
# simplify Hash256 for rlp serialisation
|
||||
EcKey32 = array[32, byte]
|
||||
|
||||
EcRecover* = LruCache[BlockHeader,EcKey32,EthAddress,CliqueError]
|
||||
|
||||
{.push raises: [Defect].}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc initEcRecover*(cache: var EcRecover) =
|
||||
|
||||
var toKey: LruKey[BlockHeader,EcKey32] =
|
||||
|
||||
# Use the seal hash for cache lookup
|
||||
proc(header:BlockHeader): EcKey32 =
|
||||
## If the signature's already cached, return that
|
||||
# clique/clique.go(148): hash := header.Hash()
|
||||
header.blockHash.data
|
||||
|
||||
var toValue: LruValue[BlockHeader,EthAddress,CliqueError] =
|
||||
|
||||
# Retrieve signature from the header's extra data fields
|
||||
proc(header: BlockHeader): Result[EthAddress,CliqueError] =
|
||||
|
||||
# Extract signature from extra data field (last 65 bytes)
|
||||
let msg = header.extraData
|
||||
|
||||
# clique/clique.go(153): if len(header.Extra) < extraSeal {
|
||||
if msg.len < EXTRA_SEAL:
|
||||
return err((errMissingSignature,""))
|
||||
let sig = Signature.fromRaw(
|
||||
msg.toOpenArray(msg.len - EXTRA_SEAL, msg.high))
|
||||
if sig.isErr:
|
||||
return err((errSkSigResult,$sig.error))
|
||||
|
||||
# Recover the public key from signature and seal hash
|
||||
# clique/clique.go(159): pubkey, err := crypto.Ecrecover( [..]
|
||||
let pubKey = recover(sig.value, SKMessage(header.hashSealHeader.data))
|
||||
if pubKey.isErr:
|
||||
return err((errSkPubKeyResult,$pubKey.error))
|
||||
|
||||
# Convert public key to address.
|
||||
return ok(pubKey.value.toCanonicalAddress)
|
||||
|
||||
cache.initCache(toKey, toValue, INMEMORY_SIGNATURES)
|
||||
|
||||
proc initEcRecover*: EcRecover {.gcsafe, raises: [Defect].} =
|
||||
result.initEcRecover
|
||||
|
||||
|
||||
# clique/clique.go(145): func ecrecover(header [..]
|
||||
proc getEcRecover*(addrCache: var EcRecover; header: BlockHeader): auto {.
|
||||
gcsafe, raises: [Defect,CatchableError].} =
|
||||
## extract Ethereum account address from a signed header block, the relevant
|
||||
## signature used is appended to the re-purposed extra data field
|
||||
addrCache.getItem(header)
|
||||
|
||||
|
||||
proc append*(rw: var RlpWriter; ecRec: EcRecover) {.
|
||||
inline, raises: [Defect,KeyError].} =
|
||||
## Generic support for `rlp.encode(ecRec)`
|
||||
rw.append(ecRec.data)
|
||||
|
||||
proc read*(rlp: var Rlp; Q: type EcRecover): Q {.
|
||||
inline, raises: [Defect,KeyError].} =
|
||||
## Generic support for `rlp.decode(bytes)` for loading the cache from a
|
||||
## serialised data stream.
|
||||
result.initEcRecover
|
||||
result.data = rlp.read(type result.data)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
@ -40,10 +40,6 @@ const
|
||||
## Number of recent vote snapshots to keep in memory.
|
||||
128
|
||||
|
||||
INMEMORY_SIGNATURES* = ##\
|
||||
## Number of recent block signatures to keep in memory
|
||||
4096
|
||||
|
||||
WIGGLE_TIME* = ##\
|
||||
## PoA mining only (currently unsupported).
|
||||
##
|
||||
@ -62,11 +58,6 @@ const
|
||||
## Suggested 32 bytes to retain the current extra-data allowance and/or use.
|
||||
32
|
||||
|
||||
EXTRA_SEAL* = ##\
|
||||
## Fixed number of extra-data suffix bytes reserved for signer seal.
|
||||
## 65 bytes fixed as signatures are based on the standard secp256k1 curve.
|
||||
65
|
||||
|
||||
NONCE_AUTH* = ##\
|
||||
## Magic nonce number 0xffffffffffffffff to vote on adding a new signer.
|
||||
0xffffffffffffffffu64.toBlockNonce
|
||||
@ -208,21 +199,11 @@ type
|
||||
## unknown.
|
||||
"unknown ancestor"
|
||||
|
||||
# errPrunedAncestor = ##\
|
||||
# ## is returned when validating a block requires an ancestor that is
|
||||
# ## known, but the state of which is not available.
|
||||
# "pruned ancestor"
|
||||
|
||||
errFutureBlock = ##\
|
||||
## is returned when a block's timestamp is in the future according to
|
||||
## the current node.
|
||||
"block in the future"
|
||||
|
||||
# errInvalidNumber = ##\
|
||||
# ## is returned if a block's number doesn't equal its parent's plus one.
|
||||
# "invalid block number"
|
||||
|
||||
|
||||
# additional/bespoke errors, manually added
|
||||
# -----------------------------------------
|
||||
|
||||
@ -237,8 +218,9 @@ type
|
||||
## Attempt to assign a value to a non-existing slot
|
||||
"Missing LRU slot for snapshot"
|
||||
|
||||
errSkSigResult ## eth/keys subsytem error: signature
|
||||
errSkPubKeyResult ## eth/keys subsytem error: public key
|
||||
errEcRecover = ##\
|
||||
## Subsytem error"
|
||||
"ecRecover failed"
|
||||
|
||||
errSnapshotLoad ## DB subsytem error
|
||||
errSnapshotStore ## ..
|
||||
|
@ -133,7 +133,7 @@ proc verifySeal(c: Clique; header: BlockHeader): CliqueOkResult
|
||||
# Resolve the authorization key and check against signers
|
||||
let signer = c.cfg.ecRecover(header)
|
||||
if signer.isErr:
|
||||
return err(signer.error)
|
||||
return err((errEcRecover,$signer.error))
|
||||
|
||||
if not snapshot.isSigner(signer.value):
|
||||
return err((errUnauthorizedSigner,""))
|
||||
|
@ -141,23 +141,25 @@ proc snapshotApplySeq*(s: Snapshot; headers: var seq[BlockHeader],
|
||||
s.recents.del(number - limit)
|
||||
|
||||
# Resolve the authorization key and check against signers
|
||||
let signer = ? s.cfg.ecRecover(header)
|
||||
let signer = s.cfg.ecRecover(header)
|
||||
if signer.isErr:
|
||||
return err((errEcRecover,$signer.error))
|
||||
#s.say "applySnapshot signer=", s.pp(signer)
|
||||
|
||||
if not s.ballot.isAuthSigner(signer):
|
||||
if not s.ballot.isAuthSigner(signer.value):
|
||||
s.say "applySnapshot signer not authorised => fail ", s.pp(29)
|
||||
return err((errUnauthorizedSigner,""))
|
||||
|
||||
for recent in s.recents.values:
|
||||
if recent == signer:
|
||||
s.say "applySnapshot signer recently seen ", s.pp(signer)
|
||||
if recent == signer.value:
|
||||
s.say "applySnapshot signer recently seen ", s.pp(signer.value)
|
||||
echo "+++ applySnapshot #", header.blockNumber, " err=errRecentlySigned"
|
||||
return err((errRecentlySigned,""))
|
||||
s.recents[number] = signer
|
||||
s.recents[number] = signer.value
|
||||
|
||||
# Header authorized, discard any previous vote from the signer
|
||||
# clique/snapshot.go(233): for i, vote := range snap.Votes {
|
||||
s.ballot.delVote(signer = signer, address = header.coinbase)
|
||||
s.ballot.delVote(signer = signer.value, address = header.coinbase)
|
||||
|
||||
# Tally up the new vote from the signer
|
||||
# clique/snapshot.go(244): var authorize bool
|
||||
@ -167,7 +169,7 @@ proc snapshotApplySeq*(s: Snapshot; headers: var seq[BlockHeader],
|
||||
elif header.nonce != NONCE_DROP:
|
||||
return err((errInvalidVote,""))
|
||||
let vote = Vote(address: header.coinbase,
|
||||
signer: signer,
|
||||
signer: signer.value,
|
||||
blockNumber: number,
|
||||
authorize: authOk)
|
||||
#s.say "applySnapshot calling addVote ", s.pp(vote)
|
||||
|
137
nimbus/utils/ec_recover.nim
Normal file
137
nimbus/utils/ec_recover.nim
Normal file
@ -0,0 +1,137 @@
|
||||
# Nimbus
|
||||
# Copyright (c) 2018 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0)
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
# http://opensource.org/licenses/MIT)
|
||||
# at your option. This file may not be copied, modified, or distributed except
|
||||
# according to those terms.
|
||||
|
||||
##
|
||||
## Recover Address From Signature
|
||||
## ==============================
|
||||
##
|
||||
## This module provides caching and direct versions for recovering the
|
||||
## `EthAddress` from an extended signature. The caching version reduces
|
||||
## calculation time for the price of maintaing it in a LRU cache.
|
||||
|
||||
import
|
||||
./utils_defs,
|
||||
./lru_cache,
|
||||
../constants,
|
||||
eth/[common, keys, rlp],
|
||||
nimcrypto,
|
||||
stew/results,
|
||||
stint
|
||||
|
||||
const
|
||||
INMEMORY_SIGNATURES* = ##\
|
||||
## Number of recent block signatures to keep in memory
|
||||
4096
|
||||
|
||||
type
|
||||
# simplify Hash256 for rlp serialisation
|
||||
EcKey32 = array[32, byte]
|
||||
|
||||
EcRecover* = LruCache[BlockHeader,EcKey32,EthAddress,UtilsError]
|
||||
|
||||
{.push raises: [Defect].}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private helpers
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc encodePreSealed(header: BlockHeader): seq[byte] {.inline.} =
|
||||
## Cut sigature off `extraData` header field and consider new `baseFee`
|
||||
## field for Eip1559.
|
||||
doAssert EXTRA_SEAL < header.extraData.len
|
||||
|
||||
var rlpHeader = header
|
||||
rlpHeader.extraData.setLen(header.extraData.len - EXTRA_SEAL)
|
||||
rlp.encode(rlpHeader)
|
||||
|
||||
|
||||
proc hashPreSealed(header: BlockHeader): Hash256 {.inline.} =
|
||||
## Returns the hash of a block prior to it being sealed.
|
||||
keccak256.digest header.encodePreSealed
|
||||
|
||||
|
||||
proc ecRecover*(extraData: openArray[byte];
|
||||
hash: Hash256): Result[EthAddress,UtilsError] {.inline.} =
|
||||
## Extract account address from the last 65 bytes of the `extraData` argument
|
||||
## (which is typically the bock header field with the same name.) The second
|
||||
## argument `hash` is used to extract the intermediate public key. Typically,
|
||||
## this would be the hash of the block header without the last 65 bytes of
|
||||
## the `extraData` field reserved for the signature.
|
||||
if extraData.len < EXTRA_SEAL:
|
||||
return err((errMissingSignature,""))
|
||||
|
||||
let sig = Signature.fromRaw(
|
||||
extraData.toOpenArray(extraData.len - EXTRA_SEAL, extraData.high))
|
||||
if sig.isErr:
|
||||
return err((errSkSigResult,$sig.error))
|
||||
|
||||
# Recover the public key from signature and seal hash
|
||||
let pubKey = recover(sig.value, SKMessage(hash.data))
|
||||
if pubKey.isErr:
|
||||
return err((errSkPubKeyResult,$pubKey.error))
|
||||
|
||||
# Convert public key to address.
|
||||
return ok(pubKey.value.toCanonicalAddress)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public function: straight ecRecover version
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc ecRecover*(header: BlockHeader): Result[EthAddress,UtilsError] =
|
||||
## Extract account address from the `extraData` field (last 65 bytes) of the
|
||||
## argument header.
|
||||
header.extraData.ecRecover(header.hashPreSealed)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public constructor for caching ecRecover version
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc initEcRecover*(cache: var EcRecover; cacheSize = INMEMORY_SIGNATURES) =
|
||||
|
||||
var toKey: LruKey[BlockHeader,EcKey32] =
|
||||
proc(header:BlockHeader): EcKey32 =
|
||||
header.blockHash.data
|
||||
|
||||
cache.initCache(toKey, ecRecover, cacheSize)
|
||||
|
||||
proc initEcRecover*: EcRecover {.gcsafe, raises: [Defect].} =
|
||||
result.initEcRecover
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public function: caching ecRecover version
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc ecRecover*(addrCache: var EcRecover;
|
||||
header: BlockHeader): Result[EthAddress,UtilsError]
|
||||
{.gcsafe, raises: [Defect,CatchableError].} =
|
||||
## Extract account address from `extraData` field (last 65 bytes) of the
|
||||
## argument header. The result is kept in a LRU cache to re-purposed for
|
||||
## improved result delivery avoiding calculations.
|
||||
addrCache.getItem(header)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public PLP mixin functions for caching version
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc append*(rw: var RlpWriter; ecRec: EcRecover) {.
|
||||
inline, raises: [Defect,KeyError].} =
|
||||
## Generic support for `rlp.encode(ecRec)`
|
||||
rw.append(ecRec.data)
|
||||
|
||||
proc read*(rlp: var Rlp; Q: type EcRecover): Q {.
|
||||
inline, raises: [Defect,KeyError].} =
|
||||
## Generic support for `rlp.decode(bytes)` for loading the cache from a
|
||||
## serialised data stream.
|
||||
result.initEcRecover
|
||||
result.data = rlp.read(type result.data)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
52
nimbus/utils/utils_defs.nim
Normal file
52
nimbus/utils/utils_defs.nim
Normal file
@ -0,0 +1,52 @@
|
||||
# Nimbus
|
||||
# Copyright (c) 2018 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0)
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
# http://opensource.org/licenses/MIT)
|
||||
# at your option. This file may not be copied, modified, or distributed except
|
||||
# according to those terms.
|
||||
|
||||
##
|
||||
## Definitions, Error Constants, etc.
|
||||
## ===================================
|
||||
##
|
||||
|
||||
type
|
||||
UtilsErrorType* = enum
|
||||
resetUtilsError = ##\
|
||||
## Default/reset value (use `utilsNoError` below rather than this valie)
|
||||
(0, "no error")
|
||||
|
||||
errMissingSignature = ##\
|
||||
## is returned if the `extraData` header field does not seem to contain
|
||||
## a 65 byte secp256k1 signature.
|
||||
"extraData 65 byte signature suffix missing"
|
||||
|
||||
errSkSigResult = ##\
|
||||
## eth/keys subsytem error: signature
|
||||
"signature error"
|
||||
|
||||
errSkPubKeyResult = ##\
|
||||
## eth/keys subsytem error: public key
|
||||
"public key error"
|
||||
|
||||
UtilsError* = ##\
|
||||
## Error message, tinned component + explanatory text (if any)
|
||||
(UtilsErrorType,string)
|
||||
|
||||
|
||||
const
|
||||
utilsNoError* = ##\
|
||||
## No-error constant
|
||||
(resetUtilsError, "")
|
||||
|
||||
|
||||
proc `$`*(e: UtilsError): string {.inline.} =
|
||||
## Join text fragments
|
||||
result = $e[0]
|
||||
if e[1] != "":
|
||||
result &= ": " & e[1]
|
||||
|
||||
# End
|
@ -9,12 +9,32 @@
|
||||
# according to those terms.
|
||||
|
||||
import
|
||||
macros, strformat, tables, sets, options,
|
||||
eth/[common, keys, rlp], nimcrypto/keccak,
|
||||
./interpreter/gas_costs, ../errors, ../forks,
|
||||
../constants, ../db/[db_chain, accounts_cache],
|
||||
../utils, json, ./transaction_tracer, ./types,
|
||||
../config, ../../stateless/[witness_from_tree, witness_types]
|
||||
std/[json, macros, options, sets, strformat, tables],
|
||||
../../stateless/[witness_from_tree, witness_types],
|
||||
../config,
|
||||
../constants,
|
||||
../db/[db_chain, accounts_cache],
|
||||
../errors,
|
||||
../forks,
|
||||
../utils,
|
||||
../utils/ec_recover,
|
||||
./interpreter/gas_costs,
|
||||
./transaction_tracer,
|
||||
./types,
|
||||
eth/[common, keys]
|
||||
|
||||
|
||||
proc getMinerAddress(vmState: BaseVMState): EthAddress =
|
||||
if not vmState.consensusEnginePoA:
|
||||
return vmState.blockHeader.coinbase
|
||||
|
||||
let account = vmState.blockHeader.ecRecover
|
||||
if account.isErr:
|
||||
let msg = "Could not recover account address: " & $account.error
|
||||
raise newException(ValidationError, msg)
|
||||
|
||||
account.value
|
||||
|
||||
|
||||
proc newAccessLogs*: AccessLogs =
|
||||
AccessLogs(reads: initTable[string, string](), writes: initTable[string, string]())
|
||||
@ -29,8 +49,6 @@ proc `$`*(vmState: BaseVMState): string =
|
||||
else:
|
||||
result = &"VMState {vmState.name}:\n header: {vmState.blockHeader}\n chaindb: {vmState.chaindb}"
|
||||
|
||||
proc getMinerAddress(vmState: BaseVMState): EthAddress
|
||||
|
||||
proc init*(self: BaseVMState, prevStateRoot: Hash256, header: BlockHeader,
|
||||
chainDB: BaseChainDB, tracerFlags: set[TracerFlags] = {}) =
|
||||
self.prevHeaders = @[]
|
||||
@ -74,43 +92,6 @@ proc consensusEnginePoA*(vmState: BaseVMState): bool =
|
||||
# using `real` engine configuration
|
||||
vmState.chainDB.config.poaEngine
|
||||
|
||||
proc getSignature(bytes: openArray[byte], output: var Signature): bool =
|
||||
let sig = Signature.fromRaw(bytes)
|
||||
if sig.isOk:
|
||||
output = sig[]
|
||||
return true
|
||||
return false
|
||||
|
||||
proc headerHashOriExtraData(vmState: BaseVMState): Hash256 =
|
||||
var tmp = vmState.blockHeader
|
||||
tmp.extraData.setLen(tmp.extraData.len-65)
|
||||
result = keccak256.digest(rlp.encode(tmp))
|
||||
|
||||
proc calcMinerAddress(sigRaw: openArray[byte], vmState: BaseVMState, output: var EthAddress): bool =
|
||||
var sig: Signature
|
||||
if sigRaw.getSignature(sig):
|
||||
let headerHash = headerHashOriExtraData(vmState)
|
||||
let pubkey = recover(sig, SKMessage(headerHash.data))
|
||||
if pubkey.isOk:
|
||||
output = pubkey[].toCanonicalAddress()
|
||||
result = true
|
||||
|
||||
proc getMinerAddress(vmState: BaseVMState): EthAddress =
|
||||
if not vmState.consensusEnginePoA:
|
||||
return vmState.blockHeader.coinbase
|
||||
|
||||
template data: untyped =
|
||||
vmState.blockHeader.extraData
|
||||
|
||||
let len = data.len
|
||||
doAssert(len >= 65)
|
||||
|
||||
var miner: EthAddress
|
||||
if calcMinerAddress(data.toOpenArray(len - 65, len-1), vmState, miner):
|
||||
result = miner
|
||||
else:
|
||||
raise newException(ValidationError, "Could not derive miner address from header extradata")
|
||||
|
||||
proc updateBlockHeader*(vmState: BaseVMState, header: BlockHeader) =
|
||||
vmState.blockHeader = header
|
||||
vmState.touchedAccounts.clear()
|
||||
@ -141,7 +122,7 @@ method difficulty*(vmState: BaseVMState): UInt256 {.base, gcsafe.} =
|
||||
method gasLimit*(vmState: BaseVMState): GasInt {.base, gcsafe.} =
|
||||
vmState.blockHeader.gasLimit
|
||||
|
||||
method baseFee*(vmState: BaseVMState): Uint256 {.base, gcsafe.} =
|
||||
method baseFee*(vmState: BaseVMState): UInt256 {.base, gcsafe.} =
|
||||
vmState.blockHeader.baseFee
|
||||
|
||||
when defined(geth):
|
||||
|
@ -9,12 +9,31 @@
|
||||
# according to those terms.
|
||||
|
||||
import
|
||||
macros, strformat, tables, sets, options,
|
||||
eth/[common, keys, rlp], nimcrypto/keccak,
|
||||
../errors, ../forks,
|
||||
../constants, ../db/[db_chain, accounts_cache],
|
||||
../utils, json, ./transaction_tracer, ./types,
|
||||
../config, ../../stateless/[witness_from_tree, witness_types]
|
||||
std/[json, macros, options, sets, strformat, tables],
|
||||
../../stateless/[witness_from_tree, witness_types],
|
||||
../config,
|
||||
../constants,
|
||||
../db/[db_chain, accounts_cache],
|
||||
../errors,
|
||||
../forks,
|
||||
../utils,
|
||||
../utils/ec_recover,
|
||||
./transaction_tracer,
|
||||
./types,
|
||||
eth/[common, keys]
|
||||
|
||||
|
||||
proc getMinerAddress(vmState: BaseVMState): EthAddress =
|
||||
if not vmState.consensusEnginePoA:
|
||||
return vmState.blockHeader.coinbase
|
||||
|
||||
let account = vmState.blockHeader.ecRecover
|
||||
if account.isErr:
|
||||
let msg = "Could not recover account address: " & $account.error
|
||||
raise newException(ValidationError, msg)
|
||||
|
||||
account.value
|
||||
|
||||
|
||||
proc newAccessLogs*: AccessLogs =
|
||||
AccessLogs(reads: initTable[string, string](), writes: initTable[string, string]())
|
||||
@ -29,8 +48,6 @@ proc `$`*(vmState: BaseVMState): string =
|
||||
else:
|
||||
result = &"VMState {vmState.name}:\n header: {vmState.blockHeader}\n chaindb: {vmState.chaindb}"
|
||||
|
||||
proc getMinerAddress(vmState: BaseVMState): EthAddress
|
||||
|
||||
proc init*(self: BaseVMState, prevStateRoot: Hash256, header: BlockHeader,
|
||||
chainDB: BaseChainDB, tracerFlags: set[TracerFlags] = {}) =
|
||||
self.prevHeaders = @[]
|
||||
@ -62,43 +79,6 @@ proc consensusEnginePoA*(vmState: BaseVMState): bool =
|
||||
# using `real` engine configuration
|
||||
vmState.chainDB.config.poaEngine
|
||||
|
||||
proc getSignature(bytes: openArray[byte], output: var Signature): bool =
|
||||
let sig = Signature.fromRaw(bytes)
|
||||
if sig.isOk:
|
||||
output = sig[]
|
||||
return true
|
||||
return false
|
||||
|
||||
proc headerHashOriExtraData(vmState: BaseVMState): Hash256 =
|
||||
var tmp = vmState.blockHeader
|
||||
tmp.extraData.setLen(tmp.extraData.len-65)
|
||||
result = keccak256.digest(rlp.encode(tmp))
|
||||
|
||||
proc calcMinerAddress(sigRaw: openArray[byte], vmState: BaseVMState, output: var EthAddress): bool =
|
||||
var sig: Signature
|
||||
if sigRaw.getSignature(sig):
|
||||
let headerHash = headerHashOriExtraData(vmState)
|
||||
let pubkey = recover(sig, SKMessage(headerHash.data))
|
||||
if pubkey.isOk:
|
||||
output = pubkey[].toCanonicalAddress()
|
||||
result = true
|
||||
|
||||
proc getMinerAddress(vmState: BaseVMState): EthAddress =
|
||||
if not vmState.consensusEnginePoA:
|
||||
return vmState.blockHeader.coinbase
|
||||
|
||||
template data: untyped =
|
||||
vmState.blockHeader.extraData
|
||||
|
||||
let len = data.len
|
||||
doAssert(len >= 65)
|
||||
|
||||
var miner: EthAddress
|
||||
if calcMinerAddress(data.toOpenArray(len - 65, len-1), vmState, miner):
|
||||
result = miner
|
||||
else:
|
||||
raise newException(ValidationError, "Could not derive miner address from header extradata")
|
||||
|
||||
proc updateBlockHeader*(vmState: BaseVMState, header: BlockHeader) =
|
||||
vmState.blockHeader = header
|
||||
vmState.touchedAccounts.clear()
|
||||
|
@ -246,11 +246,11 @@ when isMainModule:
|
||||
# `test_clique/indiump.dumpGroupNl()`
|
||||
# placed at the end of
|
||||
# `p2p/chain/persist_blocks.persistBlocks()`.
|
||||
captureFile = "test_clique" / "goerli504192.txt.gz"
|
||||
#captureFile = "test_clique" / "dump-stream.out.gz"
|
||||
captureFile = "goerli504192.txt.gz"
|
||||
#captureFile = "dump-stream.out.gz"
|
||||
|
||||
proc goerliReplay(noisy = true; showElapsed = true;
|
||||
dir = "."; captureFile = captureFile;
|
||||
dir = "/status"; captureFile = captureFile;
|
||||
startAtBlock = 0u64; stopAfterBlock = 0u64) =
|
||||
runGoerliReplay(
|
||||
noisy = noisy, showElapsed = showElapsed,
|
||||
|
@ -386,8 +386,8 @@ proc commitVoterChain*(ap: TesterPool; postProcessOk = false;
|
||||
## If `postProcessOk` is set, an additional verification step is added at
|
||||
## the end of each transaction.
|
||||
##
|
||||
## if `stopFaultyHeader` is set, the function stopps immediately on error.
|
||||
## Otherwise the offending bloch is removed, the rest of the batch is
|
||||
## if `stopFaultyHeader` is set, the function stops immediately on error.
|
||||
## Otherwise the offending block is removed, the rest of the batch is
|
||||
## adjusted and applied again repeatedly.
|
||||
result = ap
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user