define Electra types and RLP encoding (#711)

Add types for EIP-6110, EIP-7002 and EIP-7251 validator operations.
This commit is contained in:
Etan Kissling 2024-07-03 13:22:18 +02:00 committed by GitHub
parent b90483e9d2
commit d8fda55c79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 110 additions and 0 deletions

View File

@ -23,6 +23,11 @@ export
eth_hash, eth_hash,
eth_times 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 type
Hash256* = MDigest[256] Hash256* = MDigest[256]
VMWord* = UInt256 VMWord* = UInt256
@ -124,6 +129,23 @@ type
address* : EthAddress address* : EthAddress
amount* : uint64 amount* : uint64
DepositRequest* = object # EIP-6110
pubkey* : array[48, byte]
withdrawalCredentials*: array[32, byte]
amount* : uint64
signature* : array[96, byte]
index* : uint64
WithdrawalRequest* = object # EIP-7002
sourceAddress* : array[20, byte]
validatorPubkey*: array[48, byte]
amount* : uint64
ConsolidationRequest* = object # EIP-7251
sourceAddress*: array[20, byte]
sourcePubkey* : array[48, byte]
targetPubkey* : array[48, byte]
# https://eips.ethereum.org/EIPS/eip-4844#header-extension # https://eips.ethereum.org/EIPS/eip-4844#header-extension
BlockHeader* = object BlockHeader* = object
parentHash*: Hash256 parentHash*: Hash256
@ -146,6 +168,7 @@ type
blobGasUsed*: Opt[uint64] # EIP-4844 blobGasUsed*: Opt[uint64] # EIP-4844
excessBlobGas*: Opt[uint64] # EIP-4844 excessBlobGas*: Opt[uint64] # EIP-4844
parentBeaconBlockRoot*: Opt[Hash256] # EIP-4788 parentBeaconBlockRoot*: Opt[Hash256] # EIP-4788
requestsRoot*: Opt[Hash256] # EIP-7685
BlockBody* = object BlockBody* = object
transactions*: seq[Transaction] transactions*: seq[Transaction]

View File

@ -527,6 +527,85 @@ proc read*(rlp: var Rlp, T: type HashOrNum): T =
proc append*(rlpWriter: var RlpWriter, t: EthTime) {.inline.} = proc append*(rlpWriter: var RlpWriter, t: EthTime) {.inline.} =
rlpWriter.append(t.uint64) rlpWriter.append(t.uint64)
proc append*(rlpWriter: var RlpWriter, request: DepositRequest) =
rlpWriter.appendRawBytes([DEPOSIT_REQUEST_TYPE])
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 =
if not rlp.hasData:
raise (ref MalformedRlpError)(msg:
"DEPOSIT_REQUEST_TYPE expected but source RLP is empty")
let reqType = rlp.readRawByte()
if reqType != DEPOSIT_REQUEST_TYPE:
raise (ref UnsupportedRlpError)(msg:
"Unexpected DEPOSIT_REQUEST_TYPE: " & $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([WITHDRAWAL_REQUEST_TYPE])
rlpWriter.startList(3)
rlpWriter.append(request.sourceAddress)
rlpWriter.append(request.validatorPubkey)
rlpWriter.append(request.amount)
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")
let reqType = rlp.readRawByte()
if reqType != WITHDRAWAL_REQUEST_TYPE:
raise (ref UnsupportedRlpError)(msg:
"Unexpected WITHDRAWAL_REQUEST_TYPE: " & $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([CONSOLIDATION_REQUEST_TYPE])
rlpWriter.startList(3)
rlpWriter.append(request.sourceAddress)
rlpWriter.append(request.sourcePubkey)
rlpWriter.append(request.targetPubkey)
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")
let reqType = rlp.readRawByte()
if reqType != CONSOLIDATION_REQUEST_TYPE:
raise (ref UnsupportedRlpError)(msg:
"Unexpected CONSOLIDATION_REQUEST_TYPE: " & $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 rlpHash*[T](v: T): Hash256 = proc rlpHash*[T](v: T): Hash256 =
keccakHash(rlp.encode(v)) keccakHash(rlp.encode(v))

View File

@ -217,6 +217,14 @@ func getByteValue*(self: Rlp): byte =
doAssert self.isSingleByte() doAssert self.isSingleByte()
self.bytes[self.position] self.bytes[self.position]
func readRawByte*(self: var Rlp): byte =
### Read a raw byte that is not RLP encoded
### This is sometimes used to communicate union type information
doAssert self.hasData
let res = self.bytes[self.position]
inc self.position
res
func blobLen*(self: Rlp): int = func blobLen*(self: Rlp): int =
if self.isBlob(): if self.isBlob():
self.item().payload.len() self.item().payload.len()