mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 13:24:21 +00:00
Use eth/common transaction signature utilities (#2696)
* Use eth/common transaction signature utilities * bump * bump * bump * bump * bump * bump
This commit is contained in:
parent
c42ae8a037
commit
08ffb3161c
@ -14,14 +14,14 @@ import
|
||||
web3/conversions, # sigh, for FixedBytes marshalling
|
||||
web3/eth_api_types,
|
||||
web3/primitives as web3types,
|
||||
eth/common/eth_types,
|
||||
eth/common/[eth_types, transaction_utils],
|
||||
beacon_chain/spec/forks,
|
||||
../network/history/[history_network, history_content],
|
||||
../network/state/[state_network, state_content, state_endpoints],
|
||||
../network/beacon/beacon_light_client,
|
||||
../version
|
||||
|
||||
from ../../nimbus/transaction import getSender, ValidationError
|
||||
from ../../nimbus/errors import ValidationError
|
||||
from ../../nimbus/rpc/filters import headerBloomFilter, deriveLogs, filterLogs
|
||||
from ../../nimbus/beacon/web3_eth_conv import w3Addr, w3Hash, ethHash
|
||||
|
||||
@ -42,10 +42,13 @@ func init*(
|
||||
header: eth_types.BlockHeader,
|
||||
txIndex: int,
|
||||
): T {.raises: [ValidationError].} =
|
||||
let sender = tx.recoverSender().valueOr:
|
||||
raise (ref ValidationError)(msg: "Invalid tx signature")
|
||||
|
||||
TransactionObject(
|
||||
blockHash: Opt.some(w3Hash header.blockHash),
|
||||
blockNumber: Opt.some(eth_api_types.BlockNumber(header.number)),
|
||||
`from`: w3Addr tx.getSender(),
|
||||
`from`: sender,
|
||||
gas: Quantity(tx.gasLimit),
|
||||
gasPrice: Quantity(tx.gasPrice),
|
||||
hash: w3Hash tx.rlpHash,
|
||||
@ -107,7 +110,6 @@ func init*(
|
||||
if fullTx:
|
||||
var i = 0
|
||||
for tx in body.transactions:
|
||||
# ValidationError from tx.getSender in TransactionObject.init
|
||||
blockObject.transactions.add txOrHash(TransactionObject.init(tx, header, i))
|
||||
inc i
|
||||
else:
|
||||
|
@ -11,6 +11,7 @@
|
||||
import
|
||||
std/[tables],
|
||||
eth/keys,
|
||||
eth/common/transaction_utils,
|
||||
stew/endians2,
|
||||
nimcrypto/sha2,
|
||||
chronicles,
|
||||
@ -150,7 +151,8 @@ proc makeTxOfType(params: MakeTxParams, tc: BaseTx): PooledTransaction =
|
||||
value : tc.amount,
|
||||
gasLimit: tc.gasLimit,
|
||||
gasPrice: gasPrice,
|
||||
payload : tc.payload
|
||||
payload : tc.payload,
|
||||
chainId : params.chainId,
|
||||
)
|
||||
)
|
||||
of TxEip1559:
|
||||
@ -207,7 +209,7 @@ proc makeTx(params: MakeTxParams, tc: BaseTx): PooledTransaction =
|
||||
# Build the transaction depending on the specified type
|
||||
let tx = makeTxOfType(params, tc)
|
||||
PooledTransaction(
|
||||
tx: signTransaction(tx.tx, params.key, params.chainId, eip155 = true),
|
||||
tx: signTransaction(tx.tx, params.key),
|
||||
networkPayload: tx.networkPayload)
|
||||
|
||||
proc makeTx(params: MakeTxParams, tc: BigInitcodeTx): PooledTransaction =
|
||||
@ -337,7 +339,7 @@ proc makeTx*(params: MakeTxParams, tc: BlobTx): PooledTransaction =
|
||||
)
|
||||
|
||||
PooledTransaction(
|
||||
tx: signTransaction(unsignedTx, params.key, params.chainId, eip155 = true),
|
||||
tx: signTransaction(unsignedTx, params.key),
|
||||
networkPayload: NetworkPayload(
|
||||
blobs : data.blobs.mapIt(it.bytes),
|
||||
commitments: data.commitments.mapIt(it.bytes),
|
||||
@ -427,16 +429,10 @@ proc customizeTransaction*(sender: TxSender,
|
||||
if custTx.data.isSome:
|
||||
modTx.payload = custTx.data.get
|
||||
|
||||
if custTx.signature.isSome:
|
||||
let signature = custTx.signature.get
|
||||
modTx.V = signature.V
|
||||
modTx.R = signature.R
|
||||
modTx.S = signature.S
|
||||
if custTx.chainId.isSome:
|
||||
modTx.chainId = custTx.chainId.get
|
||||
|
||||
if baseTx.txType in {TxEip1559, TxEip4844}:
|
||||
if custTx.chainId.isSome:
|
||||
modTx.chainId = custTx.chainId.get
|
||||
|
||||
if custTx.gasPriceOrGasFeeCap.isSome:
|
||||
modTx.maxFeePErGas = custTx.gasPriceOrGasFeeCap.get.GasInt
|
||||
|
||||
@ -448,7 +444,12 @@ proc customizeTransaction*(sender: TxSender,
|
||||
var address: EthAddress
|
||||
modTx.to = Opt.some(address)
|
||||
|
||||
if custTx.signature.isNone:
|
||||
return signTransaction(modTx, acc.key, modTx.chainId, eip155 = true)
|
||||
if custTx.signature.isSome:
|
||||
let signature = custTx.signature.get
|
||||
modTx.V = signature.V
|
||||
modTx.R = signature.R
|
||||
modTx.S = signature.S
|
||||
else:
|
||||
modTx.signature = modTx.sign(acc.key, eip155 = true)
|
||||
|
||||
return modTx
|
||||
modTx
|
||||
|
@ -94,7 +94,7 @@ proc makeFundingTx*(
|
||||
)
|
||||
|
||||
PooledTransaction(
|
||||
tx: signTransaction(unsignedTx, v.vaultKey, v.chainId, eip155 = true))
|
||||
tx: signTransaction(unsignedTx, v.vaultKey))
|
||||
|
||||
proc signTx*(v: Vault,
|
||||
sender: EthAddress,
|
||||
@ -118,7 +118,7 @@ proc signTx*(v: Vault,
|
||||
|
||||
let key = v.accounts[sender]
|
||||
PooledTransaction(
|
||||
tx: signTransaction(unsignedTx, key, v.chainId, eip155 = true))
|
||||
tx: signTransaction(unsignedTx, key))
|
||||
|
||||
# createAccount creates a new account that is funded from the vault contract.
|
||||
# It will panic when the account could not be created and funded.
|
||||
|
@ -21,6 +21,7 @@ import
|
||||
./calculate_reward,
|
||||
./executor_helpers,
|
||||
./process_transaction,
|
||||
eth/common/transaction_utils,
|
||||
chronicles,
|
||||
results
|
||||
|
||||
@ -40,8 +41,7 @@ proc processTransactions*(
|
||||
vmState.allLogs = @[]
|
||||
|
||||
for txIndex, tx in transactions:
|
||||
var sender: EthAddress
|
||||
if not tx.getSender(sender):
|
||||
let sender = tx.recoverSender().valueOr:
|
||||
return err("Could not get sender for tx with index " & $(txIndex))
|
||||
let rc = vmState.processTransaction(tx, sender, header)
|
||||
if rc.isErr:
|
||||
|
@ -66,7 +66,7 @@ proc commitOrRollbackDependingOnGasUsed(
|
||||
proc processTransactionImpl(
|
||||
vmState: BaseVMState; ## Parent accounts environment for transaction
|
||||
tx: Transaction; ## Transaction to validate
|
||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||
sender: EthAddress; ## tx.recoverSender
|
||||
header: BlockHeader; ## Header for the block containing the current tx
|
||||
): Result[GasInt, string] =
|
||||
## Modelled after `https://eips.ethereum.org/EIPS/eip-1559#specification`_
|
||||
@ -267,7 +267,7 @@ proc processDequeueConsolidationRequests*(vmState: BaseVMState): seq[Request] =
|
||||
proc processTransaction*(
|
||||
vmState: BaseVMState; ## Parent accounts environment for transaction
|
||||
tx: Transaction; ## Transaction to validate
|
||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||
sender: EthAddress; ## tx.recoverSender
|
||||
header: BlockHeader; ## Header for the block containing the current tx
|
||||
): Result[GasInt,string] =
|
||||
vmState.processTransactionImpl(tx, sender, header)
|
||||
|
@ -18,7 +18,7 @@ import
|
||||
../../utils/utils,
|
||||
../../transaction,
|
||||
./tx_info,
|
||||
eth/[common, keys],
|
||||
eth/common/transaction_utils,
|
||||
results
|
||||
|
||||
{.push raises: [].}
|
||||
@ -62,7 +62,7 @@ proc init*(item: TxItemRef; status: TxItemStatus; info: string) =
|
||||
proc new*(T: type TxItemRef; tx: PooledTransaction; itemID: Hash256;
|
||||
status: TxItemStatus; info: string): Result[T,void] {.gcsafe,raises: [].} =
|
||||
## Create item descriptor.
|
||||
let rc = tx.tx.ecRecover
|
||||
let rc = tx.tx.recoverSender()
|
||||
if rc.isErr:
|
||||
return err()
|
||||
ok(T(itemID: itemID,
|
||||
|
@ -248,7 +248,7 @@ proc validateTxBasic*(
|
||||
proc validateTransaction*(
|
||||
roDB: ReadOnlyStateDB; ## Parent accounts environment for transaction
|
||||
tx: Transaction; ## tx to validate
|
||||
sender: EthAddress; ## tx.getSender or tx.ecRecover
|
||||
sender: EthAddress; ## tx.recoverSender
|
||||
maxLimit: GasInt; ## gasLimit from block header
|
||||
baseFee: UInt256; ## baseFee from block header
|
||||
excessBlobGas: uint64; ## excessBlobGas from parent block header
|
||||
|
@ -22,7 +22,8 @@ import
|
||||
../common/common,
|
||||
../transaction/call_evm,
|
||||
../core/[tx_pool, tx_pool/tx_item],
|
||||
../utils/utils
|
||||
../utils/utils,
|
||||
eth/common/transaction_utils
|
||||
|
||||
from eth/p2p import EthereumNode
|
||||
export httpserver
|
||||
@ -629,8 +630,7 @@ proc txFrom(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
|
||||
else:
|
||||
tx.blockNumber
|
||||
|
||||
var sender: EthAddress
|
||||
if not getSender(tx.tx, sender):
|
||||
let sender = tx.tx.recoverSender.valueOr:
|
||||
return ok(respNull())
|
||||
let hres = ctx.getBlockByNumber(blockNumber)
|
||||
if hres.isErr:
|
||||
@ -732,8 +732,7 @@ proc txCumulativeGasUsed(ud: RootRef, params: Args, parent: Node): RespResult {.
|
||||
proc txCreatedContract(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
|
||||
let ctx = GraphqlContextRef(ud)
|
||||
let tx = TxNode(parent)
|
||||
var sender: EthAddress
|
||||
if not getSender(tx.tx, sender):
|
||||
let sender = tx.tx.recoverSender.valueOr:
|
||||
return err("can't calculate sender")
|
||||
|
||||
if not tx.tx.contractCreation:
|
||||
|
@ -234,9 +234,9 @@ proc setupEthRpc*(
|
||||
|
||||
let
|
||||
accDB = stateDBFromTag(blockId("latest"))
|
||||
tx = unsignedTx(data, chainDB, accDB.getNonce(address) + 1)
|
||||
tx = unsignedTx(data, chainDB, accDB.getNonce(address) + 1, com.chainId)
|
||||
eip155 = com.isEIP155(com.syncCurrent)
|
||||
signedTx = signTransaction(tx, acc.privateKey, com.chainId, eip155)
|
||||
signedTx = signTransaction(tx, acc.privateKey, eip155)
|
||||
result = rlp.encode(signedTx)
|
||||
|
||||
server.rpc("eth_sendTransaction") do(data: TransactionArgs) -> Web3Hash:
|
||||
@ -254,9 +254,9 @@ proc setupEthRpc*(
|
||||
|
||||
let
|
||||
accDB = stateDBFromTag(blockId("latest"))
|
||||
tx = unsignedTx(data, chainDB, accDB.getNonce(address) + 1)
|
||||
tx = unsignedTx(data, chainDB, accDB.getNonce(address) + 1, com.chainId)
|
||||
eip155 = com.isEIP155(com.syncCurrent)
|
||||
signedTx = signTransaction(tx, acc.privateKey, com.chainId, eip155)
|
||||
signedTx = signTransaction(tx, acc.privateKey, eip155)
|
||||
networkPayload =
|
||||
if signedTx.txType == TxEip4844:
|
||||
if data.blobs.isNone or data.commitments.isNone or data.proofs.isNone:
|
||||
|
@ -26,7 +26,8 @@ import
|
||||
../evm/state,
|
||||
../evm/precompiles,
|
||||
../evm/tracer/access_list_tracer,
|
||||
../evm/evm_errors
|
||||
../evm/evm_errors,
|
||||
eth/common/transaction_utils
|
||||
|
||||
|
||||
const
|
||||
@ -91,7 +92,7 @@ proc calculateMedianGasPrice*(chain: CoreDbRef): GasInt
|
||||
const minGasPrice = 30_000_000_000.GasInt
|
||||
result = max(result, minGasPrice)
|
||||
|
||||
proc unsignedTx*(tx: TransactionArgs, chain: CoreDbRef, defaultNonce: AccountNonce): Transaction
|
||||
proc unsignedTx*(tx: TransactionArgs, chain: CoreDbRef, defaultNonce: AccountNonce, chainId: ChainId): Transaction
|
||||
{.gcsafe, raises: [CatchableError].} =
|
||||
if tx.to.isSome:
|
||||
result.to = Opt.some(ethAddr(tx.to.get))
|
||||
@ -117,6 +118,7 @@ proc unsignedTx*(tx: TransactionArgs, chain: CoreDbRef, defaultNonce: AccountNon
|
||||
result.nonce = defaultNonce
|
||||
|
||||
result.payload = tx.payload
|
||||
result.chainId = chainId
|
||||
|
||||
proc toWd(wd: Withdrawal): WithdrawalObject =
|
||||
WithdrawalObject(
|
||||
@ -142,7 +144,8 @@ proc populateTransactionObject*(tx: Transaction,
|
||||
result.blockHash = Opt.some(w3Hash header.blockHash)
|
||||
result.blockNumber = Opt.some(w3BlockNumber(header.number))
|
||||
|
||||
result.`from` = w3Addr tx.getSender()
|
||||
if (let sender = tx.recoverSender(); sender.isOk):
|
||||
result.`from` = sender[]
|
||||
result.gas = w3Qty(tx.gasLimit)
|
||||
result.gasPrice = w3Qty(tx.gasPrice)
|
||||
result.hash = w3Hash tx.rlpHash
|
||||
@ -221,24 +224,22 @@ proc populateBlockObject*(header: BlockHeader, chain: CoreDbRef, fullTx: bool, i
|
||||
result.parentBeaconBlockRoot = Opt.some(w3Hash header.parentBeaconBlockRoot.get)
|
||||
|
||||
proc populateReceipt*(receipt: Receipt, gasUsed: GasInt, tx: Transaction,
|
||||
txIndex: uint64, header: BlockHeader): ReceiptObject
|
||||
{.gcsafe, raises: [ValidationError].} =
|
||||
txIndex: uint64, header: BlockHeader): ReceiptObject =
|
||||
let sender = tx.recoverSender()
|
||||
result = ReceiptObject()
|
||||
result.transactionHash = w3Hash tx.rlpHash
|
||||
result.transactionIndex = w3Qty(txIndex)
|
||||
result.blockHash = w3Hash header.blockHash
|
||||
result.blockNumber = w3BlockNumber(header.number)
|
||||
result.`from` = w3Addr tx.getSender()
|
||||
if sender.isSome():
|
||||
result.`from` = sender.get()
|
||||
result.to = Opt.some(w3Addr tx.destination)
|
||||
result.cumulativeGasUsed = w3Qty(receipt.cumulativeGasUsed)
|
||||
result.gasUsed = w3Qty(gasUsed)
|
||||
result.`type` = Opt.some Quantity(receipt.receiptType)
|
||||
|
||||
if tx.contractCreation:
|
||||
var sender: EthAddress
|
||||
if tx.getSender(sender):
|
||||
let contractAddress = generateAddress(sender, tx.nonce)
|
||||
result.contractAddress = Opt.some(w3Addr contractAddress)
|
||||
if tx.contractCreation and sender.isSome:
|
||||
result.contractAddress = Opt.some(tx.creationAddress(sender[]))
|
||||
|
||||
for log in receipt.logs:
|
||||
# TODO: Work everywhere with either `Hash256` as topic or `array[32, byte]`
|
||||
|
@ -10,7 +10,7 @@
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
eth/common/eth_types,
|
||||
eth/common/[eth_types, transaction_utils],
|
||||
eth/common/eth_types_rlp,
|
||||
web3/eth_api_types,
|
||||
../beacon/web3_eth_conv,
|
||||
@ -44,9 +44,8 @@ proc populateTransactionObject*(tx: Transaction,
|
||||
result.blockHash = w3Hash optionalHash
|
||||
result.blockNumber = w3BlockNumber optionalNumber
|
||||
|
||||
var sender: EthAddress
|
||||
if tx.getSender(sender):
|
||||
result.`from` = w3Addr sender
|
||||
if (let sender = tx.recoverSender(); sender.isOk):
|
||||
result.`from` = sender[]
|
||||
result.gas = w3Qty(tx.gasLimit)
|
||||
result.gasPrice = w3Qty(tx.gasPrice)
|
||||
result.hash = w3Hash tx.rlpHash
|
||||
|
@ -15,6 +15,7 @@ import
|
||||
nimcrypto/utils as ncrutils,
|
||||
results,
|
||||
web3/conversions,
|
||||
eth/common/transaction_utils,
|
||||
./beacon/web3_eth_conv,
|
||||
./common/common,
|
||||
./constants,
|
||||
@ -187,7 +188,7 @@ proc traceTransactionImpl(
|
||||
miner = vmState.coinbase()
|
||||
|
||||
for idx, tx in transactions:
|
||||
let sender = tx.getSender
|
||||
let sender = tx.recoverSender().expect("valid signature")
|
||||
let recipient = tx.getRecipient(sender)
|
||||
|
||||
if idx.uint64 == txIndex:
|
||||
@ -263,7 +264,7 @@ proc dumpBlockStateImpl(
|
||||
stateBefore = LedgerRef.init(com.db, parent.stateRoot, storeSlotHash = true)
|
||||
|
||||
for idx, tx in blk.transactions:
|
||||
let sender = tx.getSender
|
||||
let sender = tx.recoverSender().expect("valid signature")
|
||||
let recipient = tx.getRecipient(sender)
|
||||
before.captureAccount(stateBefore, sender, senderName & $idx)
|
||||
before.captureAccount(stateBefore, recipient, recipientName & $idx)
|
||||
@ -278,7 +279,7 @@ proc dumpBlockStateImpl(
|
||||
var stateAfter = vmState.stateDB
|
||||
|
||||
for idx, tx in blk.transactions:
|
||||
let sender = tx.getSender
|
||||
let sender = tx.recoverSender().expect("valid signature")
|
||||
let recipient = tx.getRecipient(sender)
|
||||
after.captureAccount(stateAfter, sender, senderName & $idx)
|
||||
after.captureAccount(stateAfter, recipient, recipientName & $idx)
|
||||
@ -329,7 +330,7 @@ proc traceBlockImpl(
|
||||
|
||||
for tx in blk.transactions:
|
||||
let
|
||||
sender = tx.getSender
|
||||
sender = tx.recoverSender().expect("valid signature")
|
||||
rc = vmState.processTransaction(tx, sender, header)
|
||||
if rc.isOk:
|
||||
gasUsed = gasUsed + rc.value
|
||||
|
@ -6,11 +6,12 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
./constants, ./errors, eth/[common, keys], ./utils/utils,
|
||||
common/evmforks, ./evm/internals
|
||||
./[constants, errors],
|
||||
./common/evmforks,
|
||||
./evm/interpreter/gas_costs,
|
||||
eth/common/[addresses, keys, transactions, transactions_rlp, transaction_utils]
|
||||
|
||||
import eth/common/transaction as common_transaction
|
||||
export common_transaction, errors
|
||||
export addresses, keys, transactions
|
||||
|
||||
proc toWordSize(size: GasInt): GasInt =
|
||||
# Round input to the nearest bigger multiple of 32
|
||||
@ -48,54 +49,6 @@ proc intrinsicGas*(tx: Transaction, fork: EVMFork): GasInt =
|
||||
inc(numKeys, n.storageKeys.len)
|
||||
result += GasInt(numKeys) * ACCESS_LIST_STORAGE_KEY_COST
|
||||
|
||||
proc getSignature*(tx: Transaction, output: var Signature): bool =
|
||||
var bytes: array[65, byte]
|
||||
bytes[0..31] = tx.R.toBytesBE()
|
||||
bytes[32..63] = tx.S.toBytesBE()
|
||||
|
||||
if tx.txType == TxLegacy:
|
||||
var v = tx.V
|
||||
if v >= EIP155_CHAIN_ID_OFFSET:
|
||||
v = 28 - (v and 0x01)
|
||||
elif v == 27 or v == 28:
|
||||
discard
|
||||
else:
|
||||
return false
|
||||
bytes[64] = byte(v - 27)
|
||||
else:
|
||||
bytes[64] = tx.V.byte
|
||||
|
||||
let sig = Signature.fromRaw(bytes)
|
||||
if sig.isOk:
|
||||
output = sig[]
|
||||
return true
|
||||
return false
|
||||
|
||||
proc toSignature*(tx: Transaction): Signature =
|
||||
if not getSignature(tx, result):
|
||||
raise newException(Exception, "Invalid signature")
|
||||
|
||||
proc getSender*(tx: Transaction, output: var EthAddress): bool =
|
||||
## Find the address the transaction was sent from.
|
||||
var sig: Signature
|
||||
if tx.getSignature(sig):
|
||||
var txHash = tx.txHashNoSignature
|
||||
let pubkey = recover(sig, SkMessage(txHash.data))
|
||||
if pubkey.isOk:
|
||||
output = pubkey[].toCanonicalAddress()
|
||||
result = true
|
||||
|
||||
proc getSender*(tx: Transaction): EthAddress =
|
||||
## Raises error on failure to recover public key
|
||||
if not tx.getSender(result):
|
||||
raise newException(ValidationError, "Could not derive sender address from transaction")
|
||||
|
||||
proc getRecipient*(tx: Transaction, sender: EthAddress): EthAddress =
|
||||
if tx.contractCreation:
|
||||
result = generateAddress(sender, tx.nonce)
|
||||
else:
|
||||
result = tx.to.get()
|
||||
|
||||
proc validateTxLegacy(tx: Transaction, fork: EVMFork) =
|
||||
var
|
||||
vMin = 27'u64
|
||||
@ -155,6 +108,8 @@ proc validateTxEip7702(tx: Transaction) =
|
||||
raise newException(ValidationError, "Invalid EIP-7702 transaction")
|
||||
|
||||
proc validate*(tx: Transaction, fork: EVMFork) =
|
||||
# TODO it doesn't seem like this function is called from anywhere except tests
|
||||
# which feels like it might be a problem (?)
|
||||
# parameters pass validation rules
|
||||
if tx.intrinsicGas(fork) > tx.gasLimit:
|
||||
raise newException(ValidationError, "Insufficient gas")
|
||||
@ -163,8 +118,10 @@ proc validate*(tx: Transaction, fork: EVMFork) =
|
||||
raise newException(ValidationError, "Initcode size exceeds max")
|
||||
|
||||
# check signature validity
|
||||
var sender: EthAddress
|
||||
if not tx.getSender(sender):
|
||||
# TODO a validation function like this should probably be returning the sender
|
||||
# since recovering the public key accounts for ~10% of block processing
|
||||
# time (at the time of writing)
|
||||
let sender = tx.recoverSender().valueOr:
|
||||
raise newException(ValidationError, "Invalid signature or failed message verification")
|
||||
|
||||
case tx.txType
|
||||
@ -177,27 +134,9 @@ proc validate*(tx: Transaction, fork: EVMFork) =
|
||||
of TxEip7702:
|
||||
validateTxEip7702(tx)
|
||||
|
||||
proc signTransaction*(tx: Transaction, privateKey: PrivateKey, chainId: ChainId, eip155: bool): Transaction =
|
||||
proc signTransaction*(tx: Transaction, privateKey: PrivateKey, eip155 = true): Transaction =
|
||||
result = tx
|
||||
if eip155:
|
||||
# trigger rlpEncodeEIP155 in nim-eth
|
||||
result.V = chainId.uint64 * 2'u64 + 35'u64
|
||||
|
||||
let
|
||||
rlpTx = rlpEncode(result)
|
||||
sig = sign(privateKey, rlpTx).toRaw
|
||||
|
||||
case tx.txType
|
||||
of TxLegacy:
|
||||
if eip155:
|
||||
result.V = sig[64].uint64 + result.V
|
||||
else:
|
||||
result.V = sig[64].uint64 + 27'u64
|
||||
else:
|
||||
result.V = sig[64].uint64
|
||||
|
||||
result.R = UInt256.fromBytesBE(sig[0..31])
|
||||
result.S = UInt256.fromBytesBE(sig[32..63])
|
||||
result.signature = result.sign(privateKey, eip155)
|
||||
|
||||
# deriveChainId derives the chain id from the given v parameter
|
||||
func deriveChainId*(v: uint64, chainId: ChainId): ChainId =
|
||||
|
@ -51,23 +51,6 @@ type
|
||||
# Private helpers
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc vrsSerialised(tx: Transaction): Result[array[65,byte],UtilsError] =
|
||||
## Parts copied from `transaction.getSignature`.
|
||||
var data: array[65,byte]
|
||||
data[0..31] = tx.R.toBytesBE
|
||||
data[32..63] = tx.S.toBytesBE
|
||||
|
||||
if tx.txType != TxLegacy:
|
||||
data[64] = tx.V.byte
|
||||
elif tx.V >= EIP155_CHAIN_ID_OFFSET:
|
||||
data[64] = byte(1 - (tx.V and 1))
|
||||
elif tx.V == 27 or tx.V == 28:
|
||||
data[64] = byte(tx.V - 27)
|
||||
else:
|
||||
return err((errSigPrefixError,"")) # legacy error
|
||||
|
||||
ok(data)
|
||||
|
||||
proc encodePreSealed(header: BlockHeader): seq[byte] =
|
||||
## Cut sigature off `extraData` header field.
|
||||
if header.extraData.len < EXTRA_SEAL:
|
||||
@ -113,22 +96,6 @@ proc ecRecover*(header: BlockHeader): EcAddrResult =
|
||||
## the argument header.
|
||||
header.extraData.recoverImpl(header.hashPreSealed)
|
||||
|
||||
proc ecRecover*(tx: var Transaction): EcAddrResult =
|
||||
## Extracts sender address from transaction. This function has similar
|
||||
## functionality as `transaction.getSender()`.
|
||||
let txSig = tx.vrsSerialised
|
||||
if txSig.isErr:
|
||||
return err(txSig.error)
|
||||
try:
|
||||
result = txSig.value.recoverImpl(tx.txHashNoSignature)
|
||||
except ValueError as ex:
|
||||
return err((errTxEncError, ex.msg))
|
||||
|
||||
proc ecRecover*(tx: Transaction): EcAddrResult =
|
||||
## Variant of `ecRecover()` for call-by-value header.
|
||||
var ty = tx
|
||||
ty.ecRecover
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public constructor for caching ecRecover version
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -9,7 +9,7 @@
|
||||
# according to those terms.
|
||||
|
||||
import
|
||||
json, strutils, os,
|
||||
json, strutils, os, eth/common/transaction_utils,
|
||||
eth/common, httputils, nimcrypto/utils,
|
||||
stint, stew/byteutils
|
||||
|
||||
@ -196,7 +196,7 @@ proc parseWithdrawal*(n: JsonNode): Withdrawal =
|
||||
n.fromJson "amount", result.amount
|
||||
|
||||
proc validateTxSenderAndHash*(n: JsonNode, tx: Transaction) =
|
||||
var sender = tx.getSender()
|
||||
var sender = tx.recoverSender().expect("valid signature")
|
||||
var fromAddr: EthAddress
|
||||
n.fromJson "from", fromAddr
|
||||
doAssert sender.to0xHex == fromAddr.to0xHex
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
import
|
||||
json, strutils, os,
|
||||
chronicles, eth/common,
|
||||
chronicles, eth/common, eth/common/transaction_utils,
|
||||
../nimbus/transaction, ../nimbus/launcher,
|
||||
./js_tracer, ./parser, ./downloader
|
||||
|
||||
@ -157,7 +157,8 @@ proc requestPostState*(premix, n: JsonNode, blockNumber: BlockNumber) =
|
||||
for t in txs:
|
||||
var txKind = TxKind.Regular
|
||||
let tx = parseTransaction(t)
|
||||
let sender = tx.getSender
|
||||
let sender = tx.recoverSender().valueOr:
|
||||
raise (ref ValueError)(msg: "Invalid tx signature")
|
||||
if tx.contractCreation: txKind = TxKind.ContractCreation
|
||||
if hasInternalTx(tx, blockNumber, sender):
|
||||
let txTrace = requestInternalTx(t["hash"], tracer)
|
||||
|
@ -37,7 +37,6 @@ cliBuilder:
|
||||
#./test_txpool, -- fails
|
||||
./test_txpool2,
|
||||
./test_engine_api,
|
||||
./test_eip4844,
|
||||
./test_getproof_json,
|
||||
./test_aristo,
|
||||
./test_coredb
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
import
|
||||
std/[macrocache, strutils],
|
||||
eth/keys,
|
||||
eth/common/[keys, transaction_utils],
|
||||
unittest2,
|
||||
chronicles,
|
||||
stew/byteutils,
|
||||
@ -384,9 +384,10 @@ proc createSignedTx(payload: Blob, chainId: ChainId): Transaction =
|
||||
to: Opt.some codeAddress,
|
||||
value: 500.u256,
|
||||
payload: payload,
|
||||
chainId: chainId,
|
||||
versionedHashes: @[VersionedHash(EMPTY_UNCLE_HASH), VersionedHash(EMPTY_SHA3)]
|
||||
)
|
||||
signTransaction(unsignedTx, privateKey, chainId, false)
|
||||
signTransaction(unsignedTx, privateKey, false)
|
||||
|
||||
proc runVM*(vmState: BaseVMState, boa: Assembler): bool =
|
||||
let
|
||||
@ -395,7 +396,7 @@ proc runVM*(vmState: BaseVMState, boa: Assembler): bool =
|
||||
db.setCode(codeAddress, boa.code)
|
||||
db.setBalance(codeAddress, 1_000_000.u256)
|
||||
let tx = createSignedTx(boa.data, com.chainId)
|
||||
let asmResult = testCallEvm(tx, tx.getSender, vmState)
|
||||
let asmResult = testCallEvm(tx, tx.recoverSender().expect("valid signature"), vmState)
|
||||
verifyAsmResult(vmState, boa, asmResult)
|
||||
|
||||
macro assembler*(list: untyped): untyped =
|
||||
|
@ -106,7 +106,7 @@ proc main() {.used.} =
|
||||
#chainDB.dumpTest(2_283_416) # first DDOS spam attack block
|
||||
com.dumpTest(2_463_413) # tangerine call* gas cost bug
|
||||
com.dumpTest(2_675_000) # spurious dragon first block
|
||||
com.dumpTest(2_675_002) # EIP155 tx.getSender
|
||||
com.dumpTest(2_675_002) # EIP155 tx.recoverSender
|
||||
com.dumpTest(4_370_000) # Byzantium first block
|
||||
|
||||
when isMainModule:
|
||||
|
@ -1,157 +0,0 @@
|
||||
# Nimbus
|
||||
# Copyright (c) 2023-2024 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.
|
||||
|
||||
import
|
||||
stew/byteutils,
|
||||
unittest2,
|
||||
eth/[common, keys],
|
||||
../nimbus/transaction
|
||||
|
||||
const
|
||||
recipient = address"095e7baea6a6c7c4c2dfeb977efac326af552d87"
|
||||
source = address"0x0000000000000000000000000000000000000001"
|
||||
storageKey= default(StorageKey)
|
||||
accesses = @[AccessPair(address: source, storageKeys: @[storageKey])]
|
||||
abcdef = hexToSeqByte("abcdef")
|
||||
hexKey = "af1a9be9f1a54421cac82943820a0fe0f601bb5f4f6d0bccc81c613f0ce6ae22"
|
||||
senderTop = address"73cf19657412508833f618a15e8251306b3e6ee5"
|
||||
|
||||
proc tx0(i: int): Transaction =
|
||||
Transaction(
|
||||
txType: TxLegacy,
|
||||
nonce: i.AccountNonce,
|
||||
to: Opt.some recipient,
|
||||
gasLimit: 1.GasInt,
|
||||
gasPrice: 2.GasInt,
|
||||
payload: abcdef)
|
||||
|
||||
proc tx1(i: int): Transaction =
|
||||
Transaction(
|
||||
# Legacy tx contract creation.
|
||||
txType: TxLegacy,
|
||||
nonce: i.AccountNonce,
|
||||
gasLimit: 1.GasInt,
|
||||
gasPrice: 2.GasInt,
|
||||
payload: abcdef)
|
||||
|
||||
proc tx2(i: int): Transaction =
|
||||
Transaction(
|
||||
# Tx with non-zero access list.
|
||||
txType: TxEip2930,
|
||||
chainId: 1.ChainId,
|
||||
nonce: i.AccountNonce,
|
||||
to: Opt.some recipient,
|
||||
gasLimit: 123457.GasInt,
|
||||
gasPrice: 10.GasInt,
|
||||
accessList: accesses,
|
||||
payload: abcdef)
|
||||
|
||||
proc tx3(i: int): Transaction =
|
||||
Transaction(
|
||||
# Tx with empty access list.
|
||||
txType: TxEip2930,
|
||||
chainId: 1.ChainId,
|
||||
nonce: i.AccountNonce,
|
||||
to: Opt.some recipient,
|
||||
gasLimit: 123457.GasInt,
|
||||
gasPrice: 10.GasInt,
|
||||
payload: abcdef)
|
||||
|
||||
proc tx4(i: int): Transaction =
|
||||
Transaction(
|
||||
# Contract creation with access list.
|
||||
txType: TxEip2930,
|
||||
chainId: 1.ChainId,
|
||||
nonce: i.AccountNonce,
|
||||
gasLimit: 123457.GasInt,
|
||||
gasPrice: 10.GasInt,
|
||||
accessList: accesses)
|
||||
|
||||
proc tx5(i: int): Transaction =
|
||||
Transaction(
|
||||
txType: TxEip1559,
|
||||
chainId: 1.ChainId,
|
||||
nonce: i.AccountNonce,
|
||||
gasLimit: 123457.GasInt,
|
||||
maxPriorityFeePerGas: 42.GasInt,
|
||||
maxFeePerGas: 10.GasInt,
|
||||
accessList: accesses)
|
||||
|
||||
proc tx6(i: int): Transaction =
|
||||
const
|
||||
digest = hash32"010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014"
|
||||
|
||||
Transaction(
|
||||
txType: TxEip4844,
|
||||
chainId: 1.ChainId,
|
||||
nonce: i.AccountNonce,
|
||||
gasLimit: 123457.GasInt,
|
||||
maxPriorityFeePerGas:42.GasInt,
|
||||
maxFeePerGas: 10.GasInt,
|
||||
accessList: accesses,
|
||||
versionedHashes: @[digest]
|
||||
)
|
||||
|
||||
proc tx7(i: int): Transaction =
|
||||
const
|
||||
digest = hash32"01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e"
|
||||
|
||||
Transaction(
|
||||
txType: TxEip4844,
|
||||
chainID: 1.ChainId,
|
||||
nonce: i.AccountNonce,
|
||||
gasLimit: 123457.GasInt,
|
||||
maxPriorityFeePerGas:42.GasInt,
|
||||
maxFeePerGas: 10.GasInt,
|
||||
accessList: accesses,
|
||||
versionedHashes: @[digest],
|
||||
maxFeePerBlobGas: 10000000.u256,
|
||||
)
|
||||
|
||||
proc tx8(i: int): Transaction =
|
||||
const
|
||||
digest = hash32"01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e"
|
||||
|
||||
Transaction(
|
||||
txType: TxEip4844,
|
||||
chainID: 1.ChainId,
|
||||
nonce: i.AccountNonce,
|
||||
to: Opt.some recipient,
|
||||
gasLimit: 123457.GasInt,
|
||||
maxPriorityFeePerGas:42.GasInt,
|
||||
maxFeePerGas: 10.GasInt,
|
||||
accessList: accesses,
|
||||
versionedHashes: @[digest],
|
||||
maxFeePerBlobGas: 10000000.u256,
|
||||
)
|
||||
|
||||
proc privKey(keyHex: string): PrivateKey =
|
||||
let kRes = PrivateKey.fromHex(keyHex)
|
||||
if kRes.isErr:
|
||||
echo kRes.error
|
||||
quit(QuitFailure)
|
||||
|
||||
kRes.get()
|
||||
|
||||
proc eip4844Main*() =
|
||||
var signerKey = privKey(hexKey)
|
||||
|
||||
suite "EIP4844 sign transaction":
|
||||
let txs = @[tx0(3), tx1(3), tx2(3), tx3(3), tx4(3),
|
||||
tx5(3), tx6(3), tx7(3), tx8(3)]
|
||||
|
||||
test "sign transaction":
|
||||
for tx in txs:
|
||||
let signedTx = signTransaction(tx, signerKey, 1.ChainId, true)
|
||||
let sender = signedTx.getSender()
|
||||
check sender == senderTop
|
||||
|
||||
when isMainModule:
|
||||
eip4844Main()
|
@ -10,6 +10,7 @@ import
|
||||
unittest2,
|
||||
stew/byteutils,
|
||||
eth/keys,
|
||||
eth/common/transaction_utils,
|
||||
../nimbus/common,
|
||||
../nimbus/transaction,
|
||||
../nimbus/evm/types,
|
||||
@ -358,8 +359,8 @@ proc runTestOverflow() =
|
||||
)
|
||||
|
||||
let privateKey = PrivateKey.fromHex("0000000000000000000000000000000000000000000000000000001000000000")[]
|
||||
let tx = signTransaction(unsignedTx, privateKey, ChainId(1), false)
|
||||
let res = testCallEvm(tx, tx.getSender, s)
|
||||
let tx = signTransaction(unsignedTx, privateKey, false)
|
||||
let res = testCallEvm(tx, tx.recoverSender().expect("valid signature"), s)
|
||||
|
||||
when defined(evmc_enabled):
|
||||
check res.error == "EVMC_FAILURE"
|
||||
|
@ -20,6 +20,7 @@ import
|
||||
../tools/evmstate/helpers,
|
||||
../tools/common/state_clearing,
|
||||
eth/trie/trie_defs,
|
||||
eth/common/transaction_utils,
|
||||
unittest2,
|
||||
stew/byteutils,
|
||||
results
|
||||
@ -101,7 +102,7 @@ proc testFixtureIndexes(ctx: var TestCtx, testStatusIMPL: var TestStatus) =
|
||||
)
|
||||
|
||||
var gasUsed: GasInt
|
||||
let sender = ctx.tx.getSender()
|
||||
let sender = ctx.tx.recoverSender().expect("valid signature")
|
||||
|
||||
vmState.mutateStateDB:
|
||||
setupStateDB(ctx.pre, db)
|
||||
|
@ -11,6 +11,7 @@
|
||||
import
|
||||
std/[strformat, strutils, importutils],
|
||||
eth/keys,
|
||||
eth/common/transaction_utils,
|
||||
stew/byteutils,
|
||||
stew/endians2,
|
||||
../nimbus/config,
|
||||
@ -53,13 +54,13 @@ proc pp*(a: EthAddress): string =
|
||||
|
||||
proc pp*(tx: Transaction): string =
|
||||
# "(" & tx.ecRecover.value.pp & "," & $tx.nonce & ")"
|
||||
"(" & tx.getSender.pp & "," & $tx.nonce & ")"
|
||||
"(" & tx.recoverSender().value().pp & "," & $tx.nonce & ")"
|
||||
|
||||
proc pp*(h: KeccakHash): string =
|
||||
h.data.toHex[52 .. 63].toLowerAscii
|
||||
|
||||
proc pp*(tx: Transaction; ledger: LedgerRef): string =
|
||||
let address = tx.getSender
|
||||
let address = tx.recoverSender().value()
|
||||
"(" & address.pp &
|
||||
"," & $tx.nonce &
|
||||
";" & $ledger.getNonce(address) &
|
||||
@ -134,7 +135,7 @@ func makeTx(
|
||||
)
|
||||
|
||||
inc env.nonce
|
||||
signTransaction(tx, env.vaultKey, env.chainId, eip155 = true)
|
||||
signTransaction(tx, env.vaultKey, eip155 = true)
|
||||
|
||||
func initAddr(z: int): EthAddress =
|
||||
const L = sizeof(result)
|
||||
|
@ -9,6 +9,7 @@ import
|
||||
std/[strformat, strutils, json, os, tables, macros],
|
||||
unittest2, stew/byteutils,
|
||||
eth/[keys, trie],
|
||||
eth/common/transaction_utils,
|
||||
../nimbus/common/common,
|
||||
../tools/common/helpers as chp,
|
||||
../nimbus/[evm/computation,
|
||||
@ -42,10 +43,11 @@ template doTest(fixture: JsonNode; vmState: BaseVMState; address: PrecompileAddr
|
||||
gasLimit: 1_000_000_000.GasInt,
|
||||
to: Opt.some initAddress(address.byte),
|
||||
value: 0.u256,
|
||||
chainId: ChainId(1),
|
||||
payload: if dataStr.len > 0: dataStr.hexToSeqByte else: @[]
|
||||
)
|
||||
let tx = signTransaction(unsignedTx, privateKey, ChainId(1), false)
|
||||
let fixtureResult = testCallEvm(tx, tx.getSender, vmState)
|
||||
let tx = signTransaction(unsignedTx, privateKey, false)
|
||||
let fixtureResult = testCallEvm(tx, tx.recoverSender().expect("valid signature"), vmState)
|
||||
|
||||
if expectedErr:
|
||||
check fixtureResult.isError
|
||||
|
@ -12,6 +12,7 @@ import
|
||||
json_rpc/[rpcserver, rpcclient],
|
||||
nimcrypto/[keccak, hash],
|
||||
eth/[rlp, keys, trie/hexary_proof_verification],
|
||||
eth/common/transaction_utils,
|
||||
../nimbus/[constants, transaction, config, evm/state, evm/types, version],
|
||||
../nimbus/db/[ledger, storage_types],
|
||||
../nimbus/sync/protocol,
|
||||
@ -139,7 +140,8 @@ proc setupEnv(com: CommonRef, signer, ks2: EthAddress, ctx: EthContext): TestEnv
|
||||
gasPrice: 30_000_000_000,
|
||||
gasLimit: 70_000,
|
||||
value : 1.u256,
|
||||
to : some(zeroAddress)
|
||||
to : some(zeroAddress),
|
||||
chainId : com.chainId,
|
||||
)
|
||||
unsignedTx2 = Transaction(
|
||||
txType : TxLegacy,
|
||||
@ -147,11 +149,12 @@ proc setupEnv(com: CommonRef, signer, ks2: EthAddress, ctx: EthContext): TestEnv
|
||||
gasPrice: 30_000_000_100,
|
||||
gasLimit: 70_000,
|
||||
value : 2.u256,
|
||||
to : some(zeroAddress)
|
||||
to : some(zeroAddress),
|
||||
chainId : com.chainId,
|
||||
)
|
||||
eip155 = com.isEIP155(com.syncCurrent)
|
||||
signedTx1 = signTransaction(unsignedTx1, acc.privateKey, com.chainId, eip155)
|
||||
signedTx2 = signTransaction(unsignedTx2, acc.privateKey, com.chainId, eip155)
|
||||
signedTx1 = signTransaction(unsignedTx1, acc.privateKey, eip155)
|
||||
signedTx2 = signTransaction(unsignedTx2, acc.privateKey, eip155)
|
||||
txs = [signedTx1, signedTx2]
|
||||
|
||||
let txRoot = calcTxRoot(txs)
|
||||
@ -160,7 +163,7 @@ proc setupEnv(com: CommonRef, signer, ks2: EthAddress, ctx: EthContext): TestEnv
|
||||
vmState.receipts = newSeq[Receipt](txs.len)
|
||||
vmState.cumulativeGasUsed = 0
|
||||
for txIndex, tx in txs:
|
||||
let sender = tx.getSender()
|
||||
let sender = tx.recoverSender().expect("valid signature")
|
||||
let rc = vmState.processTransaction(tx, sender, vmHeader)
|
||||
doAssert(rc.isOk, "Invalid transaction: " & rc.error)
|
||||
vmState.receipts[txIndex] = makeReceipt(vmState, tx.txType)
|
||||
@ -400,7 +403,7 @@ proc rpcMain*() =
|
||||
|
||||
let signedTxBytes = await client.eth_signTransaction(unsignedTx)
|
||||
let signedTx = rlp.decode(signedTxBytes, Transaction)
|
||||
check signer == signedTx.getSender() # verified
|
||||
check signer == signedTx.recoverSender().expect("valid signature") # verified
|
||||
|
||||
let hashAhex = await client.eth_sendTransaction(unsignedTx)
|
||||
let hashBhex = await client.eth_sendRawTransaction(signedTxBytes)
|
||||
|
@ -13,6 +13,7 @@ import
|
||||
unittest2,
|
||||
eth/rlp,
|
||||
./test_helpers,
|
||||
eth/common/transaction_utils,
|
||||
../nimbus/[errors, transaction],
|
||||
../nimbus/utils/utils
|
||||
|
||||
@ -29,7 +30,7 @@ when isMainModule:
|
||||
transactionJsonMain()
|
||||
|
||||
proc txHash(tx: Transaction): string =
|
||||
toLowerAscii($keccakHash(rlp.encode(tx)))
|
||||
rlpHash(tx).toHex()
|
||||
|
||||
proc testTxByFork(tx: Transaction, forkData: JsonNode, forkName: string, testStatusIMPL: var TestStatus) =
|
||||
try:
|
||||
@ -41,7 +42,7 @@ proc testTxByFork(tx: Transaction, forkData: JsonNode, forkName: string, testSta
|
||||
let sender = EthAddress.fromHex(forkData["sender"].getStr)
|
||||
check "hash" in forkData
|
||||
check tx.txHash == forkData["hash"].getStr
|
||||
check tx.getSender == sender
|
||||
check tx.recoverSender().expect("valid signature") == sender
|
||||
|
||||
func noHash(fixture: JsonNode): bool =
|
||||
result = true
|
||||
|
@ -16,6 +16,7 @@ import
|
||||
../../nimbus/utils/ec_recover,
|
||||
../../nimbus/core/tx_pool/[tx_chain, tx_item],
|
||||
../../nimbus/transaction,
|
||||
eth/common/transaction_utils,
|
||||
./helpers,
|
||||
eth/[keys, p2p],
|
||||
stew/[keyed_queue, byteutils]
|
||||
@ -69,7 +70,7 @@ proc fillGenesis(env: var TxEnv, param: NetworkParams) =
|
||||
for z in n:
|
||||
let bytes = hexToSeqByte(z.getStr)
|
||||
let tx = rlp.decode(bytes, Transaction)
|
||||
let sender = tx.getSender()
|
||||
let sender = tx.recoverSender().expect("valid signature")
|
||||
let bal = map.getOrDefault(sender, 0.u256)
|
||||
if bal + tx.value > 0:
|
||||
map[sender] = bal + tx.value
|
||||
@ -99,10 +100,10 @@ proc setupTxPool*(getStatus: proc(): TxItemStatus): (CommonRef, TxPoolRef, int)
|
||||
let txPool = TxPoolRef.new(com)
|
||||
|
||||
for n, tx in txEnv.txs:
|
||||
let s = txEnv.getSigner(tx.getSender())
|
||||
let s = txEnv.getSigner(tx.recoverSender().expect("valid signature"))
|
||||
let status = statusInfo[getStatus()]
|
||||
let info = &"{n}/{txEnv.txs.len} {status}"
|
||||
let signedTx = signTransaction(tx, s.signer, txEnv.chainId, eip155 = true)
|
||||
let signedTx = signTransaction(tx, s.signer, eip155 = true)
|
||||
txPool.add(PooledTransaction(tx: signedTx), info)
|
||||
|
||||
(com, txPool, txEnv.txs.len)
|
||||
|
@ -9,7 +9,7 @@
|
||||
# according to those terms.
|
||||
|
||||
import
|
||||
../../nimbus/constants,
|
||||
../../nimbus/[constants, transaction],
|
||||
../../nimbus/utils/ec_recover,
|
||||
../../nimbus/core/tx_pool/tx_item,
|
||||
eth/[common, common/transaction, keys],
|
||||
@ -20,35 +20,6 @@ const
|
||||
# example from clique, signer: 658bdf435d810c91414ec09147daa6db62406379
|
||||
prvKey = "9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"
|
||||
|
||||
proc signature(tx: Transaction; key: PrivateKey): (uint64,UInt256,UInt256) =
|
||||
let
|
||||
hashData = tx.txHashNoSignature.data
|
||||
signature = key.sign(SkMessage(hashData)).toRaw
|
||||
v = signature[64].uint64
|
||||
|
||||
result[1] = UInt256.fromBytesBE(signature[0..31])
|
||||
result[2] = UInt256.fromBytesBE(signature[32..63])
|
||||
|
||||
if tx.txType == TxLegacy:
|
||||
if tx.V >= EIP155_CHAIN_ID_OFFSET:
|
||||
# just a guess which does not always work .. see `txModPair()`
|
||||
# see https://eips.ethereum.org/EIPS/eip-155
|
||||
result[0] = (tx.V and not 1'u64) or (not v and 1'u64)
|
||||
else:
|
||||
result[0] = 27 + v
|
||||
else:
|
||||
# currently unsupported, will skip this one .. see `txModPair()`
|
||||
result[0] = 0'u64
|
||||
|
||||
|
||||
proc sign(tx: Transaction; key: PrivateKey): Transaction =
|
||||
let (V,R,S) = tx.signature(key)
|
||||
result = tx
|
||||
result.V = V
|
||||
result.R = R
|
||||
result.S = S
|
||||
|
||||
|
||||
proc sign(header: BlockHeader; key: PrivateKey): BlockHeader =
|
||||
let
|
||||
hashData = header.blockHash.data
|
||||
@ -73,14 +44,14 @@ proc txModPair*(item: TxItemRef; nonce: int; priceBump: int):
|
||||
tx1.gasPrice = (tx0.gasPrice * (100 + priceBump).GasInt + 99.GasInt) div 100
|
||||
|
||||
let
|
||||
tx0Signed = tx0.sign(prvTestKey)
|
||||
tx1Signed = tx1.sign(prvTestKey)
|
||||
tx0Signed = tx0.signTransaction(prvTestKey)
|
||||
tx1Signed = tx0.signTransaction(prvTestKey)
|
||||
block:
|
||||
let rc = tx0Signed.ecRecover
|
||||
let rc = tx0Signed.recoverSender()
|
||||
if rc.isErr or rc.value != testAddress:
|
||||
return
|
||||
block:
|
||||
let rc = tx1Signed.ecRecover
|
||||
let rc = tx1Signed.recoverSender()
|
||||
if rc.isErr or rc.value != testAddress:
|
||||
return
|
||||
(item,tx0Signed,tx1Signed)
|
||||
|
@ -77,13 +77,13 @@ func makeTx(
|
||||
)
|
||||
|
||||
inc t.nonce
|
||||
signTransaction(tx, t.vaultKey, t.chainId, eip155 = true)
|
||||
signTransaction(tx, t.vaultKey, eip155 = true)
|
||||
|
||||
func signTxWithNonce(
|
||||
t: TestEnv, tx: Transaction, nonce: AccountNonce): Transaction =
|
||||
var tx = tx
|
||||
tx.nonce = nonce
|
||||
signTransaction(tx, t.vaultKey, t.chainId, eip155 = true)
|
||||
signTransaction(tx, t.vaultKey, eip155 = true)
|
||||
|
||||
proc initEnv(envFork: HardFork): TestEnv =
|
||||
var
|
||||
|
@ -12,6 +12,7 @@ import
|
||||
std/[json, strutils, sets, tables, options, streams],
|
||||
chronicles,
|
||||
eth/keys,
|
||||
eth/common/transaction_utils,
|
||||
stew/byteutils,
|
||||
results,
|
||||
stint,
|
||||
@ -68,7 +69,7 @@ method getAncestorHash(vmState: TestVMState; blockNumber: BlockNumber): Hash256
|
||||
keccakHash(toBytes($blockNumber))
|
||||
|
||||
proc verifyResult(ctx: var StateContext, vmState: BaseVMState, obtainedHash: Hash256) =
|
||||
ctx.error = ""
|
||||
ctx.error = ""
|
||||
if obtainedHash != ctx.expectedHash:
|
||||
ctx.error = "post state root mismatch: got $1, want $2" %
|
||||
[($obtainedHash).toLowerAscii, $ctx.expectedHash]
|
||||
@ -129,7 +130,7 @@ proc runExecution(ctx: var StateContext, conf: StateConf, pre: JsonNode): StateR
|
||||
tracer = tracer)
|
||||
|
||||
var gasUsed: GasInt
|
||||
let sender = ctx.tx.getSender()
|
||||
let sender = ctx.tx.recoverSender().expect("valid signature")
|
||||
|
||||
vmState.mutateStateDB:
|
||||
setupStateDB(pre, db)
|
||||
|
@ -147,7 +147,7 @@ proc parseTx*(n: JsonNode, dataIndex, gasIndex, valueIndex: int): Transaction =
|
||||
tx.to = Opt.some(EthAddress.fromHex(rawTo))
|
||||
|
||||
let secretKey = required(PrivateKey, "secretKey")
|
||||
signTransaction(tx, secretKey, tx.chainId, false)
|
||||
signTransaction(tx, secretKey, false)
|
||||
|
||||
proc parseTx*(txData, index: JsonNode): Transaction =
|
||||
let
|
||||
|
@ -228,6 +228,7 @@ proc parseTx(n: JsonNode, chainId: ChainID): Transaction =
|
||||
|
||||
if n.hasKey("to"):
|
||||
tx.to = Opt.some(EthAddress.fromJson(n, "to"))
|
||||
tx.chainId = chainId
|
||||
|
||||
case tx.txType
|
||||
of TxLegacy:
|
||||
@ -262,7 +263,7 @@ proc parseTx(n: JsonNode, chainId: ChainID): Transaction =
|
||||
if n.hasKey("secretKey"):
|
||||
let data = Blob.fromJson(n, "secretKey")
|
||||
let secretKey = PrivateKey.fromRaw(data).tryGet
|
||||
signTransaction(tx, secretKey, chainId, eip155)
|
||||
signTransaction(tx, secretKey, eip155)
|
||||
else:
|
||||
required(tx, uint64, v)
|
||||
required(tx, UInt256, r)
|
||||
|
@ -11,6 +11,7 @@
|
||||
import
|
||||
std/[json, strutils, tables, os, streams],
|
||||
eth/[rlp, trie, eip1559],
|
||||
eth/common/transaction_utils,
|
||||
stint, results,
|
||||
"."/[config, types, helpers],
|
||||
../common/state_clearing,
|
||||
@ -256,8 +257,7 @@ proc exec(ctx: var TransContext,
|
||||
continue
|
||||
|
||||
let tx = txRes.get
|
||||
var sender: EthAddress
|
||||
if not tx.getSender(sender):
|
||||
let sender = tx.recoverSender().valueOr:
|
||||
rejected.add RejectedTx(
|
||||
index: txIndex,
|
||||
error: "Could not get sender"
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Nimbus
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Copyright (c) 2022-2024 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)
|
||||
@ -11,6 +11,7 @@
|
||||
import
|
||||
eth/[common, rlp],
|
||||
stew/byteutils,
|
||||
eth/common/transaction_utils,
|
||||
../../nimbus/transaction,
|
||||
../../nimbus/common/evmforks
|
||||
|
||||
@ -19,7 +20,7 @@ proc parseTx(hexLine: string) =
|
||||
let
|
||||
bytes = hexToSeqByte(hexLine)
|
||||
tx = decodeTx(bytes)
|
||||
address = tx.getSender()
|
||||
address = tx.recoverSender().expect("valid signature")
|
||||
|
||||
tx.validate(FkLondon)
|
||||
|
||||
@ -30,8 +31,6 @@ proc parseTx(hexLine: string) =
|
||||
echo "err: ", ex.msg
|
||||
except ValueError as ex:
|
||||
echo "err: ", ex.msg
|
||||
except ValidationError as ex:
|
||||
echo "err: ", ex.msg
|
||||
except Exception:
|
||||
# TODO: rlp.hasData assertion should be
|
||||
# changed into RlpError
|
||||
|
2
vendor/nim-eth
vendored
2
vendor/nim-eth
vendored
@ -1 +1 @@
|
||||
Subproject commit 792b8b9bff09a5ed7cc98bc12b0c3d991e019b6f
|
||||
Subproject commit 4ea11b9fb9c6a0ab0886b5deca94a3d4f669386d
|
2
vendor/nim-web3
vendored
2
vendor/nim-web3
vendored
@ -1 +1 @@
|
||||
Subproject commit 62a0005b0907a64090827d4e5d691682587f5b2a
|
||||
Subproject commit c38791832cac2d23eab57cdc32decdd8123e5d36
|
Loading…
x
Reference in New Issue
Block a user