add helpers for processing withdrawals to `libnimbus_lc.a` (#5374)

Similar to the existing helpers for processing transactions / receipts,
extend `libnimbus_lc.a` with support for processing withdrawals as well.
This commit is contained in:
Etan Kissling 2023-09-04 20:44:03 +02:00 committed by GitHub
parent 41ce581149
commit be9ecfa1c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 341 additions and 6 deletions

View File

@ -1080,6 +1080,26 @@ ETH_RESULT_USE_CHECK
const ETHRoot *ETHExecutionBlockHeaderGetWithdrawalsRoot(
const ETHExecutionBlockHeader *executionBlockHeader);
/**
* Withdrawal sequence.
*/
typedef struct ETHWithdrawals ETHWithdrawals;
/**
* Obtains the withdrawal sequence of a given execution block header.
*
* - The returned value is allocated in the given execution block header.
* It must neither be released nor written to, and the execution block
* header must not be released while the returned value is in use.
*
* @param executionBlockHeader Execution block header.
*
* @return Withdrawal sequence.
*/
ETH_RESULT_USE_CHECK
const ETHWithdrawals *ETHExecutionBlockHeaderGetWithdrawals(
const ETHExecutionBlockHeader *executionBlockHeader);
/**
* Transaction sequence.
*/
@ -1765,6 +1785,114 @@ const void *ETHReceiptGetBytes(
const ETHReceipt *receipt,
int *numBytes);
/**
* Indicates the total number of withdrawals in a withdrawal sequence.
*
* - Individual withdrawals may be investigated using `ETHWithdrawalsGet`.
*
* @param withdrawals Withdrawal sequence.
*
* @return Number of available withdrawals.
*/
ETH_RESULT_USE_CHECK
int ETHWithdrawalsGetCount(const ETHWithdrawals *withdrawals);
/**
* Withdrawal.
*/
typedef struct ETHWithdrawal ETHWithdrawal;
/**
* Obtains an individual withdrawal by sequential index
* in a withdrawal sequence.
*
* - The returned value is allocated in the given withdrawal sequence.
* It must neither be released nor written to, and the withdrawal
* sequence must not be released while the returned value is in use.
*
* @param withdrawals Withdrawal sequence.
* @param withdrawalIndex Sequential withdrawal index.
*
* @return Withdrawal.
*/
ETH_RESULT_USE_CHECK
const ETHWithdrawal *ETHWithdrawalsGet(
const ETHWithdrawals *withdrawals,
int withdrawalIndex);
/**
* Obtains the index of a withdrawal.
*
* - The returned value is allocated in the given withdrawal.
* It must neither be released nor written to, and the withdrawal
* must not be released while the returned value is in use.
*
* @param withdrawal Withdrawal.
*
* @return Index.
*/
ETH_RESULT_USE_CHECK
const uint64_t *ETHWithdrawalGetIndex(const ETHWithdrawal *withdrawal);
/**
* Obtains the validator index of a withdrawal.
*
* - The returned value is allocated in the given withdrawal.
* It must neither be released nor written to, and the withdrawal
* must not be released while the returned value is in use.
*
* @param withdrawal Withdrawal.
*
* @return Validator index.
*/
ETH_RESULT_USE_CHECK
const uint64_t *ETHWithdrawalGetValidatorIndex(const ETHWithdrawal *withdrawal);
/**
* Obtains the address of a withdrawal.
*
* - The returned value is allocated in the given withdrawal.
* It must neither be released nor written to, and the withdrawal
* must not be released while the returned value is in use.
*
* @param withdrawal Withdrawal.
*
* @return Address.
*/
ETH_RESULT_USE_CHECK
const ETHExecutionAddress *ETHWithdrawalGetAddress(const ETHWithdrawal *withdrawal);
/**
* Obtains the amount of a withdrawal.
*
* - The returned value is allocated in the given withdrawal.
* It must neither be released nor written to, and the withdrawal
* must not be released while the returned value is in use.
*
* @param withdrawal Withdrawal.
*
* @return Amount.
*/
ETH_RESULT_USE_CHECK
const uint64_t *ETHWithdrawalGetAmount(const ETHWithdrawal *withdrawal);
/**
* Obtains the raw byte representation of a withdrawal.
*
* - The returned value is allocated in the given withdrawal.
* It must neither be released nor written to, and the withdrawal
* must not be released while the returned value is in use.
*
* @param withdrawal Withdrawal.
* @param[out] numBytes Length of buffer.
*
* @return Buffer with raw withdrawal data.
*/
ETH_RESULT_USE_CHECK
const void *ETHWithdrawalGetBytes(
const ETHWithdrawal *withdrawal,
int *numBytes);
#if __has_feature(nullability)
#pragma clang assume_nonnull end
#endif

View File

@ -1169,9 +1169,18 @@ func ETHExecutionPayloadHeaderGetExcessBlobGas(
## * Excess blob gas.
execution[].excess_blob_gas.cint
type ETHExecutionBlockHeader = object
transactionsRoot: Eth2Digest
withdrawalsRoot: Eth2Digest
type
ETHWithdrawal = object
index: uint64
validatorIndex: uint64
address: ExecutionAddress
amount: uint64
bytes: seq[byte]
ETHExecutionBlockHeader = object
transactionsRoot: Eth2Digest
withdrawalsRoot: Eth2Digest
withdrawals: seq[ETHWithdrawal]
proc ETHExecutionBlockHeaderCreateFromJson(
executionHash: ptr Eth2Digest,
@ -1277,10 +1286,51 @@ proc ETHExecutionBlockHeaderCreateFromJson(
if rlpHash(blockHeader) != executionHash[]:
return nil
# Construct withdrawals
var wds: seq[ETHWithdrawal]
if data.withdrawals.isSome:
doAssert data.withdrawalsRoot.isSome # Checked above
wds = newSeqOfCap[ETHWithdrawal](data.withdrawals.get.len)
for data in data.withdrawals.get:
# Check fork consistency
static: doAssert totalSerializedFields(WithdrawalObject) == 4,
"Only update this number once code is adjusted to check new fields!"
# Construct withdrawal
let
wd = ExecutionWithdrawal(
index: distinctBase(data.index),
validatorIndex: distinctBase(data.validatorIndex),
address: distinctBase(data.address),
amount: distinctBase(data.amount))
rlpBytes =
try:
rlp.encode(wd)
except RlpError:
raiseAssert "Unreachable"
wds.add ETHWithdrawal(
index: wd.index,
validatorIndex: wd.validatorIndex,
address: ExecutionAddress(data: wd.address),
amount: wd.amount,
bytes: rlpBytes)
var tr = initHexaryTrie(newMemoryDB())
for i, wd in wds:
try:
tr.put(rlp.encode(i), wd.bytes)
except RlpError:
raiseAssert "Unreachable"
if tr.rootHash() != data.withdrawalsRoot.get.asEth2Digest:
return nil
let executionBlockHeader = ETHExecutionBlockHeader.new()
executionBlockHeader[] = ETHExecutionBlockHeader(
transactionsRoot: blockHeader.txRoot,
withdrawalsRoot: blockHeader.withdrawalsRoot.get(ZERO_HASH))
withdrawalsRoot: blockHeader.withdrawalsRoot.get(ZERO_HASH),
withdrawals: wds)
executionBlockHeader.toUnmanagedPtr()
proc ETHExecutionBlockHeaderDestroy(
@ -1325,6 +1375,22 @@ func ETHExecutionBlockHeaderGetWithdrawalsRoot(
## * Execution withdrawals root.
addr executionBlockHeader[].withdrawalsRoot
func ETHExecutionBlockHeaderGetWithdrawals(
executionBlockHeader: ptr ETHExecutionBlockHeader
): ptr seq[ETHWithdrawal] {.exported.} =
## Obtains the withdrawal sequence of a given execution block header.
##
## * The returned value is allocated in the given execution block header.
## It must neither be released nor written to, and the execution block
## header must not be released while the returned value is in use.
##
## Parameters:
## * `executionBlockHeader` - Execution block header.
##
## Returns:
## * Withdrawal sequence.
addr executionBlockHeader[].withdrawals
type
ETHAccessTuple = object
address: ExecutionAddress
@ -2391,3 +2457,116 @@ func ETHReceiptGetBytes(
const defaultBytes: cstring = ""
return cast[ptr UncheckedArray[byte]](defaultBytes)
cast[ptr UncheckedArray[byte]](addr distinctBase(receipt[].bytes)[0])
func ETHWithdrawalsGetCount(
withdrawals: ptr seq[ETHWithdrawal]): cint {.exported.} =
## Indicates the total number of withdrawals in a withdrawal sequence.
##
## * Individual withdrawals may be investigated using `ETHWithdrawalsGet`.
##
## Parameters:
## * `withdrawals` - Withdrawal sequence.
##
## Returns:
## * Number of available withdrawals.
withdrawals[].len.cint
func ETHWithdrawalsGet(
withdrawals: ptr seq[ETHWithdrawal],
withdrawalIndex: cint): ptr ETHWithdrawal {.exported.} =
## Obtains an individual withdrawal by sequential index
## in a withdrawal sequence.
##
## * The returned value is allocated in the given withdrawal sequence.
## It must neither be released nor written to, and the withdrawal
## sequence must not be released while the returned value is in use.
##
## Parameters:
## * `withdrawals` - Withdrawal sequence.
## * `withdrawalIndex` - Sequential withdrawal index.
##
## Returns:
## * Withdrawal.
addr withdrawals[][withdrawalIndex.int]
func ETHWithdrawalGetIndex(
withdrawal: ptr ETHWithdrawal): ptr uint64 {.exported.} =
## Obtains the index of a withdrawal.
##
## * The returned value is allocated in the given withdrawal.
## It must neither be released nor written to, and the withdrawal
## must not be released while the returned value is in use.
##
## Parameters:
## * `withdrawal` - Withdrawal.
##
## Returns:
## * Index.
addr withdrawal[].index
func ETHWithdrawalGetValidatorIndex(
withdrawal: ptr ETHWithdrawal): ptr uint64 {.exported.} =
## Obtains the validator index of a withdrawal.
##
## * The returned value is allocated in the given withdrawal.
## It must neither be released nor written to, and the withdrawal
## must not be released while the returned value is in use.
##
## Parameters:
## * `withdrawal` - Withdrawal.
##
## Returns:
## * Validator index.
addr withdrawal[].validatorIndex
func ETHWithdrawalGetAddress(
withdrawal: ptr ETHWithdrawal): ptr ExecutionAddress {.exported.} =
## Obtains the address of a withdrawal.
##
## * The returned value is allocated in the given withdrawal.
## It must neither be released nor written to, and the withdrawal
## must not be released while the returned value is in use.
##
## Parameters:
## * `withdrawal` - Withdrawal.
##
## Returns:
## * Address.
addr withdrawal[].address
func ETHWithdrawalGetAmount(
withdrawal: ptr ETHWithdrawal): ptr uint64 {.exported.} =
## Obtains the amount of a withdrawal.
##
## * The returned value is allocated in the given withdrawal.
## It must neither be released nor written to, and the withdrawal
## must not be released while the returned value is in use.
##
## Parameters:
## * `withdrawal` - Withdrawal.
##
## Returns:
## * Amount.
addr withdrawal[].amount
func ETHWithdrawalGetBytes(
withdrawal: ptr ETHWithdrawal,
numBytes #[out]#: ptr cint): ptr UncheckedArray[byte] {.exported.} =
## Obtains the raw byte representation of a withdrawal.
##
## * The returned value is allocated in the given withdrawal.
## It must neither be released nor written to, and the withdrawal
## must not be released while the returned value is in use.
##
## Parameters:
## * `withdrawal` - Withdrawal.
## * `numBytes` [out] - Length of buffer.
##
## Returns:
## * Buffer with raw withdrawal data.
numBytes[] = distinctBase(withdrawal[].bytes).len.cint
if distinctBase(withdrawal[].bytes).len == 0:
# https://github.com/nim-lang/Nim/issues/22389
const defaultBytes: cstring = ""
return cast[ptr UncheckedArray[byte]](defaultBytes)
cast[ptr UncheckedArray[byte]](addr distinctBase(withdrawal[].bytes)[0])

View File

@ -375,7 +375,7 @@ int main(void)
ETHRootDestroy(copiedExecutionHash);
ETHLightClientHeaderDestroy(copiedHeader);
printf("- finalized_header (execution block header):\n");
printf("\nFinalized_header (execution block header):\n");
const ETHRoot *executionTransactionsRoot =
ETHExecutionBlockHeaderGetTransactionsRoot(executionBlockHeader);
@ -389,6 +389,34 @@ int main(void)
printHexString(executionWithdrawalsRoot, sizeof *executionWithdrawalsRoot);
printf("\n");
const ETHWithdrawals *withdrawals =
ETHExecutionBlockHeaderGetWithdrawals(executionBlockHeader);
int numWithdrawals = ETHWithdrawalsGetCount(withdrawals);
printf(" - withdrawals:\n");
for (int withdrawalIndex = 0; withdrawalIndex < numWithdrawals; withdrawalIndex++) {
const ETHWithdrawal *withdrawal = ETHWithdrawalsGet(withdrawals, withdrawalIndex);
const uint64_t *index = ETHWithdrawalGetIndex(withdrawal);
printf(" - index: %" PRIu64 "\n", *index);
const uint64_t *validatorIndex = ETHWithdrawalGetValidatorIndex(withdrawal);
printf(" - validator_index: %" PRIu64 "\n", *validatorIndex);
const ETHExecutionAddress *address = ETHWithdrawalGetAddress(withdrawal);
printf(" - address: ");
printHexString(address, sizeof *address);
printf("\n");
const uint64_t *amount = ETHWithdrawalGetAmount(withdrawal);
printf(" - amount: %" PRIu64 "\n", *amount);
int numBytes;
const void *bytes = ETHWithdrawalGetBytes(withdrawal, &numBytes);
printf(" - bytes: ");
printHexString(bytes, numBytes);
printf("\n");
}
ETHExecutionBlockHeaderDestroy(executionBlockHeader);
ETHRoot sampleTransactionsRoot = {{

View File

@ -34,7 +34,7 @@ type
ExecutionHash256* = eth_types.Hash256
ExecutionTransaction* = eth_types.Transaction
ExecutionReceipt* = eth_types.Receipt
ExecutionWithdrawal = eth_types.Withdrawal
ExecutionWithdrawal* = eth_types.Withdrawal
ExecutionBlockHeader* = eth_types.BlockHeader
FinalityCheckpoints* = object