Skip to content

Commit

Permalink
new Pectra engine API (#168)
Browse files Browse the repository at this point in the history
  • Loading branch information
tersec authored Oct 10, 2024
1 parent c387918 commit 785991d
Show file tree
Hide file tree
Showing 8 changed files with 36 additions and 215 deletions.
66 changes: 0 additions & 66 deletions tests/test_execution_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,6 @@ suite "Execution types tests":
shouldOverrideBuilder: Opt.some(false),
)

deposit = DepositRequestV1(
pubkey: FixedBytes[48].conv(1),
withdrawalCredentials: FixedBytes[32].conv(3),
amount: 5.Quantity,
signature: FixedBytes[96].conv(7),
index: 9.Quantity
)

withdrawal = WithdrawalRequestV1(
sourceAddress: address(7),
validatorPubkey: FixedBytes[48].conv(9)
)

consolidation = ConsolidationRequestV1(
sourceAddress: address(8),
sourcePubkey: FixedBytes[48].conv(10),
targetPubkey: FixedBytes[48].conv(11)
)

test "payload version":
var badv31 = payload
badv31.blobGasUsed = Opt.none(Quantity)
Expand Down Expand Up @@ -170,50 +151,3 @@ suite "Execution types tests":

let v1 = response.V1
check v1 == v1.getPayloadResponse.V1

test "payload version 4":
var v4 = payload
v4.depositRequests = Opt.some(@[deposit])
v4.withdrawalRequests = Opt.some(@[withdrawal])
v4.consolidationRequests = Opt.some(@[consolidation])
check v4.version == Version.V4

var bad41 = v4
bad41.depositRequests = Opt.none(seq[DepositRequestV1])
check bad41.version == Version.V4

var bad42 = v4
bad42.withdrawalRequests = Opt.none(seq[WithdrawalRequestV1])
check bad42.version == Version.V4

var bad43 = v4
bad43.consolidationRequests = Opt.none(seq[ConsolidationRequestV1])
check bad43.version == Version.V4

let v41 = bad41.V4
check v41.depositRequests == newSeq[DepositRequestV1]()
check v41.withdrawalRequests == v4.withdrawalRequests.get
check v41.consolidationRequests == v4.consolidationRequests.get

let v42 = bad42.V4
check v42.depositRequests == v4.depositRequests.get
check v42.withdrawalRequests == newSeq[WithdrawalRequestV1]()
check v41.consolidationRequests == v4.consolidationRequests.get

let v43 = bad43.V4
check v43.depositRequests == v4.depositRequests.get
check v43.withdrawalRequests == v4.withdrawalRequests.get
check v43.consolidationRequests == newSeq[ConsolidationRequestV1]()

# roundtrip
let v4p = v4.V4
check v4p == v4p.executionPayload.V4

# response version 4
var resv4 = response
resv4.executionPayload = v4
check resv4.version == Version.V4

# response roundtrip
let rv3p = resv4.V4
check rv3p == rv3p.getPayloadResponse.V4
4 changes: 2 additions & 2 deletions web3/contract_dsl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ proc genFunction(cname: NimNode, functionObject: FunctionObject): NimNode =
`senderName`.sender, `output`,
static(keccak256(`signature`).data[0..<4]) & encode(`funcParamsTuple`))

proc `&`(a, b: openarray[byte]): seq[byte] =
proc `&`(a, b: openArray[byte]): seq[byte] =
let sza = a.len
let szb = b.len
result.setLen(sza + szb)
Expand All @@ -217,7 +217,7 @@ proc genConstructor(cname: NimNode, constructorObject: ConstructorObject): NimNo
funcParamsTuple.add(ident input.name)

result = quote do:
proc deployContract*[TSender](`sender`: TSender, contractType: typedesc[`cname`], `contractCode`: openarray[byte]): auto =
proc deployContract*[TSender](`sender`: TSender, contractType: typedesc[`cname`], `contractCode`: openArray[byte]): auto =
discard
for input in constructorObject.inputs:
result[3].add nnkIdentDefs.newTree(
Expand Down
6 changes: 1 addition & 5 deletions web3/conversions.nim
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,10 @@ derefType(ReceiptObject).useDefaultSerializationIn JrpcConv
#------------------------------------------------------------------------------

WithdrawalV1.useDefaultSerializationIn JrpcConv
DepositRequestV1.useDefaultSerializationIn JrpcConv
WithdrawalRequestV1.useDefaultSerializationIn JrpcConv
ExecutionPayloadV1.useDefaultSerializationIn JrpcConv
ExecutionPayloadV2.useDefaultSerializationIn JrpcConv
ExecutionPayloadV1OrV2.useDefaultSerializationIn JrpcConv
ExecutionPayloadV3.useDefaultSerializationIn JrpcConv
ExecutionPayloadV4.useDefaultSerializationIn JrpcConv
BlobsBundleV1.useDefaultSerializationIn JrpcConv
ExecutionPayloadBodyV1.useDefaultSerializationIn JrpcConv
PayloadAttributesV1.useDefaultSerializationIn JrpcConv
Expand All @@ -82,7 +79,6 @@ GetPayloadV2ResponseExact.useDefaultSerializationIn JrpcConv
GetPayloadV3Response.useDefaultSerializationIn JrpcConv
GetPayloadV4Response.useDefaultSerializationIn JrpcConv
ClientVersionV1.useDefaultSerializationIn JrpcConv
ConsolidationRequestV1.useDefaultSerializationIn JrpcConv

#------------------------------------------------------------------------------
# execution_types
Expand Down Expand Up @@ -329,7 +325,7 @@ proc readValue*(r: var JsonReader[JrpcConv], val: var RtBlockIdentifier)
proc writeValue*(w: var JsonWriter[JrpcConv], v: RtBlockIdentifier)
{.gcsafe, raises: [IOError].} =
case v.kind
of bidNumber: w.writeValue(v.number.Quantity)
of bidNumber: w.writeValue(v.number)
of bidAlias: w.writeValue(v.alias)

proc readValue*(r: var JsonReader[JrpcConv], val: var TxOrHash)
Expand Down
36 changes: 18 additions & 18 deletions web3/encoding.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ func encode*[bits: static[int]](x: StUint[bits]): seq[byte] =
func encode*[bits: static[int]](x: StInt[bits]): seq[byte] =
@(x.toByteArrayBE())

func decode*(input: openarray[byte], baseOffset, offset: int, to: var StUint): int =
func decode*(input: openArray[byte], baseOffset, offset: int, to: var StUint): int =
const meaningfulLen = to.bits div 8
let offset = offset + baseOffset
to = type(to).fromBytesBE(input.toOpenArray(offset, offset + meaningfulLen - 1))
meaningfulLen

func decode*[N](input: openarray[byte], baseOffset, offset: int, to: var StInt[N]): int =
func decode*[N](input: openArray[byte], baseOffset, offset: int, to: var StInt[N]): int =
const meaningfulLen = N div 8
let offset = offset + baseOffset
to = type(to).fromBytesBE(input.toOpenArray(offset, offset + meaningfulLen - 1))
Expand All @@ -39,7 +39,7 @@ func encode*[N: static int](b: FixedBytes[N]): seq[byte] = encodeFixed(b.data)
func encode*(b: Address): seq[byte] = encodeFixed(b.data)
func encode*[N](b: array[N, byte]): seq[byte] {.inline.} = encodeFixed(b)

func decodeFixed(input: openarray[byte], baseOffset, offset: int, to: var openArray[byte]): int =
func decodeFixed(input: openArray[byte], baseOffset, offset: int, to: var openArray[byte]): int =
let meaningfulLen = to.len
var padding = to.len mod 32
if padding != 0:
Expand All @@ -49,10 +49,10 @@ func decodeFixed(input: openarray[byte], baseOffset, offset: int, to: var openAr
assign(to, input.toOpenArray(offset, offset + meaningfulLen - 1))
meaningfulLen + padding

func decode*[N](input: openarray[byte], baseOffset, offset: int, to: var FixedBytes[N]): int {.inline.} =
func decode*[N](input: openArray[byte], baseOffset, offset: int, to: var FixedBytes[N]): int {.inline.} =
decodeFixed(input, baseOffset, offset, array[N, byte](to))

func decode*(input: openarray[byte], baseOffset, offset: int, to: var Address): int {.inline.} =
func decode*(input: openArray[byte], baseOffset, offset: int, to: var Address): int {.inline.} =
decodeFixed(input, baseOffset, offset, array[20, byte](to))

func encodeDynamic(v: openArray[byte]): seq[byte] =
Expand All @@ -71,7 +71,7 @@ func encode*(x: seq[byte]): seq[byte] {.inline.} =
func encode*(x: string): seq[byte] {.inline.} =
encodeDynamic(x.toOpenArrayByte(0, x.high))

func decode*(input: openarray[byte], baseOffset, offset: int, to: var seq[byte]): int =
func decode*(input: openArray[byte], baseOffset, offset: int, to: var seq[byte]): int =
var dataOffsetBig, dataLenBig: UInt256
result = decode(input, baseOffset, offset, dataOffsetBig)
let dataOffset = dataOffsetBig.truncate(int)
Expand All @@ -80,7 +80,7 @@ func decode*(input: openarray[byte], baseOffset, offset: int, to: var seq[byte])
let actualDataOffset = baseOffset + dataOffset + 32
to = input[actualDataOffset ..< actualDataOffset + dataLen]

func decode*(input: openarray[byte], baseOffset, offset: int, to: var string): int =
func decode*(input: openArray[byte], baseOffset, offset: int, to: var string): int =
var dataOffsetBig, dataLenBig: UInt256
result = decode(input, baseOffset, offset, dataOffsetBig)
let dataOffset = dataOffsetBig.truncate(int)
Expand All @@ -89,15 +89,15 @@ func decode*(input: openarray[byte], baseOffset, offset: int, to: var string): i
let actualDataOffset = baseOffset + dataOffset + 32
to = string.fromBytes(input.toOpenArray(actualDataOffset, actualDataOffset + dataLen - 1))

func decode*(input: openarray[byte], baseOffset, offset: int, to: var DynamicBytes): int {.inline.} =
func decode*(input: openArray[byte], baseOffset, offset: int, to: var DynamicBytes): int {.inline.} =
var s: seq[byte]
result = decode(input, baseOffset, offset, s)
# TODO: Check data len, and raise?
to = typeof(to)(move(s))

func decode*(input: openarray[byte], baseOffset, offset: int, obj: var object): int
func decode*(input: openArray[byte], baseOffset, offset: int, obj: var object): int

func decode*[T](input: openarray[byte], baseOffset, offset: int, to: var seq[T]): int {.inline.} =
func decode*[T](input: openArray[byte], baseOffset, offset: int, to: var seq[T]): int {.inline.} =
var dataOffsetBig, dataLenBig: UInt256
result = decode(input, baseOffset, offset, dataOffsetBig)
let dataOffset = dataOffsetBig.truncate(int)
Expand All @@ -110,31 +110,31 @@ func decode*[T](input: openarray[byte], baseOffset, offset: int, to: var seq[T])
for i in 0 ..< dataLen:
offset += decode(input, baseOffset, offset, to[i])

proc isDynamicObject(T: typedesc): bool
func isDynamicObject(T: typedesc): bool

template isDynamicType(a: typedesc): bool =
when a is seq | openarray | string | DynamicBytes:
when a is seq | openArray | string | DynamicBytes:
true
elif a is object:
const r = isDynamicObject(a)
r
else:
false

proc isDynamicObject(T: typedesc): bool =
func isDynamicObject(T: typedesc): bool =
var a: T
for v in fields(a):
if isDynamicType(typeof(v)): return true
false

func encode*(x: bool): seq[byte] = encode(x.int.u256)

func decode*(input: openarray[byte], baseOffset, offset: int, to: var bool): int =
func decode*(input: openArray[byte], baseOffset, offset: int, to: var bool): int =
var i: Int256
result = decode(input, baseOffset, offset, i)
to = not i.isZero()

func decode*(input: openarray[byte], baseOffset, offset: int, obj: var object): int =
func decode*(input: openArray[byte], baseOffset, offset: int, obj: var object): int =
when isDynamicObject(typeof(obj)):
var dataOffsetBig: UInt256
result = decode(input, baseOffset, offset, dataOffsetBig)
Expand All @@ -153,7 +153,7 @@ func decode*(input: openarray[byte], baseOffset, offset: int, obj: var object):

func encode*(x: tuple): seq[byte]

func encode*[T](x: openarray[T]): seq[byte] =
func encode*[T](x: openArray[T]): seq[byte] =
result = encode(x.len.u256)
when isDynamicType(T):
result.setLen((1 + x.len) * 32)
Expand All @@ -165,7 +165,7 @@ func encode*[T](x: openarray[T]): seq[byte] =
for i in 0 ..< x.len:
result &= encode(x[i])

proc getTupleImpl(t: NimNode): NimNode =
func getTupleImpl(t: NimNode): NimNode =
getTypeImpl(t)[1].getTypeImpl()

macro typeListLen*(t: typedesc[tuple]): int =
Expand All @@ -191,5 +191,5 @@ func encode*(x: tuple): seq[byte] =
inc i

# Obsolete
func decode*(input: string, offset: int, to: var DynamicBytes): int {.inline, deprecated: "Use decode(openarray[byte], ...) instead".} =
func decode*(input: string, offset: int, to: var DynamicBytes): int {.inline, deprecated: "Use decode(openArray[byte], ...) instead".} =
decode(hexToSeqByte(input), 0, offset div 2, to) * 2
13 changes: 3 additions & 10 deletions web3/engine_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ createRpcSigsFromNim(RpcClient):
proc engine_newPayloadV1(payload: ExecutionPayloadV1): PayloadStatusV1
proc engine_newPayloadV2(payload: ExecutionPayloadV2): PayloadStatusV1
proc engine_newPayloadV3(payload: ExecutionPayloadV3, expectedBlobVersionedHashes: seq[VersionedHash], parentBeaconBlockRoot: Hash32): PayloadStatusV1
proc engine_newPayloadV4(payload: ExecutionPayloadV4, expectedBlobVersionedHashes: seq[VersionedHash], parentBeaconBlockRoot: Hash32): PayloadStatusV1
proc engine_newPayloadV4(payload: ExecutionPayloadV3, expectedBlobVersionedHashes: seq[VersionedHash], parentBeaconBlockRoot: Hash32, executionRequests: array[3, seq[byte]]): PayloadStatusV1
proc engine_forkchoiceUpdatedV1(forkchoiceState: ForkchoiceStateV1, payloadAttributes: Opt[PayloadAttributesV1]): ForkchoiceUpdatedResponse
proc engine_forkchoiceUpdatedV2(forkchoiceState: ForkchoiceStateV1, payloadAttributes: Opt[PayloadAttributesV2]): ForkchoiceUpdatedResponse
proc engine_forkchoiceUpdatedV3(forkchoiceState: ForkchoiceStateV1, payloadAttributes: Opt[PayloadAttributesV3]): ForkchoiceUpdatedResponse
Expand All @@ -54,7 +54,8 @@ createRpcSigsFromNim(RpcClient):
parentBeaconBlockRoot: Opt[Hash32]): PayloadStatusV1
proc engine_newPayloadV4(payload: ExecutionPayload,
expectedBlobVersionedHashes: Opt[seq[VersionedHash]],
parentBeaconBlockRoot: Opt[Hash32]): PayloadStatusV1
parentBeaconBlockRoot: Opt[Hash32],
executionRequests: Opt[array[3, seq[byte]]]): PayloadStatusV1
proc engine_forkchoiceUpdatedV2(forkchoiceState: ForkchoiceStateV1, payloadAttributes: Opt[PayloadAttributes]): ForkchoiceUpdatedResponse
proc engine_forkchoiceUpdatedV3(forkchoiceState: ForkchoiceStateV1, payloadAttributes: Opt[PayloadAttributes]): ForkchoiceUpdatedResponse

Expand Down Expand Up @@ -124,14 +125,6 @@ template newPayload*(
engine_newPayloadV3(
rpcClient, payload, versionedHashes, parentBeaconBlockRoot)

template newPayload*(
rpcClient: RpcClient,
payload: ExecutionPayloadV4,
versionedHashes: seq[VersionedHash],
parentBeaconBlockRoot: Hash32): Future[PayloadStatusV1] =
engine_newPayloadV4(
rpcClient, payload, versionedHashes, parentBeaconBlockRoot)

template exchangeCapabilities*(
rpcClient: RpcClient,
methods: seq[string]): Future[seq[string]] =
Expand Down
52 changes: 4 additions & 48 deletions web3/engine_api_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,6 @@ type
address*: Address
amount*: Quantity

# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.4/src/engine/prague.md#depositrequestv1
DepositRequestV1* = object
pubkey*: Bytes48
withdrawalCredentials*: Bytes32
amount*: Quantity
signature*: Bytes96
index*: Quantity

# https://github.com/nflaig/execution-apis/blob/update-withdrawal-request/src/engine/prague.md#withdrawalrequestv1
WithdrawalRequestV1* = object
sourceAddress*: Address
validatorPubkey*: Bytes48
amount*: Quantity

# https://github.com/ethereum/execution-apis/blob/3ae3d29fc9900e5c48924c238dff7643fdc3680e/src/engine/prague.md#consolidationrequestv1
ConsolidationRequestV1* = object
sourceAddress*: Address
sourcePubkey*: Bytes48
targetPubkey*: Bytes48

# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.4/src/engine/paris.md#executionpayloadv1
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.4/src/engine/openrpc/schemas/payload.yaml#L51
ExecutionPayloadV1* = object
Expand Down Expand Up @@ -136,35 +116,10 @@ type
blobGasUsed*: Quantity
excessBlobGas*: Quantity

# https://github.com/ethereum/execution-apis/blob/3ae3d29fc9900e5c48924c238dff7643fdc3680e/src/engine/prague.md#executionpayloadv4
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.4/src/engine/openrpc/schemas/payload.yaml#L246
ExecutionPayloadV4* = object
parentHash*: Hash32
feeRecipient*: Address
stateRoot*: Hash32
receiptsRoot*: Hash32
logsBloom*: Bytes256
prevRandao*: Bytes32
blockNumber*: Quantity
gasLimit*: Quantity
gasUsed*: Quantity
timestamp*: Quantity
extraData*: DynamicBytes[0, 32]
baseFeePerGas*: UInt256
blockHash*: Hash32
transactions*: seq[TypedTransaction]
withdrawals*: seq[WithdrawalV1]
blobGasUsed*: Quantity
excessBlobGas*: Quantity
depositRequests*: seq[DepositRequestV1]
withdrawalRequests*: seq[WithdrawalRequestV1]
consolidationRequests*: seq[ConsolidationRequestV1]

SomeExecutionPayload* =
ExecutionPayloadV1 |
ExecutionPayloadV2 |
ExecutionPayloadV3 |
ExecutionPayloadV4
ExecutionPayloadV3

# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.4/src/engine/cancun.md#blobsbundlev1
BlobsBundleV1* = object
Expand Down Expand Up @@ -260,12 +215,13 @@ type
blobsBundle*: BlobsBundleV1
shouldOverrideBuilder*: bool

# https://github.com/ethereum/execution-apis/blob/90a46e9137c89d58e818e62fa33a0347bba50085/src/engine/prague.md#response-1
# https://github.com/ethereum/execution-apis/blob/4140e528360fea53c34a766d86a000c6c039100e/src/engine/prague.md#response-1
GetPayloadV4Response* = object
executionPayload*: ExecutionPayloadV4
executionPayload*: ExecutionPayloadV3
blockValue*: UInt256
blobsBundle*: BlobsBundleV1
shouldOverrideBuilder*: bool
executionRequests*: array[3, seq[byte]]

SomeGetPayloadResponse* =
ExecutionPayloadV1 |
Expand Down
Loading

0 comments on commit 785991d

Please sign in to comment.