mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 12:54:13 +00:00
preparation for EIP-1559 implementation
- unify signTx in test_helper and signTransaction in rpc_utils and put it into transaction.nim - clean up mess by previous EIP-2930
This commit is contained in:
parent
f8b3922eb5
commit
4a188788bd
@ -580,13 +580,13 @@ proc txTo(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
|
||||
# TODO: with block param
|
||||
let ctx = GraphqlContextRef(ud)
|
||||
let tx = TxNode(parent)
|
||||
if tx.tx.isContractCreation:
|
||||
if tx.tx.contractCreation:
|
||||
return ok(respNull())
|
||||
let hres = ctx.getBlockByNumber(tx.blockNumber)
|
||||
if hres.isErr:
|
||||
return hres
|
||||
let h = HeaderNode(hres.get())
|
||||
ctx.accountNode(h.header, tx.tx.to)
|
||||
ctx.accountNode(h.header, tx.tx.to.get())
|
||||
|
||||
proc txValue(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
|
||||
let ctx = GraphqlContextRef(ud)
|
||||
@ -617,7 +617,7 @@ proc txStatus(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.}
|
||||
let ctx = GraphqlContextRef(ud)
|
||||
let tx = TxNode(parent)
|
||||
if tx.receipt.hasStatus:
|
||||
longNode(tx.receipt.status().uint64)
|
||||
longNode(tx.receipt.status.uint64)
|
||||
else:
|
||||
ok(respNull())
|
||||
|
||||
@ -638,7 +638,7 @@ proc txCreatedContract(ud: RootRef, params: Args, parent: Node): RespResult {.ap
|
||||
if not getSender(tx.tx, sender):
|
||||
return err("can't calculate sender")
|
||||
|
||||
if not tx.tx.isContractCreation:
|
||||
if not tx.tx.contractCreation:
|
||||
return ok(respNull())
|
||||
|
||||
let hres = getBlockByNumber(ctx, tx.blockNumber)
|
||||
@ -677,11 +677,11 @@ proc txType(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
|
||||
proc txAccessList(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
|
||||
let ctx = GraphqlContextRef(ud)
|
||||
let tx = TxNode(parent)
|
||||
if tx.tx.txType == LegacyTxType:
|
||||
if tx.tx.txType == TxLegacy:
|
||||
ok(respNull())
|
||||
else:
|
||||
var list = respList()
|
||||
for x in tx.tx.accessListTx.accessList:
|
||||
for x in tx.tx.accessList:
|
||||
list.add aclNode(ctx, x)
|
||||
ok(list)
|
||||
|
||||
|
@ -110,7 +110,7 @@ const
|
||||
# params/protocol_params.go(123): InitialBaseFee = 1000000000 [..]
|
||||
EIP1559_INITIAL_BASE_FEE* = ##\
|
||||
## Initial base fee for Eip1559 blocks.
|
||||
1000000000i64
|
||||
1000000000.u256
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Error tokens
|
||||
|
@ -154,12 +154,8 @@ proc isLondonOrLater*(c: var ChainConfig; number: BlockNumber): bool =
|
||||
## FIXME: London is not defined yet, will come after Berlin
|
||||
FkBerlin < c.toFork(number)
|
||||
|
||||
proc baseFee*(header: BlockHeader): GasInt =
|
||||
# FIXME: `baseFee` header field not defined before `London` fork
|
||||
0.GasInt
|
||||
|
||||
# consensus/misc/eip1559.go(55): func CalcBaseFee(config [..]
|
||||
proc calc1599BaseFee*(c: var ChainConfig; parent: BlockHeader): GasInt =
|
||||
proc calc1599BaseFee*(c: var ChainConfig; parent: BlockHeader): UInt256 =
|
||||
## calculates the basefee of the header.
|
||||
|
||||
# If the current block is the first EIP-1559 block, return the
|
||||
@ -174,26 +170,29 @@ proc calc1599BaseFee*(c: var ChainConfig; parent: BlockHeader): GasInt =
|
||||
if parent.gasUsed == parentGasTarget:
|
||||
return parent.baseFee
|
||||
|
||||
let parentGasDenom = parentGasTarget.i128 *
|
||||
EIP1559_BASE_FEE_CHANGE_DENOMINATOR.i128
|
||||
let parentGasDenom = parentGasTarget.u256 *
|
||||
EIP1559_BASE_FEE_CHANGE_DENOMINATOR.u256
|
||||
|
||||
# baseFee is an Option[T]
|
||||
let parentBaseFee = parent.baseFee
|
||||
|
||||
if parentGasTarget < parent.gasUsed:
|
||||
# If the parent block used more gas than its target, the baseFee should
|
||||
# increase.
|
||||
let
|
||||
gasUsedDelta = (parent.gasUsed - parentGasTarget).i128
|
||||
baseFeeDelta = (parent.baseFee.i128 * gasUsedDelta) div parentGasDenom
|
||||
gasUsedDelta = (parent.gasUsed - parentGasTarget).u256
|
||||
baseFeeDelta = (parentBaseFee * gasUsedDelta) div parentGasDenom
|
||||
|
||||
return parent.baseFee + max(baseFeeDelta.truncate(GasInt), 1)
|
||||
return parentBaseFee + max(baseFeeDelta, 1.u256)
|
||||
|
||||
else:
|
||||
# Otherwise if the parent block used less gas than its target, the
|
||||
# baseFee should decrease.
|
||||
let
|
||||
gasUsedDelta = (parentGasTarget - parent.gasUsed).i128
|
||||
baseFeeDelta = (parent.baseFee.i128 * gasUsedDelta) div parentGasDenom
|
||||
gasUsedDelta = (parentGasTarget - parent.gasUsed).u256
|
||||
baseFeeDelta = (parentBaseFee * gasUsedDelta) div parentGasDenom
|
||||
|
||||
return max(parent.baseFee - baseFeeDelta.truncate(GasInt), 0)
|
||||
return max(parentBaseFee - baseFeeDelta, 0.u256)
|
||||
|
||||
|
||||
# consensus/misc/eip1559.go(32): func VerifyEip1559Header(config [..]
|
||||
@ -209,13 +208,14 @@ proc verify1559Header*(c: var ChainConfig;
|
||||
if rc.isErr:
|
||||
return err(rc.error)
|
||||
|
||||
let headerBaseFee = header.baseFee
|
||||
# Verify the header is not malformed
|
||||
if header.baseFee.isZero:
|
||||
if headerBaseFee.isZero:
|
||||
return err((errCliqueExpectedBaseFee,""))
|
||||
|
||||
# Verify the baseFee is correct based on the parent header.
|
||||
var expectedBaseFee = c.calc1599BaseFee(parent)
|
||||
if header.baseFee != expectedBaseFee:
|
||||
if headerBaseFee != expectedBaseFee:
|
||||
return err((errCliqueBaseFeeError,
|
||||
&"invalid baseFee: have {expectedBaseFee}, "&
|
||||
&"want {header.baseFee}, " &
|
||||
@ -224,15 +224,6 @@ proc verify1559Header*(c: var ChainConfig;
|
||||
|
||||
return ok()
|
||||
|
||||
# clique/clique.go(730): func encodeSigHeader(w [..]
|
||||
proc encode1559*(header: BlockHeader): seq[byte] =
|
||||
## Encode header field and considering new `baseFee` field for Eip1559.
|
||||
var writer = initRlpWriter()
|
||||
writer.append(header)
|
||||
if not header.baseFee.isZero:
|
||||
writer.append(header.baseFee)
|
||||
writer.finish
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Seal hash support
|
||||
# ------------------------------------------------------------------------------
|
||||
@ -246,7 +237,7 @@ proc encodeSealHeader*(header: BlockHeader): seq[byte] =
|
||||
var rlpHeader = header
|
||||
rlpHeader.extraData.setLen(header.extraData.len - EXTRA_SEAL)
|
||||
|
||||
rlpHeader.encode1559
|
||||
rlp.encode(rlpHeader)
|
||||
|
||||
# clique/clique.go(688): func SealHash(header *types.Header) common.Hash {
|
||||
proc hashSealHeader*(header: BlockHeader): Hash256 =
|
||||
|
@ -60,25 +60,19 @@ func createBloom*(receipts: openArray[Receipt]): Bloom =
|
||||
result = bloom.value.toByteArrayBE
|
||||
|
||||
proc makeReceipt*(vmState: BaseVMState, fork: Fork, txType: TxType): Receipt =
|
||||
if txType == AccessListTxType:
|
||||
var rec = AccessListReceipt(
|
||||
status: vmState.status,
|
||||
cumulativeGasUsed: vmState.cumulativeGasUsed,
|
||||
logs: vmState.getAndClearLogEntries()
|
||||
)
|
||||
rec.bloom = logsBloom(rec.logs).value.toByteArrayBE
|
||||
return Receipt(receiptType: AccessListReceiptType, accessListReceipt: rec)
|
||||
|
||||
var rec: LegacyReceipt
|
||||
var rec: Receipt
|
||||
if fork < FkByzantium:
|
||||
rec.stateRootOrStatus = hashOrStatus(vmState.accountDb.rootHash)
|
||||
rec.isHash = true
|
||||
rec.hash = vmState.accountDb.rootHash
|
||||
else:
|
||||
rec.stateRootOrStatus = hashOrStatus(vmState.status)
|
||||
rec.isHash = false
|
||||
rec.status = vmState.status
|
||||
|
||||
rec.receiptType = txType
|
||||
rec.cumulativeGasUsed = vmState.cumulativeGasUsed
|
||||
rec.logs = vmState.getAndClearLogEntries()
|
||||
rec.bloom = logsBloom(rec.logs).value.toByteArrayBE
|
||||
Receipt(receiptType: LegacyReceiptType, legacyReceipt: rec)
|
||||
rec
|
||||
|
||||
func eth(n: int): Uint256 {.compileTime.} =
|
||||
n.u256 * pow(10.u256, 18)
|
||||
|
@ -214,9 +214,10 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB , server: RpcServer) =
|
||||
let
|
||||
accDB = accountDbFromTag("latest")
|
||||
tx = unsignedTx(data, chain, accDB.getNonce(address) + 1)
|
||||
signedTx = signTransaction(tx, chain, acc.privateKey)
|
||||
eip155 = chain.currentBlock >= chain.config.eip155Block
|
||||
signedTx = signTransaction(tx, acc.privateKey, chain.config.chainId, eip155)
|
||||
rlpTx = rlp.encode(signedTx)
|
||||
|
||||
|
||||
result = hexDataStr(rlpTx)
|
||||
|
||||
server.rpc("eth_sendTransaction") do(data: TxSend) -> EthHashStr:
|
||||
@ -237,9 +238,10 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB , server: RpcServer) =
|
||||
let
|
||||
accDB = accountDbFromTag("latest")
|
||||
tx = unsignedTx(data, chain, accDB.getNonce(address) + 1)
|
||||
signedTx = signTransaction(tx, chain, acc.privateKey)
|
||||
eip155 = chain.currentBlock >= chain.config.eip155Block
|
||||
signedTx = signTransaction(tx, acc.privateKey, chain.config.chainId, eip155)
|
||||
rlpTx = rlp.encode(signedTx)
|
||||
|
||||
|
||||
result = keccak_256.digest(rlpTx).ethHashStr
|
||||
|
||||
server.rpc("eth_sendRawTransaction") do(data: HexDataStr) -> EthHashStr:
|
||||
|
@ -63,12 +63,9 @@ proc calculateMedianGasPrice*(chain: BaseChainDB): GasInt =
|
||||
else:
|
||||
result = prices[middle]
|
||||
|
||||
proc unsignedTx*(tx: TxSend, chain: BaseChainDB, defaultNonce: AccountNonce): LegacyUnsignedTx =
|
||||
proc unsignedTx*(tx: TxSend, chain: BaseChainDB, defaultNonce: AccountNonce): Transaction =
|
||||
if tx.to.isSome:
|
||||
result.to = toAddress(tx.to.get())
|
||||
result.isContractCreation = false
|
||||
else:
|
||||
result.isContractCreation = true
|
||||
result.to = some(toAddress(tx.to.get))
|
||||
|
||||
if tx.gas.isSome:
|
||||
result.gasLimit = hexToInt(tx.gas.get().string, GasInt)
|
||||
@ -92,47 +89,6 @@ proc unsignedTx*(tx: TxSend, chain: BaseChainDB, defaultNonce: AccountNonce): Le
|
||||
|
||||
result.payload = hexToSeqByte(tx.data.string)
|
||||
|
||||
func rlpEncode(tx: LegacyUnsignedTx, chainId: ChainId): auto =
|
||||
rlp.encode(LegacyTx(
|
||||
nonce: tx.nonce,
|
||||
gasPrice: tx.gasPrice,
|
||||
gasLimit: tx.gasLimit,
|
||||
to: tx.to,
|
||||
value: tx.value,
|
||||
payload: tx.payload,
|
||||
isContractCreation: tx.isContractCreation,
|
||||
V: chainId.int64,
|
||||
R: 0.u256,
|
||||
S: 0.u256
|
||||
))
|
||||
|
||||
proc signTransaction*(tx: LegacyUnsignedTx, chain: BaseChainDB, privateKey: PrivateKey): Transaction =
|
||||
let eip155 = chain.currentBlock >= chain.config.eip155Block
|
||||
let rlpTx = if eip155:
|
||||
rlpEncode(tx, chain.config.chainId)
|
||||
else:
|
||||
rlp.encode(tx)
|
||||
|
||||
let sig = sign(privateKey, rlpTx).toRaw
|
||||
let v = if eip155:
|
||||
sig[64].int64 + chain.config.chainId.int64 * 2'i64 + 35'i64
|
||||
else:
|
||||
sig[64].int64 + 27'i64
|
||||
|
||||
let tx = LegacyTx(
|
||||
nonce: tx.nonce,
|
||||
gasPrice: tx.gasPrice,
|
||||
gasLimit: tx.gasLimit,
|
||||
to: tx.to,
|
||||
value: tx.value,
|
||||
payload: tx.payload,
|
||||
isContractCreation: tx.isContractCreation,
|
||||
V: v,
|
||||
R: Uint256.fromBytesBE(sig[0..31]),
|
||||
S: Uint256.fromBytesBE(sig[32..63])
|
||||
)
|
||||
Transaction(txType: LegacyTxType, legacyTx: tx)
|
||||
|
||||
proc callData*(call: EthCall, callMode: bool = true, chain: BaseChainDB): RpcCallData =
|
||||
if call.source.isSome:
|
||||
result.source = toAddress(call.source.get)
|
||||
@ -169,8 +125,7 @@ proc populateTransactionObject*(tx: Transaction, header: BlockHeader, txIndex: i
|
||||
result.hash = tx.rlpHash
|
||||
result.input = tx.payLoad
|
||||
result.nonce = encodeQuantity(tx.nonce.uint64)
|
||||
if not tx.isContractCreation:
|
||||
result.to = some(tx.to)
|
||||
result.to = some(tx.destination)
|
||||
result.transactionIndex = some(encodeQuantity(txIndex.uint64))
|
||||
result.value = encodeQuantity(tx.value)
|
||||
result.v = encodeQuantity(tx.V.uint)
|
||||
@ -220,14 +175,11 @@ proc populateReceipt*(receipt: Receipt, gasUsed: GasInt, tx: Transaction, txInde
|
||||
result.blockHash = header.hash
|
||||
result.blockNumber = encodeQuantity(header.blockNumber)
|
||||
result.`from` = tx.getSender()
|
||||
|
||||
if tx.isContractCreation:
|
||||
result.to = some(tx.to)
|
||||
|
||||
result.to = some(tx.destination)
|
||||
result.cumulativeGasUsed = encodeQuantity(receipt.cumulativeGasUsed.uint64)
|
||||
result.gasUsed = encodeQuantity(gasUsed.uint64)
|
||||
|
||||
if tx.isContractCreation:
|
||||
if tx.contractCreation:
|
||||
var sender: EthAddress
|
||||
if tx.getSender(sender):
|
||||
let contractAddress = generateAddress(sender, tx.nonce)
|
||||
@ -241,4 +193,4 @@ proc populateReceipt*(receipt: Receipt, gasUsed: GasInt, tx: Transaction, txInde
|
||||
result.root = some(receipt.stateRoot)
|
||||
else:
|
||||
# 1 = success, 0 = failure.
|
||||
result.status = some(receipt.status)
|
||||
result.status = some(receipt.status.int)
|
||||
|
@ -7,36 +7,11 @@
|
||||
|
||||
import
|
||||
./constants, ./errors, eth/[common, keys], ./utils,
|
||||
stew/shims/macros,
|
||||
./forks, ./vm_gas_costs
|
||||
|
||||
import eth/common/transaction as common_transaction
|
||||
export common_transaction
|
||||
|
||||
template txc(fn: untyped, params: varargs[untyped]): untyped =
|
||||
if tx.txType == LegacyTxType:
|
||||
unpackArgs(fn, [tx.legacyTx, params])
|
||||
else:
|
||||
unpackArgs(fn, [tx.accessListTx, params])
|
||||
|
||||
template txField(field: untyped): untyped =
|
||||
if tx.txType == LegacyTxType:
|
||||
tx.legacyTx.field
|
||||
else:
|
||||
tx.accessListTx.field
|
||||
|
||||
template txFieldAsgn(field, data: untyped) =
|
||||
if tx.txType == LegacyTxType:
|
||||
tx.legacyTx.field = data
|
||||
else:
|
||||
tx.accessListTx.field = data
|
||||
|
||||
template recField(field: untyped): untyped =
|
||||
if rec.receiptType == LegacyReceiptType:
|
||||
rec.legacyReceipt.field
|
||||
else:
|
||||
rec.accessListReceipt.field
|
||||
|
||||
func intrinsicGas*(data: openarray[byte], fork: Fork): GasInt =
|
||||
result = gasFees[fork][GasTransaction]
|
||||
for i in data:
|
||||
@ -45,16 +20,7 @@ func intrinsicGas*(data: openarray[byte], fork: Fork): GasInt =
|
||||
else:
|
||||
result += gasFees[fork][GasTXDataNonZero]
|
||||
|
||||
proc intrinsicGas*(tx: LegacyTx, fork: Fork): GasInt =
|
||||
# Compute the baseline gas cost for this transaction. This is the amount
|
||||
# of gas needed to send this transaction (but that is not actually used
|
||||
# for computation)
|
||||
result = tx.payload.intrinsicGas(fork)
|
||||
|
||||
if tx.isContractCreation:
|
||||
result = result + gasFees[fork][GasTXCreate]
|
||||
|
||||
proc intrinsicGas*(tx: AccessListTx, fork: Fork): GasInt =
|
||||
proc intrinsicGas*(tx: Transaction, fork: Fork): GasInt =
|
||||
const
|
||||
ADDRESS_COST = 2400
|
||||
STORAGE_KEY_COST = 1900
|
||||
@ -64,58 +30,44 @@ proc intrinsicGas*(tx: AccessListTx, fork: Fork): GasInt =
|
||||
# for computation)
|
||||
result = tx.payload.intrinsicGas(fork)
|
||||
|
||||
result = result + tx.accessList.len * ADDRESS_COST
|
||||
var numKeys = 0
|
||||
for n in tx.accessList:
|
||||
inc(numKeys, n.storageKeys.len)
|
||||
|
||||
result = result + numKeys * STORAGE_KEY_COST
|
||||
if tx.isContractCreation:
|
||||
if tx.contractCreation:
|
||||
result = result + gasFees[fork][GasTXCreate]
|
||||
|
||||
proc intrinsicGas*(tx: Transaction, fork: Fork): GasInt =
|
||||
txc(intrinsicGas, fork)
|
||||
|
||||
proc getSignature*(tx: LegacyTx, output: var Signature): bool =
|
||||
var bytes: array[65, byte]
|
||||
bytes[0..31] = tx.R.toByteArrayBE()
|
||||
bytes[32..63] = tx.S.toByteArrayBE()
|
||||
|
||||
# TODO: V will become a byte or range soon.
|
||||
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)
|
||||
let sig = Signature.fromRaw(bytes)
|
||||
if sig.isOk:
|
||||
output = sig[]
|
||||
return true
|
||||
return false
|
||||
|
||||
proc getSignature*(tx: AccessListTx, output: var Signature): bool =
|
||||
var bytes: array[65, byte]
|
||||
bytes[0..31] = tx.R.toByteArrayBE()
|
||||
bytes[32..63] = tx.S.toByteArrayBE()
|
||||
bytes[64] = tx.V.byte
|
||||
let sig = Signature.fromRaw(bytes)
|
||||
if sig.isOk:
|
||||
output = sig[]
|
||||
return true
|
||||
return false
|
||||
if tx.txType > TxLegacy:
|
||||
result = result + tx.accessList.len * ADDRESS_COST
|
||||
var numKeys = 0
|
||||
for n in tx.accessList:
|
||||
inc(numKeys, n.storageKeys.len)
|
||||
result = result + numKeys * STORAGE_KEY_COST
|
||||
|
||||
proc getSignature*(tx: Transaction, output: var Signature): bool =
|
||||
txc(getSignature, output)
|
||||
var bytes: array[65, byte]
|
||||
bytes[0..31] = tx.R.toByteArrayBE()
|
||||
bytes[32..63] = tx.S.toByteArrayBE()
|
||||
|
||||
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: LegacyTx | AccessListTx | Transaction, output: var EthAddress): bool =
|
||||
proc getSender*(tx: Transaction, output: var EthAddress): bool =
|
||||
## Find the address the transaction was sent from.
|
||||
var sig: Signature
|
||||
if tx.getSignature(sig):
|
||||
@ -125,98 +77,18 @@ proc getSender*(tx: LegacyTx | AccessListTx | Transaction, output: var EthAddres
|
||||
output = pubkey[].toCanonicalAddress()
|
||||
result = true
|
||||
|
||||
proc getSender*(tx: LegacyTx | AccessListTx | Transaction): EthAddress =
|
||||
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: LegacyTx | AccessListTx, sender: EthAddress): EthAddress =
|
||||
if tx.isContractCreation:
|
||||
proc getRecipient*(tx: Transaction, sender: EthAddress): EthAddress =
|
||||
if tx.contractCreation:
|
||||
result = generateAddress(sender, tx.nonce)
|
||||
else:
|
||||
result = tx.to
|
||||
|
||||
proc getRecipient*(tx: Transaction, sender: EthAddress): EthAddress =
|
||||
txc(getRecipient, sender)
|
||||
|
||||
proc gasLimit*(tx: Transaction): GasInt =
|
||||
txField(gasLimit)
|
||||
|
||||
proc gasPrice*(tx: Transaction): GasInt =
|
||||
txField(gasPrice)
|
||||
|
||||
proc value*(tx: Transaction): UInt256 =
|
||||
txField(value)
|
||||
|
||||
proc isContractCreation*(tx: Transaction): bool =
|
||||
txField(isContractCreation)
|
||||
|
||||
proc to*(tx: Transaction): EthAddress =
|
||||
txField(to)
|
||||
|
||||
proc payload*(tx: Transaction): Blob =
|
||||
txField(payload)
|
||||
|
||||
proc nonce*(tx: Transaction): AccountNonce =
|
||||
txField(nonce)
|
||||
|
||||
proc V*(tx: Transaction): int64 =
|
||||
txField(V)
|
||||
|
||||
proc R*(tx: Transaction): UInt256 =
|
||||
txField(R)
|
||||
|
||||
proc S*(tx: Transaction): UInt256 =
|
||||
txField(S)
|
||||
|
||||
proc `payload=`*(tx: var Transaction, data: Blob) =
|
||||
txFieldAsgn(payload, data)
|
||||
|
||||
proc `gasLimit=`*(tx: var Transaction, data: GasInt) =
|
||||
txFieldAsgn(gasLimit, data)
|
||||
|
||||
proc cumulativeGasUsed*(rec: Receipt): GasInt =
|
||||
recField(cumulativeGasUsed)
|
||||
|
||||
proc logs*(rec: Receipt): auto =
|
||||
recField(logs)
|
||||
|
||||
proc bloom*(rec: Receipt): auto =
|
||||
recField(bloom)
|
||||
|
||||
proc hasStateRoot*(rec: Receipt): bool =
|
||||
if rec.receiptType == LegacyReceiptType:
|
||||
rec.legacyReceipt.hasStateRoot
|
||||
else:
|
||||
false
|
||||
|
||||
proc hasStatus*(rec: Receipt): bool =
|
||||
if rec.receiptType == LegacyReceiptType:
|
||||
rec.legacyReceipt.hasStatus
|
||||
else:
|
||||
true
|
||||
|
||||
proc status*(rec: Receipt): int =
|
||||
if rec.receiptType == LegacyReceiptType:
|
||||
rec.legacyReceipt.status
|
||||
else:
|
||||
rec.accessListReceipt.status.int
|
||||
|
||||
proc stateRoot*(rec: Receipt): Hash256 =
|
||||
if rec.receiptType == LegacyReceiptType:
|
||||
return rec.legacyReceipt.stateRoot
|
||||
|
||||
proc validate*(tx: LegacyTx, fork: Fork) =
|
||||
# Hook called during instantiation to ensure that all transaction
|
||||
# parameters pass validation rules
|
||||
if tx.intrinsicGas(fork) > tx.gasLimit:
|
||||
raise newException(ValidationError, "Insufficient gas")
|
||||
|
||||
# check signature validity
|
||||
var sender: EthAddress
|
||||
if not tx.getSender(sender):
|
||||
raise newException(ValidationError, "Invalid signature or failed message verification")
|
||||
result = tx.to.get()
|
||||
|
||||
proc validateTxLegacy(tx: Transaction, fork: Fork) =
|
||||
var
|
||||
vMin = 27'i64
|
||||
vMax = 28'i64
|
||||
@ -239,7 +111,17 @@ proc validate*(tx: LegacyTx, fork: Fork) =
|
||||
if not isValid:
|
||||
raise newException(ValidationError, "Invalid transaction")
|
||||
|
||||
proc validate*(tx: AccessListTx, fork: Fork) =
|
||||
proc validateTxEip2930(tx: Transaction) =
|
||||
var isValid = tx.V in {0'i64, 1'i64}
|
||||
isValid = isValid and tx.S >= Uint256.one
|
||||
isValid = isValid and tx.S < SECPK1_N
|
||||
isValid = isValid and tx.R < SECPK1_N
|
||||
|
||||
if not isValid:
|
||||
raise newException(ValidationError, "Invalid transaction")
|
||||
|
||||
proc validate*(tx: Transaction, fork: Fork) =
|
||||
# parameters pass validation rules
|
||||
if tx.intrinsicGas(fork) > tx.gasLimit:
|
||||
raise newException(ValidationError, "Insufficient gas")
|
||||
|
||||
@ -248,19 +130,30 @@ proc validate*(tx: AccessListTx, fork: Fork) =
|
||||
if not tx.getSender(sender):
|
||||
raise newException(ValidationError, "Invalid signature or failed message verification")
|
||||
|
||||
var isValid = tx.V in {0'i64, 1'i64}
|
||||
isValid = isValid and tx.S >= Uint256.one
|
||||
isValid = isValid and tx.S < SECPK1_N
|
||||
isValid = isValid and tx.R < SECPK1_N
|
||||
|
||||
# TODO: chainId need validation?
|
||||
# TODO: accessList need validation?
|
||||
|
||||
if not isValid:
|
||||
raise newException(ValidationError, "Invalid transaction")
|
||||
|
||||
proc validate*(tx: Transaction, fork: Fork) =
|
||||
if tx.txType == LegacyTxType:
|
||||
validate(tx.legacyTx, fork)
|
||||
case tx.txType
|
||||
of TxLegacy:
|
||||
validateTxLegacy(tx, fork)
|
||||
else:
|
||||
validate(tx.accessListTx, fork)
|
||||
validateTxEip2930(tx)
|
||||
|
||||
proc signTransaction*(tx: Transaction, privateKey: PrivateKey, chainId: ChainId, eip155: bool): Transaction =
|
||||
result = tx
|
||||
if eip155:
|
||||
# trigger rlpEncodeEIP155 in nim-eth
|
||||
result.V = chainId.int64 * 2'i64 + 35'i64
|
||||
|
||||
let
|
||||
rlpTx = rlpEncode(result)
|
||||
sig = sign(privateKey, rlpTx).toRaw
|
||||
|
||||
case tx.txType
|
||||
of TxLegacy:
|
||||
if eip155:
|
||||
result.V = sig[64].int64 + result.V
|
||||
else:
|
||||
result.V = sig[64].int64 + 27'i64
|
||||
else:
|
||||
result.V = sig[64].int64
|
||||
|
||||
result.R = Uint256.fromBytesBE(sig[0..31])
|
||||
result.S = Uint256.fromBytesBE(sig[32..63])
|
||||
|
@ -119,13 +119,13 @@ proc txCallEvm*(tx: Transaction, sender: EthAddress, vmState: BaseVMState, fork:
|
||||
gasPrice: tx.gasPrice,
|
||||
gasLimit: tx.gasLimit,
|
||||
sender: sender,
|
||||
to: tx.to,
|
||||
isCreate: tx.isContractCreation,
|
||||
to: tx.destination,
|
||||
isCreate: tx.contractCreation,
|
||||
value: tx.value,
|
||||
input: tx.payload
|
||||
)
|
||||
if tx.txType == AccessListTxType:
|
||||
shallowCopy(call.accessList, tx.accessListTx.accessList)
|
||||
if tx.txType > TxLegacy:
|
||||
shallowCopy(call.accessList, tx.accessList)
|
||||
return runComputation(call).gasUsed
|
||||
|
||||
type
|
||||
@ -156,7 +156,7 @@ proc asmCallEvm*(blockNumber: Uint256, chainDB: BaseChainDB, code, data: seq[byt
|
||||
# creates the new contract using `code` like `CREATE`, but then executes the
|
||||
# contract like it's `CALL`.
|
||||
|
||||
doAssert tx.isContractCreation
|
||||
doAssert tx.contractCreation
|
||||
let contractAddress = generateAddress(sender, vmState.readOnlyStateDB.getNonce(sender))
|
||||
vmState.mutateStateDB:
|
||||
db.setCode(contractAddress, code)
|
||||
|
@ -60,12 +60,12 @@ proc setupComputation*(vmState: BaseVMState, tx: Transaction, sender: EthAddress
|
||||
)
|
||||
|
||||
let msg = Message(
|
||||
kind: if tx.isContractCreation: evmcCreate else: evmcCall,
|
||||
kind: if tx.contractCreation: evmcCreate else: evmcCall,
|
||||
depth: 0,
|
||||
gas: gas,
|
||||
sender: sender,
|
||||
contractAddress: tx.getRecipient(sender),
|
||||
codeAddress: tx.to,
|
||||
codeAddress: tx.destination,
|
||||
value: tx.value,
|
||||
data: tx.payload
|
||||
)
|
||||
|
@ -81,14 +81,15 @@ proc parseBlockHeader*(n: JsonNode): BlockHeader =
|
||||
n.fromJson "nonce", result.nonce
|
||||
|
||||
proc parseTransaction*(n: JsonNode): Transaction =
|
||||
var tx: LegacyTx
|
||||
var tx = Transaction(txType: TxLegacy)
|
||||
n.fromJson "nonce", tx.nonce
|
||||
n.fromJson "gasPrice", tx.gasPrice
|
||||
n.fromJson "gas", tx.gasLimit
|
||||
|
||||
tx.isContractCreation = n["to"].kind == JNull
|
||||
if not tx.isContractCreation:
|
||||
n.fromJson "to", tx.to
|
||||
if n["to"].kind != JNull:
|
||||
var to: EthAddress
|
||||
n.fromJson "to", to
|
||||
tx.to = some(to)
|
||||
|
||||
n.fromJson "value", tx.value
|
||||
n.fromJson "input", tx.payload
|
||||
@ -99,7 +100,7 @@ proc parseTransaction*(n: JsonNode): Transaction =
|
||||
var sender = tx.getSender()
|
||||
doAssert sender.prefixHex == n["from"].getStr()
|
||||
doAssert n["hash"].getStr() == tx.rlpHash().prefixHex
|
||||
result = Transaction(txType: LegacyTxType, legacyTx: tx)
|
||||
tx
|
||||
|
||||
proc parseLog(n: JsonNode): Log =
|
||||
n.fromJson "address", result.address
|
||||
@ -120,20 +121,22 @@ proc parseLogs(n: JsonNode): seq[Log] =
|
||||
result = @[]
|
||||
|
||||
proc parseReceipt*(n: JsonNode): Receipt =
|
||||
var rec: LegacyReceipt
|
||||
var rec = Receipt(receiptType: LegacyReceipt)
|
||||
if n.hasKey("root"):
|
||||
var hash: Hash256
|
||||
n.fromJson "root", hash
|
||||
rec.stateRootOrStatus = hashOrStatus(hash)
|
||||
rec.isHash = true
|
||||
rec.hash = hash
|
||||
else:
|
||||
var status: int
|
||||
n.fromJson "status", status
|
||||
rec.stateRootOrStatus = hashOrStatus(status == 1)
|
||||
rec.isHash = false
|
||||
rec.status = status == 1
|
||||
|
||||
n.fromJson "cumulativeGasUsed", rec.cumulativeGasUsed
|
||||
n.fromJson "logsBloom", rec.bloom
|
||||
rec.logs = parseLogs(n["logs"])
|
||||
Receipt(receiptType: LegacyReceiptType, legacyReceipt: rec)
|
||||
rec
|
||||
|
||||
proc headerHash*(n: JsonNode): Hash256 =
|
||||
n.fromJson "hash", result
|
||||
|
@ -15,7 +15,7 @@ proc fakeAlloc(n: JsonNode) =
|
||||
currMem = n[i]["memory"]
|
||||
prevPc = n[i-1]["pc"].getInt()
|
||||
currPc = n[i]["pc"].getInt()
|
||||
|
||||
|
||||
if currMem.len > prevMem.len and prevPc == currPc - 1:
|
||||
let diff = currMem.len - prevMem.len
|
||||
for _ in 0 ..< diff:
|
||||
@ -75,7 +75,7 @@ proc hasInternalTx(tx: Transaction, blockNumber: Uint256, sender: EthAddress): b
|
||||
code = request("eth_getCode", %[%recipient.prefixHex, number])
|
||||
recipientHasCode = code.getStr.len > 2 # "0x"
|
||||
|
||||
if tx.isContractCreation:
|
||||
if tx.contractCreation:
|
||||
return recipientHasCode or tx.payload.len > 0
|
||||
|
||||
recipientHasCode
|
||||
@ -148,14 +148,14 @@ proc requestPostState*(premix, n: JsonNode, blockNumber: Uint256) =
|
||||
var txKind = TxKind.Regular
|
||||
let tx = parseTransaction(t)
|
||||
let sender = tx.getSender
|
||||
if tx.isContractCreation: txKind = TxKind.ContractCreation
|
||||
if tx.contractCreation: txKind = TxKind.ContractCreation
|
||||
if hasInternalTx(tx, blockNumber, sender):
|
||||
let txTrace = requestInternalTx(t["hash"], tracer)
|
||||
for address, account in txTrace:
|
||||
updateAccount(address, account, blockNumber)
|
||||
premix.add account
|
||||
if not tx.isContractCreation: txKind = TxKind.ContractCall
|
||||
else:
|
||||
if not tx.contractCreation: txKind = TxKind.ContractCall
|
||||
else:
|
||||
premix.requestAccount(blockNumber, tx.getRecipient(sender))
|
||||
premix.requestAccount(blockNumber, sender)
|
||||
|
||||
|
@ -198,28 +198,12 @@ proc parseAccessList(n: JsonNode): AccessList =
|
||||
ap.storageKeys.add hexToByteArray[32](sk.getStr())
|
||||
result.add ap
|
||||
|
||||
proc signTx(tx: var LegacyTx, privateKey: PrivateKey) =
|
||||
let sig = sign(privateKey, tx.rlpEncode)
|
||||
let raw = sig.toRaw()
|
||||
tx.R = fromBytesBE(Uint256, raw[0..31])
|
||||
tx.S = fromBytesBE(Uint256, raw[32..63])
|
||||
tx.V = raw[64].int64 + 27
|
||||
|
||||
proc signTx(tx: var AccessListTx, privateKey: PrivateKey) =
|
||||
let sig = sign(privateKey, tx.rlpEncode)
|
||||
let raw = sig.toRaw()
|
||||
tx.R = fromBytesBE(Uint256, raw[0..31])
|
||||
tx.S = fromBytesBE(Uint256, raw[32..63])
|
||||
tx.V = raw[64].int64
|
||||
|
||||
proc getFixtureTransaction*(j: JsonNode, dataIndex, gasIndex, valueIndex: int): Transaction =
|
||||
let nonce = j["nonce"].getHexadecimalInt.AccountNonce
|
||||
let gasPrice = j["gasPrice"].getHexadecimalInt
|
||||
let gasLimit = j["gasLimit"][gasIndex].getHexadecimalInt
|
||||
|
||||
var toAddr: EthAddress
|
||||
var contract: bool
|
||||
|
||||
var toAddr: Option[EthAddress]
|
||||
# Fixture transactions with `"to": ""` are contract creations.
|
||||
#
|
||||
# Fixture transactions with `"to": "0x..."` or `"to": "..."` where `...` are
|
||||
@ -230,12 +214,8 @@ proc getFixtureTransaction*(j: JsonNode, dataIndex, gasIndex, valueIndex: int):
|
||||
# "0x" prefix is used in some but not all fixtures, and upper case hex digits
|
||||
# occur in a few.
|
||||
let rawTo = j["to"].getStr
|
||||
if rawTo == "":
|
||||
toAddr = ZERO_ADDRESS
|
||||
contract = true
|
||||
else:
|
||||
toAddr = rawTo.parseAddress
|
||||
contract = false
|
||||
if rawTo != "":
|
||||
toAddr = some(rawTo.parseAddress)
|
||||
|
||||
let value = fromHex(UInt256, j["value"][valueIndex].getStr)
|
||||
let payload = j["data"][dataIndex].getStr.safeHexToSeqByte
|
||||
@ -246,37 +226,29 @@ proc getFixtureTransaction*(j: JsonNode, dataIndex, gasIndex, valueIndex: int):
|
||||
|
||||
if j.hasKey("accessLists"):
|
||||
let accList = j["accessLists"][dataIndex]
|
||||
var tx = AccessListTx(
|
||||
var tx = Transaction(
|
||||
txType: TxEip2930,
|
||||
nonce: nonce,
|
||||
gasPrice: gasPrice,
|
||||
gasLimit: gasLimit,
|
||||
to: toAddr,
|
||||
isContractCreation: contract,
|
||||
value: value,
|
||||
payload: payload,
|
||||
accessList: parseAccessList(accList),
|
||||
chainId: common.ChainId(1)
|
||||
)
|
||||
signTx(tx, privateKey)
|
||||
Transaction(
|
||||
txType: AccessListTxType,
|
||||
accessListTx: tx
|
||||
chainId: ChainId(1)
|
||||
)
|
||||
signTransaction(tx, privateKey, ChainId(1), false)
|
||||
else:
|
||||
var tx = LegacyTx(
|
||||
var tx = Transaction(
|
||||
txType: TxLegacy,
|
||||
nonce: nonce,
|
||||
gasPrice: gasPrice,
|
||||
gasLimit: gasLimit,
|
||||
to: toAddr,
|
||||
isContractCreation: contract,
|
||||
value: value,
|
||||
payload: payload
|
||||
)
|
||||
signTx(tx, privateKey)
|
||||
Transaction(
|
||||
txType: LegacyTxType,
|
||||
legacyTx: tx
|
||||
)
|
||||
signTransaction(tx, privateKey, ChainId(1), false)
|
||||
|
||||
proc hashLogEntries*(logs: seq[Log]): string =
|
||||
toLowerAscii("0x" & $keccakHash(rlp.encode(logs)))
|
||||
|
@ -53,25 +53,30 @@ proc setupEnv(chain: BaseChainDB, signer, ks2: EthAddress, conf: NimbusConfigura
|
||||
|
||||
ac.setCode(ks2, code)
|
||||
ac.addBalance(signer, 9_000_000_000.u256)
|
||||
var vmState = newBaseVMState(ac.rootHash, BlockHeader(parentHash: parentHash), chain)
|
||||
var
|
||||
vmState = newBaseVMState(ac.rootHash, BlockHeader(parentHash: parentHash), chain)
|
||||
zeroAddress: EthAddress
|
||||
|
||||
let
|
||||
unsignedTx1 = LegacyUnsignedTx(
|
||||
unsignedTx1 = Transaction(
|
||||
txType : TxLegacy,
|
||||
nonce : 0,
|
||||
gasPrice: 1_100,
|
||||
gasLimit: 70_000,
|
||||
value : 1.u256,
|
||||
isContractCreation: false
|
||||
to : some(zeroAddress)
|
||||
)
|
||||
unsignedTx2 = LegacyUnsignedTx(
|
||||
unsignedTx2 = Transaction(
|
||||
txType : TxLegacy,
|
||||
nonce : 0,
|
||||
gasPrice: 1_200,
|
||||
gasLimit: 70_000,
|
||||
value : 2.u256,
|
||||
isContractCreation: false
|
||||
to : some(zeroAddress)
|
||||
)
|
||||
signedTx1 = signTransaction(unsignedTx1, chain, acc.privateKey)
|
||||
signedTx2 = signTransaction(unsignedTx2, chain, acc.privateKey)
|
||||
eip155 = chain.currentBlock >= chain.config.eip155Block
|
||||
signedTx1 = signTransaction(unsignedTx1, acc.privateKey, chain.config.chainId, eip155)
|
||||
signedTx2 = signTransaction(unsignedTx2, acc.privateKey, chain.config.chainId, eip155)
|
||||
txs = [signedTx1, signedTx2]
|
||||
txRoot = chain.persistTransactions(blockNumber, txs)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user