nim-eth/eth/common/blocks_rlp.nim

158 lines
5.3 KiB
Nim

# eth
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.push raises: [].}
import ./[addresses_rlp, blocks, base_rlp, hashes_rlp], ../rlp
from stew/objects import checkedEnumAssign
export addresses_rlp, blocks, base_rlp, hashes_rlp, rlp
proc append*(rlpWriter: var RlpWriter, request: DepositRequest) =
rlpWriter.appendRawBytes([DepositRequestType.byte])
rlpWriter.startList(5)
rlpWriter.append(request.pubkey)
rlpWriter.append(request.withdrawalCredentials)
rlpWriter.append(request.amount)
rlpWriter.append(request.signature)
rlpWriter.append(request.index)
proc read*(rlp: var Rlp, T: type DepositRequest): T {.raises: [RlpError].} =
if not rlp.hasData:
raise (ref MalformedRlpError)(
msg: "DepositRequestType expected but source RLP is empty"
)
let reqType = rlp.readRawByte()
if reqType != DepositRequestType:
raise (ref UnsupportedRlpError)(msg: "Unexpected DepositRequestType: " & $reqType)
var res: DepositRequest
rlp.tryEnterList()
rlp.read(res.pubkey)
rlp.read(res.withdrawalCredentials)
rlp.read(res.amount)
rlp.read(res.signature)
rlp.read(res.index)
if rlp.hasData:
raise (ref MalformedRlpError)(msg: "Extra data after DepositRequest")
res
proc append*(rlpWriter: var RlpWriter, request: WithdrawalRequest) =
rlpWriter.appendRawBytes([WithdrawalRequestType.byte])
rlpWriter.startList(3)
rlpWriter.append(request.sourceAddress)
rlpWriter.append(request.validatorPubkey)
rlpWriter.append(request.amount)
proc read*(rlp: var Rlp, T: type WithdrawalRequest): T {.raises: [RlpError].} =
if not rlp.hasData:
raise (ref MalformedRlpError)(
msg: "WithdrawalRequestType expected but source RLP is empty"
)
let reqType = rlp.readRawByte()
if reqType != WithdrawalRequestType:
raise
(ref UnsupportedRlpError)(msg: "Unexpected WithdrawalRequestType: " & $reqType)
var res: WithdrawalRequest
rlp.tryEnterList()
rlp.read(res.sourceAddress)
rlp.read(res.validatorPubkey)
rlp.read(res.amount)
if rlp.hasData:
raise (ref MalformedRlpError)(msg: "Extra data after WithdrawalRequest")
res
proc append*(rlpWriter: var RlpWriter, request: ConsolidationRequest) =
rlpWriter.appendRawBytes([ConsolidationRequestType.byte])
rlpWriter.startList(3)
rlpWriter.append(request.sourceAddress)
rlpWriter.append(request.sourcePubkey)
rlpWriter.append(request.targetPubkey)
proc read*(rlp: var Rlp, T: type ConsolidationRequest): T {.raises: [RlpError].} =
if not rlp.hasData:
raise (ref MalformedRlpError)(
msg: "ConsolidationRequestType expected but source RLP is empty"
)
let reqType = rlp.readRawByte()
if reqType != ConsolidationRequestType:
raise
(ref UnsupportedRlpError)(msg: "Unexpected ConsolidationRequestType: " & $reqType)
var res: ConsolidationRequest
rlp.tryEnterList()
rlp.read(res.sourceAddress)
rlp.read(res.sourcePubkey)
rlp.read(res.targetPubkey)
if rlp.hasData:
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 {.raises: [RlpError].} =
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] {.raises: [RlpError].} =
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(seq[byte]))
reqs.add rr.read(Request)
reqs