Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement EIP-4844: Shard Blobs Transactions #582

Merged
merged 1 commit into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eth.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ task test_utp, "Run utp tests":
runTest("tests/utp/all_utp_tests")

task test_common, "Run common tests":
runTest("tests/common/test_eth_types")
runTest("tests/common/all_tests")

task test, "Run all tests":
for filename in [
Expand Down
38 changes: 33 additions & 5 deletions eth/common/eth_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,29 @@ type

AccessList* = seq[AccessPair]

VersionedHash* = Hash256
VersionedHashes* = seq[VersionedHash]
KzgCommitment* = array[48, byte]
KzgProof* = array[48, byte]

# 32 -> UInt256
# 4096 -> FIELD_ELEMENTS_PER_BLOB
NetworkBlob* = array[32*4096, byte]

TxType* = enum
TxLegacy
TxEip2930
TxEip1559
TxLegacy # 0
TxEip2930 # 1
TxEip1559 # 2
TxEip4844 # 3

# instead of wrap Transaction with
# NetworkPayload, we embed it to Transaction
# the rest of magic happened in RLP
# encoding decoding
NetworkPayload* = ref object
blobs* : seq[NetworkBlob]
commitments* : seq[KzgCommitment]
proofs* : seq[KzgProof]

Transaction* = object
txType* : TxType # EIP-2718
Expand All @@ -79,6 +98,9 @@ type
value* : UInt256
payload* : Blob
accessList* : AccessList # EIP-2930
maxFeePerDataGas*: GasInt # EIP-4844
versionedHashes*: VersionedHashes # EIP-4844
networkPayload*: NetworkPayload # EIP-4844
V* : int64
R*, S* : UInt256

Expand Down Expand Up @@ -138,6 +160,7 @@ type
# LegacyReceipt = TxLegacy
# Eip2930Receipt = TxEip2930
# Eip1559Receipt = TxEip1559
# Eip4844Receipt = TxEip4844

Receipt* = object
receiptType* : ReceiptType
Expand Down Expand Up @@ -183,6 +206,7 @@ const
LegacyReceipt* = TxLegacy
Eip2930Receipt* = TxEip2930
Eip1559Receipt* = TxEip1559
Eip4844Receipt* = TxEip4844

# TODO clean these up
EMPTY_ROOT_HASH* = "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".toDigest
Expand Down Expand Up @@ -271,8 +295,12 @@ func destination*(tx: Transaction): EthAddress =
if tx.to.isSome:
return tx.to.get

func init*(
T: type BlockHashOrNumber, str: string): T {.raises: [ValueError].} =
func removeNetworkPayload*(tx: Transaction): Transaction =
result = tx
result.networkPayload = nil

func init*(T: type BlockHashOrNumber, str: string): T
{.raises: [ValueError].} =
if str.startsWith "0x":
if str.len != sizeof(default(T).hash.data) * 2 + 2:
raise newException(ValueError, "Block hash has incorrect length")
Expand Down
96 changes: 88 additions & 8 deletions eth/common/eth_types_rlp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ proc appendTxLegacy(w: var RlpWriter, tx: Transaction) =
w.append(tx.S)

proc appendTxEip2930(w: var RlpWriter, tx: Transaction) =
w.append(1)
w.append(TxEip2930)
w.startList(11)
w.append(tx.chainId.uint64)
w.append(tx.nonce)
Expand All @@ -98,7 +98,7 @@ proc appendTxEip2930(w: var RlpWriter, tx: Transaction) =
w.append(tx.S)

proc appendTxEip1559(w: var RlpWriter, tx: Transaction) =
w.append(2)
w.append(TxEip1559)
w.startList(12)
w.append(tx.chainId.uint64)
w.append(tx.nonce)
Expand All @@ -113,6 +113,42 @@ proc appendTxEip1559(w: var RlpWriter, tx: Transaction) =
w.append(tx.R)
w.append(tx.S)

proc appendTxEip4844Signed(w: var RlpWriter, tx: Transaction) =
# exclude tx type
w.startList(14)
w.append(tx.chainId.uint64)
w.append(tx.nonce)
w.append(tx.maxPriorityFee)
w.append(tx.maxFee)
w.append(tx.gasLimit)
w.append(tx.to)
w.append(tx.value)
w.append(tx.payload)
w.append(tx.accessList)
w.append(tx.maxFeePerDataGas)
w.append(tx.versionedHashes)
w.append(tx.V)
w.append(tx.R)
w.append(tx.S)

proc appendTxEip4844Network(w: var RlpWriter, tx: Transaction) =
# exclude tx type
# spec: rlp([tx_payload, blobs, commitments, proofs])
w.startList(4)
w.appendTxEip4844Signed(tx)
w.append(tx.networkPayload.blobs)
w.append(tx.networkPayload.commitments)
w.append(tx.networkPayload.proofs)

proc appendTxEip4844(w: var RlpWriter, tx: Transaction) =
# append the tx type first
w.append(TxEip4844)

if tx.networkPayload.isNil:
w.appendTxEip4844Signed(tx)
else:
w.appendTxEip4844Network(tx)

proc append*(w: var RlpWriter, tx: Transaction) =
case tx.txType
of TxLegacy:
Expand All @@ -121,6 +157,8 @@ proc append*(w: var RlpWriter, tx: Transaction) =
w.appendTxEip2930(tx)
of TxEip1559:
w.appendTxEip1559(tx)
of TxEip4844:
w.appendTxEip4844(tx)

template read[T](rlp: var Rlp, val: var T)=
val = rlp.read(type val)
Expand Down Expand Up @@ -175,6 +213,44 @@ proc readTxEip1559(rlp: var Rlp, tx: var Transaction)=
rlp.read(tx.R)
rlp.read(tx.S)

proc readTxEip4844Signed(rlp: var Rlp, tx: var Transaction) =
rlp.tryEnterList()
tx.chainId = rlp.read(uint64).ChainId
rlp.read(tx.nonce)
rlp.read(tx.maxPriorityFee)
rlp.read(tx.maxFee)
rlp.read(tx.gasLimit)
rlp.read(tx.to)
rlp.read(tx.value)
rlp.read(tx.payload)
rlp.read(tx.accessList)
rlp.read(tx.maxFeePerDataGas)
rlp.read(tx.versionedHashes)
rlp.read(tx.V)
rlp.read(tx.R)
rlp.read(tx.S)

proc readTxEip4844Network(rlp: var Rlp, tx: var Transaction) =
# spec: rlp([tx_payload, blobs, commitments, proofs])
rlp.tryEnterList()
rlp.readTxEip4844Signed(tx)
var np = NetworkPayload()
rlp.read(np.blobs)
rlp.read(np.commitments)
rlp.read(np.proofs)
tx.networkPayload = np

proc readTxEip4844(rlp: var Rlp, tx: var Transaction) =
tx.txType = TxEip4844
let listLen = rlp.listLen
if listLen == 4:
rlp.readTxEip4844Network(tx)
elif listLen == 14:
rlp.readTxEip4844Signed(tx)
else:
raise newException(MalformedRlpError,
"Invalid EIP-4844 transaction: listLen should be in 4 or 14, got: " & $listLen)

proc readTxTyped(rlp: var Rlp, tx: var Transaction) {.inline.} =
# EIP-2718: We MUST decode the first byte as a byte, not `rlp.read(int)`.
# If decoded with `rlp.read(int)`, bad transaction data (from the network)
Expand Down Expand Up @@ -204,12 +280,14 @@ proc readTxTyped(rlp: var Rlp, tx: var Transaction) {.inline.} =
of TxEip1559:
rlp.readTxEip1559(tx)
return
of TxEip4844:
rlp.readTxEip4844(tx)
return
else:
discard

raise newException(UnsupportedRlpError,
"TypedTransaction type must be 1 or 2 in this version, got " & $txType)

"TypedTransaction type must be 1, 2, or 3 in this version, got " & $txType)

proc read*(rlp: var Rlp, T: type Transaction): T =
# Individual transactions are encoded and stored as either `RLP([fields..])`
Expand Down Expand Up @@ -258,7 +336,7 @@ proc append*(rlpWriter: var RlpWriter,
rlpWriter.append(rlp.encode(tx))

proc append*(w: var RlpWriter, rec: Receipt) =
if rec.receiptType in {Eip2930Receipt, Eip1559Receipt}:
if rec.receiptType in {Eip2930Receipt, Eip1559Receipt, Eip4844Receipt}:
w.append(rec.receiptType.int)

w.startList(4)
Expand All @@ -276,10 +354,12 @@ proc read*(rlp: var Rlp, T: type Receipt): T =
result.receiptType = LegacyReceipt
else:
# EIP 2718
let recType = rlp.read(int)
if recType notin {1, 2}:
let recType = rlp.getByteValue
rlp.position += 1

if recType notin {1, 2, 3}:
raise newException(UnsupportedRlpError,
"TxType expect 1 or 2 got " & $recType)
"TxType expect 1, 2, or 3 got " & $recType)
result.receiptType = ReceiptType(recType)

rlp.tryEnterList()
Expand Down
25 changes: 22 additions & 3 deletions eth/common/transaction.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import
../common/eth_types_rlp
./eth_types_rlp

export eth_types_rlp

Expand Down Expand Up @@ -58,7 +58,7 @@ func rlpEncodeEip155(tx: Transaction): auto =

func rlpEncodeEip2930(tx: Transaction): auto =
var w = initRlpWriter()
w.append(1)
w.append(TxEip2930)
w.startList(8)
w.append(tx.chainId.uint64)
w.append(tx.nonce)
Expand All @@ -72,7 +72,7 @@ func rlpEncodeEip2930(tx: Transaction): auto =

func rlpEncodeEip1559(tx: Transaction): auto =
var w = initRlpWriter()
w.append(2)
w.append(TxEip1559)
w.startList(9)
w.append(tx.chainId.uint64)
w.append(tx.nonce)
Expand All @@ -85,6 +85,23 @@ func rlpEncodeEip1559(tx: Transaction): auto =
w.append(tx.accessList)
w.finish()

func rlpEncodeEip4844(tx: Transaction): auto =
var w = initRlpWriter()
w.append(TxEip4844)
w.startList(11)
w.append(tx.chainId.uint64)
w.append(tx.nonce)
w.append(tx.maxPriorityFee)
w.append(tx.maxFee)
w.append(tx.gasLimit)
w.append(tx.to)
w.append(tx.value)
w.append(tx.payload)
w.append(tx.accessList)
w.append(tx.maxFeePerDataGas)
w.append(tx.versionedHashes)
w.finish()

func rlpEncode*(tx: Transaction): auto =
case tx.txType
of TxLegacy:
Expand All @@ -96,6 +113,8 @@ func rlpEncode*(tx: Transaction): auto =
tx.rlpEncodeEip2930
of TxEip1559:
tx.rlpEncodeEip1559
of TxEip4844:
tx.rlpEncodeEip4844

func txHashNoSignature*(tx: Transaction): Hash256 =
# Hash transaction without signature
Expand Down
4 changes: 2 additions & 2 deletions eth/common/utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
# those terms.

import
std/[hashes, os],
std/[hashes],
nimcrypto/hash, stew/byteutils, metrics,
./eth_types

when defined(posix):
import std/posix
import std/[posix, os]

export metrics

Expand Down
14 changes: 12 additions & 2 deletions eth/p2p/private/p2p_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -153,18 +153,28 @@ type

# Private types:
MessageHandlerDecorator* = proc(msgId: int, n: NimNode): NimNode

ThunkProc* = proc(x: Peer, msgId: int, data: Rlp): Future[void]
{.gcsafe, raises: [RlpError].}

MessageContentPrinter* = proc(msg: pointer): string
{.gcsafe, raises: [].}

RequestResolver* = proc(msg: pointer, future: FutureBase)
{.gcsafe, raises: [].}

NextMsgResolver* = proc(msgData: Rlp, future: FutureBase)
{.gcsafe, raises: [RlpError].}
PeerStateInitializer* = proc(peer: Peer): RootRef {.gcsafe, raises: [].}

PeerStateInitializer* = proc(peer: Peer): RootRef
{.gcsafe, raises: [].}

NetworkStateInitializer* = proc(network: EthereumNode): RootRef
{.gcsafe, raises: [].}
HandshakeStep* = proc(peer: Peer): Future[void] {.gcsafe, raises: [].}

HandshakeStep* = proc(peer: Peer): Future[void]
{.gcsafe, raises: [].}

DisconnectionHandler* = proc(peer: Peer, reason: DisconnectionReason):
Future[void] {.gcsafe, raises: [].}

Expand Down
3 changes: 3 additions & 0 deletions eth/rlp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ proc currentElemEnd*(self: Rlp): int {.gcsafe.}
template rawData*(self: Rlp): openArray[byte] =
self.bytes.toOpenArray(self.position, self.currentElemEnd - 1)

template remainingBytes*(self: Rlp): openArray[byte] =
self.bytes.toOpenArray(self.position, self.bytes.len - 1)

proc isBlob*(self: Rlp): bool =
self.hasData() and self.bytes[self.position] < LIST_START_MARKER

Expand Down
14 changes: 14 additions & 0 deletions tests/common/all_tests.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Nimbus
# Copyright (c) 2023 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# https://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# https://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.

import
test_eth_types,
test_eip4844

Loading