bubble up validate transaction error message
This commit is contained in:
parent
8700d8b1e1
commit
10aabd8ca1
|
@ -11,6 +11,7 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
|
std/strutils,
|
||||||
../../common/common,
|
../../common/common,
|
||||||
../../db/accounts_cache,
|
../../db/accounts_cache,
|
||||||
../../transaction/call_evm,
|
../../transaction/call_evm,
|
||||||
|
@ -19,7 +20,6 @@ import
|
||||||
../../vm_types,
|
../../vm_types,
|
||||||
../../evm/async/operations,
|
../../evm/async/operations,
|
||||||
../validate,
|
../validate,
|
||||||
chronicles,
|
|
||||||
chronos,
|
chronos,
|
||||||
stew/results
|
stew/results
|
||||||
|
|
||||||
|
@ -38,18 +38,18 @@ proc commitOrRollbackDependingOnGasUsed(
|
||||||
vmState: BaseVMState, accTx: SavePoint,
|
vmState: BaseVMState, accTx: SavePoint,
|
||||||
header: BlockHeader, tx: Transaction,
|
header: BlockHeader, tx: Transaction,
|
||||||
gasBurned: GasInt, priorityFee: GasInt):
|
gasBurned: GasInt, priorityFee: GasInt):
|
||||||
Result[GasInt, void] {.raises: [].} =
|
Result[GasInt, string] {.raises: [].} =
|
||||||
# Make sure that the tx does not exceed the maximum cumulative limit as
|
# Make sure that the tx does not exceed the maximum cumulative limit as
|
||||||
# set in the block header. Again, the eip-1559 reference does not mention
|
# set in the block header. Again, the eip-1559 reference does not mention
|
||||||
# an early stop. It would rather detect differing values for the block
|
# an early stop. It would rather detect differing values for the block
|
||||||
# header `gasUsed` and the `vmState.cumulativeGasUsed` at a later stage.
|
# header `gasUsed` and the `vmState.cumulativeGasUsed` at a later stage.
|
||||||
if header.gasLimit < vmState.cumulativeGasUsed + gasBurned:
|
if header.gasLimit < vmState.cumulativeGasUsed + gasBurned:
|
||||||
vmState.stateDB.rollback(accTx)
|
try:
|
||||||
debug "invalid tx: block header gasLimit reached",
|
vmState.stateDB.rollback(accTx)
|
||||||
maxLimit = header.gasLimit,
|
return err("invalid tx: block header gasLimit reached. gasLimit=$1, gasUsed=$2, addition=$3" % [
|
||||||
gasUsed = vmState.cumulativeGasUsed,
|
$header.gasLimit, $vmState.cumulativeGasUsed, $gasBurned])
|
||||||
addition = gasBurned
|
except ValueError as ex:
|
||||||
return err()
|
return err(ex.msg)
|
||||||
else:
|
else:
|
||||||
# Accept transaction and collect mining fee.
|
# Accept transaction and collect mining fee.
|
||||||
vmState.stateDB.commit(accTx)
|
vmState.stateDB.commit(accTx)
|
||||||
|
@ -66,15 +66,12 @@ proc asyncProcessTransactionImpl(
|
||||||
tx: Transaction; ## Transaction to validate
|
tx: Transaction; ## Transaction to validate
|
||||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||||
header: BlockHeader; ## Header for the block containing the current tx
|
header: BlockHeader; ## Header for the block containing the current tx
|
||||||
fork: EVMFork): Future[Result[GasInt,void]]
|
fork: EVMFork): Future[Result[GasInt, string]]
|
||||||
# wildcard exception, wrapped below
|
# wildcard exception, wrapped below
|
||||||
{.async, gcsafe.} =
|
{.async, gcsafe.} =
|
||||||
## Modelled after `https://eips.ethereum.org/EIPS/eip-1559#specification`_
|
## Modelled after `https://eips.ethereum.org/EIPS/eip-1559#specification`_
|
||||||
## which provides a backward compatible framwork for EIP1559.
|
## which provides a backward compatible framwork for EIP1559.
|
||||||
|
|
||||||
#trace "Sender", sender
|
|
||||||
#trace "txHash", rlpHash = ty.rlpHash
|
|
||||||
|
|
||||||
let
|
let
|
||||||
roDB = vmState.readOnlyStateDB
|
roDB = vmState.readOnlyStateDB
|
||||||
baseFee256 = header.eip1559BaseFee(fork)
|
baseFee256 = header.eip1559BaseFee(fork)
|
||||||
|
@ -83,7 +80,7 @@ proc asyncProcessTransactionImpl(
|
||||||
priorityFee = min(tx.maxPriorityFee, tx.maxFee - baseFee)
|
priorityFee = min(tx.maxPriorityFee, tx.maxFee - baseFee)
|
||||||
|
|
||||||
# Return failure unless explicitely set `ok()`
|
# Return failure unless explicitely set `ok()`
|
||||||
var res: Result[GasInt,void] = err()
|
var res: Result[GasInt, string] = err("")
|
||||||
|
|
||||||
await ifNecessaryGetAccounts(vmState, @[sender, vmState.coinbase()])
|
await ifNecessaryGetAccounts(vmState, @[sender, vmState.coinbase()])
|
||||||
if tx.to.isSome:
|
if tx.to.isSome:
|
||||||
|
@ -91,10 +88,9 @@ proc asyncProcessTransactionImpl(
|
||||||
|
|
||||||
# buy gas, then the gas goes into gasMeter
|
# buy gas, then the gas goes into gasMeter
|
||||||
if vmState.gasPool < tx.gasLimit:
|
if vmState.gasPool < tx.gasLimit:
|
||||||
debug "gas limit reached",
|
return err("gas limit reached. gasLimit=$1, gasNeeded=$2" % [
|
||||||
gasLimit = vmState.gasPool,
|
$vmState.gasPool, $tx.gasLimit])
|
||||||
gasNeeded = tx.gasLimit
|
|
||||||
return
|
|
||||||
vmState.gasPool -= tx.gasLimit
|
vmState.gasPool -= tx.gasLimit
|
||||||
|
|
||||||
# Actually, the eip-1559 reference does not mention an early exit.
|
# Actually, the eip-1559 reference does not mention an early exit.
|
||||||
|
@ -103,7 +99,8 @@ proc asyncProcessTransactionImpl(
|
||||||
# before leaving is crucial for some unit tests that us a direct/deep call
|
# before leaving is crucial for some unit tests that us a direct/deep call
|
||||||
# of the `processTransaction()` function. So there is no `return err()`
|
# of the `processTransaction()` function. So there is no `return err()`
|
||||||
# statement, here.
|
# statement, here.
|
||||||
if roDB.validateTransaction(tx, sender, header.gasLimit, baseFee256, fork):
|
let txRes = roDB.validateTransaction(tx, sender, header.gasLimit, baseFee256, fork)
|
||||||
|
if txRes.isOk:
|
||||||
|
|
||||||
# Execute the transaction.
|
# Execute the transaction.
|
||||||
let
|
let
|
||||||
|
@ -111,6 +108,8 @@ proc asyncProcessTransactionImpl(
|
||||||
gasBurned = tx.txCallEvm(sender, vmState, fork)
|
gasBurned = tx.txCallEvm(sender, vmState, fork)
|
||||||
|
|
||||||
res = commitOrRollbackDependingOnGasUsed(vmState, accTx, header, tx, gasBurned, priorityFee)
|
res = commitOrRollbackDependingOnGasUsed(vmState, accTx, header, tx, gasBurned, priorityFee)
|
||||||
|
else:
|
||||||
|
res = err(txRes.error)
|
||||||
|
|
||||||
if vmState.generateWitness:
|
if vmState.generateWitness:
|
||||||
vmState.stateDB.collectWitnessData()
|
vmState.stateDB.collectWitnessData()
|
||||||
|
@ -129,7 +128,7 @@ proc asyncProcessTransaction*(
|
||||||
tx: Transaction; ## Transaction to validate
|
tx: Transaction; ## Transaction to validate
|
||||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||||
header: BlockHeader; ## Header for the block containing the current tx
|
header: BlockHeader; ## Header for the block containing the current tx
|
||||||
fork: EVMFork): Future[Result[GasInt,void]]
|
fork: EVMFork): Future[Result[GasInt,string]]
|
||||||
{.async, gcsafe.} =
|
{.async, gcsafe.} =
|
||||||
## Process the transaction, write the results to accounts db. The function
|
## Process the transaction, write the results to accounts db. The function
|
||||||
## returns the amount of gas burned if executed.
|
## returns the amount of gas burned if executed.
|
||||||
|
@ -140,7 +139,7 @@ proc asyncProcessTransaction*(
|
||||||
vmState: BaseVMState; ## Parent accounts environment for transaction
|
vmState: BaseVMState; ## Parent accounts environment for transaction
|
||||||
tx: Transaction; ## Transaction to validate
|
tx: Transaction; ## Transaction to validate
|
||||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||||
header: BlockHeader): Future[Result[GasInt,void]]
|
header: BlockHeader): Future[Result[GasInt,string]]
|
||||||
{.async, gcsafe.} =
|
{.async, gcsafe.} =
|
||||||
## Variant of `asyncProcessTransaction()` with `*fork* derived
|
## Variant of `asyncProcessTransaction()` with `*fork* derived
|
||||||
## from the `vmState` argument.
|
## from the `vmState` argument.
|
||||||
|
@ -152,7 +151,7 @@ proc processTransaction*(
|
||||||
tx: Transaction; ## Transaction to validate
|
tx: Transaction; ## Transaction to validate
|
||||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||||
header: BlockHeader; ## Header for the block containing the current tx
|
header: BlockHeader; ## Header for the block containing the current tx
|
||||||
fork: EVMFork): Result[GasInt,void]
|
fork: EVMFork): Result[GasInt,string]
|
||||||
{.gcsafe, raises: [CatchableError].} =
|
{.gcsafe, raises: [CatchableError].} =
|
||||||
return waitFor(vmState.asyncProcessTransaction(tx, sender, header, fork))
|
return waitFor(vmState.asyncProcessTransaction(tx, sender, header, fork))
|
||||||
|
|
||||||
|
@ -160,7 +159,7 @@ proc processTransaction*(
|
||||||
vmState: BaseVMState; ## Parent accounts environment for transaction
|
vmState: BaseVMState; ## Parent accounts environment for transaction
|
||||||
tx: Transaction; ## Transaction to validate
|
tx: Transaction; ## Transaction to validate
|
||||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||||
header: BlockHeader): Result[GasInt,void]
|
header: BlockHeader): Result[GasInt,string]
|
||||||
{.gcsafe, raises: [CatchableError].} =
|
{.gcsafe, raises: [CatchableError].} =
|
||||||
return waitFor(vmState.asyncProcessTransaction(tx, sender, header))
|
return waitFor(vmState.asyncProcessTransaction(tx, sender, header))
|
||||||
|
|
||||||
|
|
|
@ -234,7 +234,7 @@ proc classifyValidatePacked*(xp: TxPoolRef;
|
||||||
xp.chain.limits.trgLimit
|
xp.chain.limits.trgLimit
|
||||||
tx = item.tx.eip1559TxNormalization(xp.chain.baseFee.GasInt, fork)
|
tx = item.tx.eip1559TxNormalization(xp.chain.baseFee.GasInt, fork)
|
||||||
|
|
||||||
roDB.validateTransaction(tx, item.sender, gasLimit, baseFee, fork)
|
roDB.validateTransaction(tx, item.sender, gasLimit, baseFee, fork).isOk
|
||||||
|
|
||||||
proc classifyPacked*(xp: TxPoolRef; gasBurned, moreBurned: GasInt): bool =
|
proc classifyPacked*(xp: TxPoolRef; gasBurned, moreBurned: GasInt): bool =
|
||||||
## Classifier for *packing* (i.e. adding up `gasUsed` values after executing
|
## Classifier for *packing* (i.e. adding up `gasUsed` values after executing
|
||||||
|
|
|
@ -9,21 +9,16 @@
|
||||||
# according to those terms.
|
# according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[sequtils, sets, times],
|
std/[sequtils, sets, times, strutils],
|
||||||
../common/common,
|
../common/common,
|
||||||
../db/accounts_cache,
|
../db/accounts_cache,
|
||||||
".."/[errors, transaction, vm_state, vm_types],
|
".."/[errors, transaction, vm_state, vm_types],
|
||||||
"."/[dao, eip4844, gaslimit, withdrawals],
|
"."/[dao, eip4844, gaslimit, withdrawals],
|
||||||
./pow/[difficulty, header],
|
./pow/[difficulty, header],
|
||||||
./pow,
|
./pow,
|
||||||
chronicles,
|
nimcrypto/utils,
|
||||||
stew/[objects, results]
|
stew/[objects, results]
|
||||||
|
|
||||||
# chronicles stuff
|
|
||||||
when loggingEnabled or enabledLogLevel > NONE:
|
|
||||||
import
|
|
||||||
nimcrypto/utils
|
|
||||||
|
|
||||||
from stew/byteutils
|
from stew/byteutils
|
||||||
import nil
|
import nil
|
||||||
|
|
||||||
|
@ -51,31 +46,28 @@ func isGenesis(header: BlockHeader): bool =
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc validateSeal(pow: PowRef; header: BlockHeader): Result[void,string] =
|
proc validateSeal(pow: PowRef; header: BlockHeader): Result[void,string] =
|
||||||
let (expMixDigest, miningValue) = try:
|
try:
|
||||||
pow.getPowDigest(header)
|
let (expMixDigest, miningValue) = pow.getPowDigest(header)
|
||||||
|
|
||||||
|
if expMixDigest != header.mixDigest:
|
||||||
|
let
|
||||||
|
miningHash = header.getPowSpecs.miningHash
|
||||||
|
(size, cachedHash) = try: pow.getPowCacheLookup(header.blockNumber)
|
||||||
|
except KeyError: return err("Unknown block")
|
||||||
|
except CatchableError as e: return err(e.msg)
|
||||||
|
return err("mixHash mismatch. actual=$1, expected=$2," &
|
||||||
|
" blockNumber=$3, miningHash=$4, nonce=$5, difficulty=$6," &
|
||||||
|
" size=$7, cachedHash=$8" % [
|
||||||
|
$header.mixDigest, $expMixDigest, $header.blockNumber,
|
||||||
|
$miningHash, header.nonce.toHex, $header.difficulty,
|
||||||
|
$size, $cachedHash])
|
||||||
|
|
||||||
|
let value = UInt256.fromBytesBE(miningValue.data)
|
||||||
|
if value > UInt256.high div header.difficulty:
|
||||||
|
return err("mining difficulty error")
|
||||||
|
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
return err("test")
|
return err(err.msg)
|
||||||
|
|
||||||
if expMixDigest != header.mixDigest:
|
|
||||||
let
|
|
||||||
miningHash = header.getPowSpecs.miningHash
|
|
||||||
(size, cachedHash) = try: pow.getPowCacheLookup(header.blockNumber)
|
|
||||||
except KeyError: return err("Unknown block")
|
|
||||||
except CatchableError as e: return err(e.msg)
|
|
||||||
debug "mixHash mismatch",
|
|
||||||
actual = header.mixDigest,
|
|
||||||
expected = expMixDigest,
|
|
||||||
blockNumber = header.blockNumber,
|
|
||||||
miningHash = miningHash,
|
|
||||||
nonce = header.nonce.toHex,
|
|
||||||
difficulty = header.difficulty,
|
|
||||||
size = size,
|
|
||||||
cachedHash = cachedHash
|
|
||||||
return err("mixHash mismatch")
|
|
||||||
|
|
||||||
let value = UInt256.fromBytesBE(miningValue.data)
|
|
||||||
if value > UInt256.high div header.difficulty:
|
|
||||||
return err("mining difficulty error")
|
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
|
@ -249,22 +241,19 @@ proc validateTransaction*(
|
||||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||||
maxLimit: GasInt; ## gasLimit from block header
|
maxLimit: GasInt; ## gasLimit from block header
|
||||||
baseFee: UInt256; ## baseFee from block header
|
baseFee: UInt256; ## baseFee from block header
|
||||||
fork: EVMFork): bool =
|
fork: EVMFork): Result[void, string] =
|
||||||
let
|
let
|
||||||
balance = roDB.getBalance(sender)
|
balance = roDB.getBalance(sender)
|
||||||
nonce = roDB.getNonce(sender)
|
nonce = roDB.getNonce(sender)
|
||||||
|
|
||||||
if tx.txType == TxEip2930 and fork < FkBerlin:
|
if tx.txType == TxEip2930 and fork < FkBerlin:
|
||||||
debug "invalid tx: Eip2930 Tx type detected before Berlin"
|
return err("invalid tx: Eip2930 Tx type detected before Berlin")
|
||||||
return false
|
|
||||||
|
|
||||||
if tx.txType == TxEip1559 and fork < FkLondon:
|
if tx.txType == TxEip1559 and fork < FkLondon:
|
||||||
debug "invalid tx: Eip1559 Tx type detected before London"
|
return err("invalid tx: Eip1559 Tx type detected before London")
|
||||||
return false
|
|
||||||
|
|
||||||
if fork >= FkShanghai and tx.contractCreation and tx.payload.len > EIP3860_MAX_INITCODE_SIZE:
|
if fork >= FkShanghai and tx.contractCreation and tx.payload.len > EIP3860_MAX_INITCODE_SIZE:
|
||||||
debug "invalid tx: initcode size exceeds maximum"
|
return err("invalid tx: initcode size exceeds maximum")
|
||||||
return false
|
|
||||||
|
|
||||||
# Note that the following check bears some plausibility but is _not_
|
# Note that the following check bears some plausibility but is _not_
|
||||||
# covered by the eip-1559 reference (sort of) pseudo code, for details
|
# covered by the eip-1559 reference (sort of) pseudo code, for details
|
||||||
|
@ -281,81 +270,66 @@ proc validateTransaction*(
|
||||||
#
|
#
|
||||||
# The parallel lowGasLimit.json test never triggers the case checked below
|
# The parallel lowGasLimit.json test never triggers the case checked below
|
||||||
# as the paricular transaction is omitted (the txs list is just set empty.)
|
# as the paricular transaction is omitted (the txs list is just set empty.)
|
||||||
if maxLimit < tx.gasLimit:
|
try:
|
||||||
debug "invalid tx: block header gasLimit exceeded",
|
if maxLimit < tx.gasLimit:
|
||||||
maxLimit,
|
return err("invalid tx: block header gasLimit exceeded. maxLimit=$1, gasLimit=$2" % [
|
||||||
gasLimit = tx.gasLimit
|
$maxLimit, $tx.gasLimit])
|
||||||
return false
|
|
||||||
|
|
||||||
# ensure that the user was willing to at least pay the base fee
|
# ensure that the user was willing to at least pay the base fee
|
||||||
if tx.maxFee < baseFee.truncate(int64):
|
if tx.maxFee < baseFee.truncate(int64):
|
||||||
debug "invalid tx: maxFee is smaller than baseFee",
|
return err("invalid tx: maxFee is smaller than baseFee. maxFee=$1, baseFee=$2" % [
|
||||||
maxFee = tx.maxFee,
|
$tx.maxFee, $baseFee])
|
||||||
baseFee
|
|
||||||
return false
|
|
||||||
|
|
||||||
# The total must be the larger of the two
|
# The total must be the larger of the two
|
||||||
if tx.maxFee < tx.maxPriorityFee:
|
if tx.maxFee < tx.maxPriorityFee:
|
||||||
debug "invalid tx: maxFee is smaller than maPriorityFee",
|
return err("invalid tx: maxFee is smaller than maPriorityFee. maxFee=$1, maxPriorityFee=$2" % [
|
||||||
maxFee = tx.maxFee,
|
$tx.maxFee, $tx.maxPriorityFee])
|
||||||
maxPriorityFee = tx.maxPriorityFee
|
|
||||||
return false
|
|
||||||
|
|
||||||
# the signer must be able to fully afford the transaction
|
# the signer must be able to fully afford the transaction
|
||||||
let gasCost = if tx.txType >= TxEip1559:
|
let gasCost = if tx.txType >= TxEip1559:
|
||||||
tx.gasLimit.u256 * tx.maxFee.u256
|
tx.gasLimit.u256 * tx.maxFee.u256
|
||||||
else:
|
else:
|
||||||
tx.gasLimit.u256 * tx.gasPrice.u256
|
tx.gasLimit.u256 * tx.gasPrice.u256
|
||||||
|
|
||||||
if balance < gasCost:
|
if balance < gasCost:
|
||||||
debug "invalid tx: not enough cash for gas",
|
return err("invalid tx: not enough cash for gas. avail=$1, require=$2" % [
|
||||||
available = balance,
|
$balance, $gasCost])
|
||||||
require = gasCost
|
|
||||||
return false
|
|
||||||
|
|
||||||
if balance - gasCost < tx.value:
|
if balance - gasCost < tx.value:
|
||||||
debug "invalid tx: not enough cash to send",
|
return err("invalid tx: not enough cash to send. avail=$1, availMinusGas=$2, require=$3" % [
|
||||||
available=balance,
|
$balance, $(balance-gasCost), $tx.value])
|
||||||
availableMinusGas=balance-gasCost,
|
|
||||||
require=tx.value
|
|
||||||
return false
|
|
||||||
|
|
||||||
if tx.gasLimit < tx.intrinsicGas(fork):
|
if tx.gasLimit < tx.intrinsicGas(fork):
|
||||||
debug "invalid tx: not enough gas to perform calculation",
|
return err("invalid tx: not enough gas to perform calculation. avail=$1, require=$2" % [
|
||||||
available=tx.gasLimit,
|
$tx.gasLimit, $tx.intrinsicGas(fork)])
|
||||||
require=tx.intrinsicGas(fork)
|
|
||||||
return false
|
|
||||||
|
|
||||||
if tx.nonce != nonce:
|
if tx.nonce != nonce:
|
||||||
debug "invalid tx: account nonce mismatch",
|
return err("invalid tx: account nonce mismatch. txNonce=$1, accNonce=$2" % [
|
||||||
txNonce=tx.nonce,
|
$tx.nonce, $nonce])
|
||||||
accountNonce=nonce
|
|
||||||
return false
|
|
||||||
|
|
||||||
if tx.nonce == high(uint64):
|
if tx.nonce == high(uint64):
|
||||||
debug "invalid tx: nonce at maximum"
|
return err("invalid tx: nonce at maximum")
|
||||||
return false
|
|
||||||
|
|
||||||
# EIP-3607 Reject transactions from senders with deployed code
|
# EIP-3607 Reject transactions from senders with deployed code
|
||||||
# The EIP spec claims this attack never happened before
|
# The EIP spec claims this attack never happened before
|
||||||
# Clients might choose to disable this rule for RPC calls like
|
# Clients might choose to disable this rule for RPC calls like
|
||||||
# `eth_call` and `eth_estimateGas`
|
# `eth_call` and `eth_estimateGas`
|
||||||
# EOA = Externally Owned Account
|
# EOA = Externally Owned Account
|
||||||
let codeHash = roDB.getCodeHash(sender)
|
let codeHash = roDB.getCodeHash(sender)
|
||||||
if codeHash != EMPTY_SHA3:
|
if codeHash != EMPTY_SHA3:
|
||||||
debug "invalid tx: sender is not an EOA",
|
return err("invalid tx: sender is not an EOA. sender=$1, codeHash=$2" % [
|
||||||
sender=sender.toHex,
|
sender.toHex, codeHash.data.toHex])
|
||||||
codeHash=codeHash.data.toHex
|
except CatchableError as ex:
|
||||||
return false
|
return err(ex.msg)
|
||||||
|
|
||||||
true
|
ok()
|
||||||
|
|
||||||
proc validateTransaction*(
|
proc validateTransaction*(
|
||||||
vmState: BaseVMState; ## Parent accounts environment for transaction
|
vmState: BaseVMState; ## Parent accounts environment for transaction
|
||||||
tx: Transaction; ## tx to validate
|
tx: Transaction; ## tx to validate
|
||||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||||
header: BlockHeader; ## Header for the block containing the current tx
|
header: BlockHeader; ## Header for the block containing the current tx
|
||||||
fork: EVMFork): bool =
|
fork: EVMFork): Result[void, string] =
|
||||||
## Variant of `validateTransaction()`
|
## Variant of `validateTransaction()`
|
||||||
let
|
let
|
||||||
roDB = vmState.readOnlyStateDB
|
roDB = vmState.readOnlyStateDB
|
||||||
|
|
|
@ -228,7 +228,7 @@ proc exec(ctx: var TransContext,
|
||||||
if rc.isErr:
|
if rc.isErr:
|
||||||
rejected.add RejectedTx(
|
rejected.add RejectedTx(
|
||||||
index: txIndex,
|
index: txIndex,
|
||||||
error: "processTransaction failed"
|
error: rc.error
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue