mirror of https://github.com/status-im/nim-eth.git
Fix EIP-7865 types and RLP encoding
This commit is contained in:
parent
11eafac0f0
commit
59715353db
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue