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:
jangko 2021-06-27 11:19:43 +07:00
parent f8b3922eb5
commit 4a188788bd
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
13 changed files with 160 additions and 348 deletions

View File

@ -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)

View File

@ -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

View File

@ -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 =

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -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])

View File

@ -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)

View File

@ -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
)

View File

@ -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

View File

@ -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)

View File

@ -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)))

View File

@ -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)