Fix EIP-7865 types and RLP encoding

This commit is contained in:
jangko 2024-09-10 19:28:58 +07:00
parent 11eafac0f0
commit 59715353db
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
3 changed files with 158 additions and 17 deletions

View File

@ -23,11 +23,6 @@ export
eth_hash,
eth_times
const
DEPOSIT_REQUEST_TYPE* = 0x00'u8 # EIP-6110
WITHDRAWAL_REQUEST_TYPE* = 0x01'u8 # EIP-7002
CONSOLIDATION_REQUEST_TYPE* = 0x02'u8 # EIP-7251
type
Hash256* = MDigest[256]
VMWord* = UInt256
@ -170,10 +165,26 @@ type
parentBeaconBlockRoot*: Opt[Hash256] # EIP-4788
requestsRoot*: Opt[Hash256] # EIP-7685
RequestType* = enum
DepositRequestType # EIP-6110
WithdrawalRequestType # EIP-7002
ConsolidationRequestType # EIP-7251
Request* = object
case requestType*: RequestType
of DepositRequestType:
deposit*: DepositRequest
of WithdrawalRequestType:
withdrawal*: WithdrawalRequest
of ConsolidationRequestType:
consolidation*: ConsolidationRequest
BlockBody* = object
transactions*: seq[Transaction]
uncles*: seq[BlockHeader]
withdrawals*: Opt[seq[Withdrawal]] # EIP-4895
requests*: Opt[seq[Request]] # EIP-7865
Log* = object
address*: EthAddress
@ -202,6 +213,7 @@ type
transactions*: seq[Transaction]
uncles* : seq[BlockHeader]
withdrawals*: Opt[seq[Withdrawal]] # EIP-4895
requests*: Opt[seq[Request]] # EIP-7865
BlobsBundle* = object
commitments*: seq[KzgCommitment]
@ -333,3 +345,15 @@ func init*(T: type EthBlock, header: BlockHeader, body: BlockBody): T =
uncles: body.uncles,
withdrawals: body.withdrawals,
)
func `==`*(a, b: Request): bool =
if a.requestType != b.requestType:
return false
case a.requestType
of DepositRequestType:
a.deposit == b.deposit
of WithdrawalRequestType:
a.withdrawal == b.withdrawal
of ConsolidationRequestType:
a.consolidation == b.consolidation

View File

@ -516,7 +516,7 @@ proc append*(rlpWriter: var RlpWriter, t: EthTime) {.inline.} =
rlpWriter.append(t.uint64)
proc append*(rlpWriter: var RlpWriter, request: DepositRequest) =
rlpWriter.appendRawBytes([DEPOSIT_REQUEST_TYPE])
rlpWriter.appendRawBytes([DepositRequestType.byte])
rlpWriter.startList(5)
rlpWriter.append(request.pubkey)
rlpWriter.append(request.withdrawalCredentials)
@ -527,11 +527,11 @@ proc append*(rlpWriter: var RlpWriter, request: DepositRequest) =
proc read*(rlp: var Rlp, T: type DepositRequest): T =
if not rlp.hasData:
raise (ref MalformedRlpError)(msg:
"DEPOSIT_REQUEST_TYPE expected but source RLP is empty")
"DepositRequestType expected but source RLP is empty")
let reqType = rlp.readRawByte()
if reqType != DEPOSIT_REQUEST_TYPE:
if reqType != DepositRequestType:
raise (ref UnsupportedRlpError)(msg:
"Unexpected DEPOSIT_REQUEST_TYPE: " & $reqType)
"Unexpected DepositRequestType: " & $reqType)
var res: DepositRequest
rlp.tryEnterList()
@ -545,7 +545,7 @@ proc read*(rlp: var Rlp, T: type DepositRequest): T =
res
proc append*(rlpWriter: var RlpWriter, request: WithdrawalRequest) =
rlpWriter.appendRawBytes([WITHDRAWAL_REQUEST_TYPE])
rlpWriter.appendRawBytes([WithdrawalRequestType.byte])
rlpWriter.startList(3)
rlpWriter.append(request.sourceAddress)
rlpWriter.append(request.validatorPubkey)
@ -554,11 +554,11 @@ proc append*(rlpWriter: var RlpWriter, request: WithdrawalRequest) =
proc read*(rlp: var Rlp, T: type WithdrawalRequest): T =
if not rlp.hasData:
raise (ref MalformedRlpError)(msg:
"WITHDRAWAL_REQUEST_TYPE expected but source RLP is empty")
"WithdrawalRequestType expected but source RLP is empty")
let reqType = rlp.readRawByte()
if reqType != WITHDRAWAL_REQUEST_TYPE:
if reqType != WithdrawalRequestType:
raise (ref UnsupportedRlpError)(msg:
"Unexpected WITHDRAWAL_REQUEST_TYPE: " & $reqType)
"Unexpected WithdrawalRequestType: " & $reqType)
var res: WithdrawalRequest
rlp.tryEnterList()
@ -570,7 +570,7 @@ proc read*(rlp: var Rlp, T: type WithdrawalRequest): T =
res
proc append*(rlpWriter: var RlpWriter, request: ConsolidationRequest) =
rlpWriter.appendRawBytes([CONSOLIDATION_REQUEST_TYPE])
rlpWriter.appendRawBytes([ConsolidationRequestType.byte])
rlpWriter.startList(3)
rlpWriter.append(request.sourceAddress)
rlpWriter.append(request.sourcePubkey)
@ -579,11 +579,11 @@ proc append*(rlpWriter: var RlpWriter, request: ConsolidationRequest) =
proc read*(rlp: var Rlp, T: type ConsolidationRequest): T =
if not rlp.hasData:
raise (ref MalformedRlpError)(msg:
"CONSOLIDATION_REQUEST_TYPE expected but source RLP is empty")
"ConsolidationRequestType expected but source RLP is empty")
let reqType = rlp.readRawByte()
if reqType != CONSOLIDATION_REQUEST_TYPE:
if reqType != ConsolidationRequestType:
raise (ref UnsupportedRlpError)(msg:
"Unexpected CONSOLIDATION_REQUEST_TYPE: " & $reqType)
"Unexpected ConsolidationRequestType: " & $reqType)
var res: ConsolidationRequest
rlp.tryEnterList()
@ -594,6 +594,71 @@ proc read*(rlp: var Rlp, T: type ConsolidationRequest): T =
raise (ref MalformedRlpError)(msg: "Extra data after ConsolidationRequest")
res
proc append*(rlpWriter: var RlpWriter, request: Request) =
case request.requestType
of DepositRequestType:
rlpWriter.append(request.deposit)
of WithdrawalRequestType:
rlpWriter.append(request.withdrawal)
of ConsolidationRequestType:
rlpWriter.append(request.consolidation)
proc append*(
rlpWriter: var RlpWriter, reqs: seq[Request] | openArray[Request]
) =
rlpWriter.startList(reqs.len)
for req in reqs:
rlpWriter.append(rlp.encode(req))
proc read*(rlp: var Rlp, T: type Request): T =
if not rlp.hasData:
raise newException(MalformedRlpError,
"Request expected but source RLP is empty")
if not rlp.isSingleByte:
raise newException(MalformedRlpError,
"RequestType byte is out of range, must be 0x00 to 0x7f")
let reqType = rlp.getByteValue
rlp.position += 1
var reqVal: RequestType
if checkedEnumAssign(reqVal, reqType):
result = Request(requestType: reqVal)
rlp.tryEnterList()
case reqVal
of DepositRequestType:
rlp.read(result.deposit.pubkey)
rlp.read(result.deposit.withdrawalCredentials)
rlp.read(result.deposit.amount)
rlp.read(result.deposit.signature)
rlp.read(result.deposit.index)
of WithdrawalRequestType:
rlp.read(result.withdrawal.sourceAddress)
rlp.read(result.withdrawal.validatorPubkey)
rlp.read(result.withdrawal.amount)
of ConsolidationRequestType:
rlp.read(result.consolidation.sourceAddress)
rlp.read(result.consolidation.sourcePubkey)
rlp.read(result.consolidation.targetPubkey)
else:
raise (ref UnsupportedRlpError)(msg:
"Unexpected RequestType: " & $reqType)
proc read*(
rlp: var Rlp,
T: (type seq[Request]) | (type openArray[Request])
): seq[Request] =
if not rlp.isList:
raise newException(RlpTypeMismatch,
"Requests list expected, but source RLP is not a list")
var reqs: seq[Request]
for item in rlp:
var rr = rlpFromBytes(rlp.read(Blob))
reqs.add rr.read(Request)
reqs
proc rlpHash*[T](v: T): Hash256 =
keccakHash(rlp.encode(v))

View File

@ -13,6 +13,7 @@
import
std/[os, strutils],
stew/io2,
stew/byteutils,
results,
unittest2,
../../eth/[rlp, common]
@ -245,3 +246,54 @@ template genTestOpt(TT) =
genTestOpt(BlockBodyOpt)
genTestOpt(EthBlockOpt)
suite "EIP-7865 tests":
const reqs = [
Request(
requestType: DepositRequestType,
deposit: DepositRequest(
pubkey : hexToByteArray[48]("0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
withdrawalCredentials: hexToByteArray[32]("0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"),
amount : 1,
signature : hexToByteArray[96]("0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
index : 3,
)
),
Request(
requestType: WithdrawalRequestType,
withdrawal: WithdrawalRequest(
sourceAddress : hexToByteArray[20]("0xDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"),
validatorPubkey: hexToByteArray[48]("0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
amount : 7,
)
),
Request(
requestType: ConsolidationRequestType,
consolidation: ConsolidationRequest(
sourceAddress: hexToByteArray[20]("0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"),
sourcePubkey : hexToByteArray[48]("0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
targetPubkey : hexToByteArray[48]("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
)
)
]
test "rlp roundtrip":
let
body = BlockBody(
withdrawals: Opt.some(@[Withdrawal()]),
requests: Opt.some(@reqs)
)
blk = EthBlock(
withdrawals: Opt.some(@[Withdrawal()]),
requests: Opt.some(@reqs)
)
encodedBody = rlp.encode(body)
encodedBlock = rlp.encode(blk)
decodedBody = rlp.decode(encodedBody, BlockBody)
decodedBlk = rlp.decode(encodedBlock, EthBlock)
check decodedBody == body
check decodedBlk == blk