Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
101 lines
4.1 KiB
Solidity
101 lines
4.1 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.23;
|
|
|
|
/**
|
|
* @title RLPReader — minimal Recursive-Length-Prefix decoder for MPT node parsing.
|
|
*
|
|
* @dev Operates on `bytes memory`. Just enough to walk Ethereum trie nodes:
|
|
* decode an item header, split a list into its raw element items, and read
|
|
* a string item's content. Rejects malformed / truncated input.
|
|
*/
|
|
library RLPReader {
|
|
struct Item {
|
|
uint256 offset; // byte offset of the item header within `data`
|
|
uint256 headerLen; // length of the length-prefix header
|
|
uint256 payloadLen; // length of the payload
|
|
bool isList;
|
|
}
|
|
|
|
/// @notice Decode the RLP item header starting at `pos` in `data`.
|
|
function itemAt(bytes memory data, uint256 pos) internal pure returns (Item memory it) {
|
|
require(pos < data.length, "RLP:oob");
|
|
uint256 b = uint8(data[pos]);
|
|
if (b < 0x80) {
|
|
// single byte, itself the payload
|
|
it = Item(pos, 0, 1, false);
|
|
} else if (b < 0xb8) {
|
|
it = Item(pos, 1, b - 0x80, false);
|
|
} else if (b < 0xc0) {
|
|
uint256 lenOfLen = b - 0xb7;
|
|
uint256 len = _readLen(data, pos + 1, lenOfLen);
|
|
it = Item(pos, 1 + lenOfLen, len, false);
|
|
} else if (b < 0xf8) {
|
|
it = Item(pos, 1, b - 0xc0, true);
|
|
} else {
|
|
uint256 lenOfLen = b - 0xf7;
|
|
uint256 len = _readLen(data, pos + 1, lenOfLen);
|
|
it = Item(pos, 1 + lenOfLen, len, true);
|
|
}
|
|
require(it.offset + it.headerLen + it.payloadLen <= data.length, "RLP:truncated");
|
|
}
|
|
|
|
function _readLen(bytes memory data, uint256 pos, uint256 lenOfLen) private pure returns (uint256 len) {
|
|
require(lenOfLen >= 1 && lenOfLen <= 8, "RLP:lenoflen");
|
|
require(pos + lenOfLen <= data.length, "RLP:len oob");
|
|
for (uint256 i = 0; i < lenOfLen; i++) {
|
|
len = (len << 8) | uint8(data[pos + i]);
|
|
}
|
|
}
|
|
|
|
/// @notice Total encoded length (header + payload) of the item at `pos`.
|
|
function totalLen(bytes memory data, uint256 pos) internal pure returns (uint256) {
|
|
Item memory it = itemAt(data, pos);
|
|
return it.headerLen + it.payloadLen;
|
|
}
|
|
|
|
/// @notice Copy out the raw RLP bytes (header + payload) of the item at `pos`.
|
|
function rawItemAt(bytes memory data, uint256 pos) internal pure returns (bytes memory out) {
|
|
Item memory it = itemAt(data, pos);
|
|
uint256 n = it.headerLen + it.payloadLen;
|
|
out = new bytes(n);
|
|
for (uint256 i = 0; i < n; i++) out[i] = data[pos + i];
|
|
}
|
|
|
|
/// @notice Read the CONTENT (payload) of a string item; reverts if it is a list.
|
|
function readBytes(bytes memory item) internal pure returns (bytes memory out) {
|
|
Item memory it = itemAt(item, 0);
|
|
require(!it.isList, "RLP:not string");
|
|
uint256 start = it.headerLen; // for single-byte, headerLen=0 so start=0 => the byte itself
|
|
out = new bytes(it.payloadLen);
|
|
for (uint256 i = 0; i < it.payloadLen; i++) out[i] = item[start + i];
|
|
}
|
|
|
|
/// @notice True iff the first byte marks a list (>= 0xc0).
|
|
function isList(bytes memory item) internal pure returns (bool) {
|
|
return item.length != 0 && uint8(item[0]) >= 0xc0;
|
|
}
|
|
|
|
/// @notice Split a list item into the RAW rlp bytes of each of its elements.
|
|
function splitList(bytes memory listItem) internal pure returns (bytes[] memory items) {
|
|
Item memory head = itemAt(listItem, 0);
|
|
require(head.isList, "RLP:not list");
|
|
uint256 end = head.headerLen + head.payloadLen;
|
|
// First pass: count.
|
|
uint256 count = 0;
|
|
uint256 p = head.headerLen;
|
|
while (p < end) {
|
|
p += totalLen(listItem, p);
|
|
count++;
|
|
}
|
|
items = new bytes[](count);
|
|
p = head.headerLen;
|
|
for (uint256 i = 0; i < count; i++) {
|
|
uint256 n = totalLen(listItem, p);
|
|
bytes memory el = new bytes(n);
|
|
for (uint256 j = 0; j < n; j++) el[j] = listItem[p + j];
|
|
items[i] = el;
|
|
p += n;
|
|
}
|
|
}
|
|
}
|