Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ nimble.paths

#OS specific files
**/.DS_Store

.claude/
7 changes: 6 additions & 1 deletion eth.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ requires "nim >= 2.0.10",
"unittest2",
"results",
"minilru",
"snappy"
"snappy",
"ssz_serialization"

let nimc = getEnv("NIMC", "nim") # Which nim compiler to use
let lang = getEnv("NIMLANG", "c") # Which backend (c/cpp/js)
Expand Down Expand Up @@ -64,6 +65,9 @@ task test_utp, "Run utp tests":
task test_common, "Run common tests":
run "tests/common/all_tests", "common"

task test_ssz, "Run SSZ tests":
run "tests/ssz/all_tests", "ssz_suite"

task test, "Run all tests":
run "tests/test_bloom", ""

Expand All @@ -75,6 +79,7 @@ task test, "Run all tests":
test_utp_task()
test_common_task()


task test_discv5_full, "Run discovery v5 and its dependencies tests":
test_rlp_task()
test_discv5_task()
Expand Down
2 changes: 2 additions & 0 deletions eth/common/addresses.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
## https://ethereum.org/en/developers/docs/accounts/#account-creation

import std/[typetraits, hashes as std_hashes], "."/[base, hashes], stew/assign2
import ssz_serialization/codec
import ssz_serialization/merkleization

export hashes

Expand Down
10 changes: 10 additions & 0 deletions eth/common/hashes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
## replaced with proof-of-stake.

import std/[typetraits, hashes], nimcrypto/keccak, ./base, stew/assign2
import ssz_serialization/codec
import ssz_serialization/merkleization

export hashes, keccak.update, keccak.finish

Expand Down Expand Up @@ -102,3 +104,11 @@ template withKeccak256*(body: untyped): Hash32 =
var h {.inject.}: keccak.keccak256
body
h.finish().to(Hash32)

# template toSszType*(T: type Hash32): auto =
# T.data()

# proc fromSszBytes*(T: type Hash32, bytes: openArray[byte]): T {.raises: [SszError].} =
# if bytes.len != sizeof(result.data()):
# raiseIncorrectSize T
# copyMem(addr result.data()[0], unsafeAddr bytes[0], sizeof(result.data()))
1 change: 1 addition & 0 deletions eth/common/headers.nim
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type
parentBeaconBlockRoot*: Opt[Hash32] # EIP-4788
requestsHash*: Opt[Hash32] # EIP-7685
blockAccessListHash*: Opt[Hash32] # EIP-7928
systemLogsRoot*: Opt[Hash32] # EIP-7685

# starting from EIP-4399, `mixDigest` field is called `prevRandao`
template prevRandao*(h: Header): Bytes32 =
Expand Down
27 changes: 25 additions & 2 deletions eth/common/receipts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

{.push raises: [].}

import
import
./[addresses, base, hashes, transactions],
../bloom

Expand All @@ -30,6 +30,7 @@ type
# Eip1559Receipt = TxEip1559
# Eip4844Receipt = TxEip4844
# Eip7702Receipt = TxEip7702
# Eip7807Receipt = TxEip7807

Receipt* = object
receiptType* : ReceiptType
Expand All @@ -39,6 +40,10 @@ type
cumulativeGasUsed*: GasInt
logsBloom* : Bloom
logs* : seq[Log]
# authorities* : seq[Address]
# txGasUsed* : uint64 # Gas used by THIS transaction only
# contactAddress* : Address # Address of the contract being called/created
# origin* : Address #sender address of the transaction

StoredReceipt* = object
receiptType* : ReceiptType
Expand All @@ -47,13 +52,25 @@ type
hash* : Hash32
cumulativeGasUsed*: GasInt
logs* : seq[Log]
eip7807ReceiptType*: Eip7807ReceiptType
authorities* : seq[Address]
txGasUsed* : uint64 # Gas used by THIS transaction only
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is txGasUsed required from spec?
If yes please mentioned spec link in comments

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention it in the code as a comment

contactAddress* : Address # Address of the contract being called/created
origin* : Address #sender address of the transaction

Eip7807ReceiptType* = enum
Eip7807Create
Eip7807Basic
Eip7807SetCode


const
LegacyReceipt* = TxLegacy
Eip2930Receipt* = TxEip2930
Eip1559Receipt* = TxEip1559
Eip4844Receipt* = TxEip4844
Eip7702Receipt* = TxEip7702
Eip7807Receipt* = TxEip7807

func hasStatus*(rec: Receipt): bool {.inline.} =
rec.isHash == false
Expand All @@ -75,13 +92,19 @@ func logsBloom(logs: openArray[Log]): BloomFilter =
res

func to*(rec: Receipt, _: type StoredReceipt): StoredReceipt =
# fill in default values for the new fields
StoredReceipt(
receiptType : rec.receiptType,
isHash : rec.isHash,
status : rec.status,
hash : rec.hash,
cumulativeGasUsed : rec.cumulativeGasUsed,
logs : rec.logs
logs : rec.logs,
authorities : @[],
# https://github.com/ethereum/EIPs/blob/676604927b316a44195008e632778d4ca1101deb/EIPS/eip-6466.md?plain=1#L138
txGasUsed : 0'u64,
contactAddress : default(Address), # default address
origin : default(Address) # default address
)

func to*(rec: StoredReceipt, _: type Receipt): Receipt =
Expand Down
37 changes: 34 additions & 3 deletions eth/common/receipts_rlp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export addresses_rlp, base_rlp, hashes_rlp, receipts, rlp

# RLP encoding for Receipt (eth/68)
proc append*(w: var RlpWriter, rec: Receipt) =
if rec.receiptType in {Eip2930Receipt, Eip1559Receipt, Eip4844Receipt, Eip7702Receipt}:
if rec.receiptType in {Eip2930Receipt, Eip1559Receipt, Eip4844Receipt, Eip7702Receipt, Eip7807Receipt}:
Comment thread
advaita-saha marked this conversation as resolved.
w.appendDetached(rec.receiptType.uint8)

w.startList(4)
Expand All @@ -29,7 +29,15 @@ proc append*(w: var RlpWriter, rec: Receipt) =

# RLP encoding for StoredReceipt (eth/69)
proc append*(w: var RlpWriter, rec: StoredReceipt) =
w.startList(4)

let tailLen =
if rec.receiptType == Eip7807Receipt:
case rec.eip7807ReceiptType
of Eip7807Basic: 3 # subtype, origin, txGasUsed
of Eip7807Create: 4 # + contractAddress
of Eip7807SetCode: 4 # + authorities
else: 0
w.startList(4 + tailLen)
w.append(rec.receiptType.uint)
if rec.isHash:
w.append(rec.hash)
Expand All @@ -38,6 +46,15 @@ proc append*(w: var RlpWriter, rec: StoredReceipt) =
w.append(rec.cumulativeGasUsed)
w.append(rec.logs)

if rec.receiptType == Eip7807Receipt:
w.append(rec.eip7807ReceiptType.uint)
w.append(rec.origin)
w.append(rec.txGasUsed)
case rec.eip7807ReceiptType
of Eip7807Create: w.append(rec.contactAddress)
of Eip7807SetCode: w.append(rec.authorities)
of Eip7807Basic: discard

# Decode legacy receipt (eth/68)
proc readReceiptLegacy(rlp: var Rlp, receipt: var Receipt) {.raises: [RlpError].} =
receipt.receiptType = LegacyReceipt
Expand Down Expand Up @@ -71,7 +88,7 @@ proc readReceiptTyped(rlp: var Rlp, receipt: var Receipt) {.raises: [RlpError].}
var txVal: ReceiptType
if checkedEnumAssign(txVal, recType):
case txVal
of Eip2930Receipt, Eip1559Receipt, Eip4844Receipt, Eip7702Receipt:
of Eip2930Receipt, Eip1559Receipt, Eip4844Receipt, Eip7702Receipt, Eip7807Receipt:
receipt.receiptType = txVal
of LegacyReceipt:
raise newException(MalformedRlpError, "Invalid ReceiptType: " & $recType)
Expand Down Expand Up @@ -116,6 +133,20 @@ proc read*(rlp: var Rlp, T: type StoredReceipt): StoredReceipt {.raises: [RlpErr
rlp.read(rec.cumulativeGasUsed)
rlp.read(rec.logs)

if rec.receiptType == Eip7807Receipt:
let st = rlp.read(uint)
if not checkedEnumAssign(rec.eip7807ReceiptType, st):
raise newException(UnsupportedRlpError, "Bad Eip7807ReceiptType: " & $st)
rlp.read(rec.origin)
rlp.read(rec.txGasUsed)
case rec.eip7807ReceiptType
of Eip7807Create: rlp.read(rec.contactAddress)
of Eip7807SetCode: rlp.read(rec.authorities)
of Eip7807Basic: discard

if rlp.hasData:
raise newException(MalformedRlpError, "Trailing fields in StoredReceipt")

rec

# Decode eth/68 Receipt
Expand Down
1 change: 1 addition & 0 deletions eth/common/transactions.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type
TxEip1559 # 2
TxEip4844 # 3
TxEip7702 # 4
TxEip7807 # 5

Transaction* = object
txType* : TxType # EIP-2718
Expand Down
24 changes: 16 additions & 8 deletions eth/common/transactions_rlp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

{.push raises: [].}

import
"."/[addresses_rlp, base_rlp, hashes_rlp, transactions],
import
"."/[addresses_rlp, base_rlp, hashes_rlp, transactions],
../rlp,
../rlp/[length_writer, two_pass_writer, hash_writer]

Expand Down Expand Up @@ -99,7 +99,7 @@ proc appendTxEip7702(w: var RlpWriter, tx: Transaction) =
w.append(tx.R)
w.append(tx.S)

proc appendTxPayload(w: var RlpWriter, tx: Transaction) =
proc appendTxPayload(w: var RlpWriter, tx: Transaction) {.raises: [UnsupportedRlpError].}=
case tx.txType
of TxLegacy:
w.appendTxLegacy(tx)
Expand All @@ -111,8 +111,12 @@ proc appendTxPayload(w: var RlpWriter, tx: Transaction) =
w.appendTxEip4844(tx)
of TxEip7702:
w.appendTxEip7702(tx)
of TxEip7807:
raise newException(UnsupportedRlpError, "TxEip7807 has no RLP encoding; use SSZ")

proc append*(w: var RlpWriter, tx: Transaction) =
proc append*(w: var RlpWriter, tx: Transaction) {.raises: [UnsupportedRlpError].} =
if tx.txType == TxEip7807:
raise newException(UnsupportedRlpError, "TxEip7807 has no RLP encoding; use SSZ")
if tx.txType != TxLegacy:
# since the tx type is encoded outside the transaction type its encoding
# cannot be considered a part of the rlp list that encodes the type. Hence
Expand Down Expand Up @@ -195,7 +199,7 @@ proc rlpEncodeEip7702(w: var RlpWriter, tx: Transaction) =
w.append(tx.accessList)
w.append(tx.authorizationList)

proc encodeUnsignedTransaction*(w: var RlpWriter, tx: Transaction, eip155: bool) =
proc encodeUnsignedTransaction*(w: var RlpWriter, tx: Transaction, eip155: bool){.raises: [UnsupportedRlpError].} =
## Encode transaction data in preparation for signing or signature checking.
## For signature checking, set `eip155 = tx.isEip155`
case tx.txType
Expand All @@ -209,8 +213,10 @@ proc encodeUnsignedTransaction*(w: var RlpWriter, tx: Transaction, eip155: bool)
w.rlpEncodeEip4844(tx)
of TxEip7702:
w.rlpEncodeEip7702(tx)
of TxEip7807:
raise newException(UnsupportedRlpError, "TxEip7807 has no RLP encoding; use SSZ")

proc encodeForSigning*(tx: Transaction, eip155: bool): seq[byte] =
proc encodeForSigning*(tx: Transaction, eip155: bool): seq[byte] {.raises: [UnsupportedRlpError].} =
## Encode transaction data in preparation for signing or signature checking.
## For signature checking, set `eip155 = tx.isEip155`
var tracker: DynamicRlpLengthTracker
Expand All @@ -223,7 +229,7 @@ proc encodeForSigning*(tx: Transaction, eip155: bool): seq[byte] =
template rlpEncode*(tx: Transaction): seq[byte] {.deprecated.} =
encodeForSigning(tx, tx.isEip155())

func rlpHashForSigning*(tx: Transaction, eip155: bool): Hash32 =
func rlpHashForSigning*(tx: Transaction, eip155: bool): Hash32 {.raises: [UnsupportedRlpError].} =
var tracker: DynamicRlpLengthTracker
tracker.initLengthTracker()
tracker.encodeUnsignedTransaction(tx, eip155)
Expand Down Expand Up @@ -403,6 +409,8 @@ proc readTxPayload(
rlp.readTxEip4844(tx)
of TxEip7702:
rlp.readTxEip7702(tx)
of TxEip7807:
raise newException(UnsupportedRlpError, "TxEip7807 has no RLP decoding; use SSZ")

proc readTxTyped(rlp: var Rlp, tx: var Transaction) {.raises: [RlpError].} =
let txType = rlp.readTxType()
Expand Down Expand Up @@ -446,7 +454,7 @@ proc read*(
rr.readTxTyped(tx)
result.add tx

proc append*(rlpWriter: var RlpWriter, txs: seq[Transaction] | openArray[Transaction]) =
proc append*(rlpWriter: var RlpWriter, txs: seq[Transaction] | openArray[Transaction]){.raises: [UnsupportedRlpError].} =
# See above about encoding arrays/sequences of transactions.
rlpWriter.startList(txs.len)
for tx in txs:
Expand Down
34 changes: 34 additions & 0 deletions eth/ssz/adapter.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{.push raises: [].}

import
../common/[addresses, hashes, base],
std/[typetraits],
ssz_serialization,
ssz_serialization/codec,
ssz_serialization/merkleization

# This follows how
# https://github.com/status-im/nimbus-eth2/blob/9839f140628ae0e2e8aa7eb055da5c4bb08171d0/beacon_chain/spec/ssz_codec.nim#L29
# does it for addresses in eth 2
export ssz_serialization, codec, base, typetraits

# SSZ for Address
template toSszType*(T: Address): auto =
distinctBase(T)

func fromSszBytes*(T: type Address, bytes: openArray[byte]): T {.raises: [SszError].} =
readSszValue(bytes, distinctBase(result))

# SSZ for Hash32
template toSszType*(T: Hash32): auto =
distinctBase(T)

func fromSszBytes*(T: type Hash32, bytes: openArray[byte]): T {.raises: [SszError].} =
readSszValue(bytes, distinctBase(result))

# SSZ for Bytes32
template toSszType*(T: Bytes32): auto =
distinctBase(T)

func fromSszBytes*(T: type Bytes32, bytes: openArray[byte]): T {.raises: [SszError].} =
readSszValue(bytes, distinctBase(result))
Loading