编译器
0.8.20+commit.a1b79de6
文件 1 的 24:Adapter.sol
pragma solidity ^0.8.20;
import { IAdapter } from "../interfaces/IAdapter.sol";
abstract contract Adapter is IAdapter {
mapping(uint256 => mapping(uint256 => bytes32)) private _hashes;
function getHash(uint256 domain, uint256 id) public view returns (bytes32) {
return _hashes[domain][id];
}
function _storeHashes(uint256 domain, uint256[] memory ids, bytes32[] memory hashes) internal {
for (uint256 i = 0; i < ids.length; ) {
_storeHash(domain, ids[i], hashes[i]);
unchecked {
++i;
}
}
}
function _storeHash(uint256 domain, uint256 id, bytes32 hash) internal {
bytes32 currentHash = _hashes[domain][id];
if (currentHash != hash) {
_hashes[domain][id] = hash;
emit HashStored(id, hash);
}
}
}
文件 2 的 24:BlockHashAdapter.sol
pragma solidity ^0.8.20;
import { RLPReader } from "solidity-rlp/contracts/RLPReader.sol";
import { Adapter } from "./Adapter.sol";
import { IBlockHashAdapter } from "../interfaces/IBlockHashAdapter.sol";
abstract contract BlockHashAdapter is IBlockHashAdapter, Adapter {
using RLPReader for RLPReader.RLPItem;
function proveAncestralBlockHashes(uint256 chainId, bytes[] memory blockHeaders) external {
for (uint256 i = 0; i < blockHeaders.length; i++) {
RLPReader.RLPItem memory blockHeaderRLP = RLPReader.toRlpItem(blockHeaders[i]);
if (!blockHeaderRLP.isList()) revert InvalidBlockHeaderRLP();
RLPReader.RLPItem[] memory blockHeaderContent = blockHeaderRLP.toList();
bytes32 blockParent = bytes32(blockHeaderContent[0].toUint());
uint256 blockNumber = uint256(blockHeaderContent[8].toUint());
bytes32 blockHash = keccak256(blockHeaders[i]);
bytes32 storedBlockHash = getHash(chainId, blockNumber);
if (blockHash != storedBlockHash) revert ConflictingBlockHeader(blockNumber, blockHash, storedBlockHash);
_storeHash(chainId, blockNumber - 1, blockParent);
}
}
}
文件 3 的 24:Bytes.sol
pragma solidity 0.8.20;
import {Memory} from "./Memory.sol";
struct ByteSlice {
bytes data;
uint256 offset;
}
library Bytes {
uint256 internal constant BYTES_HEADER_SIZE = 32;
function equals(
bytes memory self,
bytes memory other
) internal pure returns (bool equal) {
if (self.length != other.length) {
return false;
}
uint256 addr;
uint256 addr2;
assembly {
addr := add(self, 32)
addr2 := add(other, 32)
}
equal = Memory.equals(addr, addr2, self.length);
}
function readByte(ByteSlice memory self) internal pure returns (uint8) {
if (self.offset + 1 > self.data.length) {
revert("Out of range");
}
uint8 b = uint8(self.data[self.offset]);
self.offset += 1;
return b;
}
function read(
ByteSlice memory self,
uint256 len
) internal pure returns (bytes memory) {
require(self.offset + len <= self.data.length);
if (len == 0) {
return "";
}
uint256 addr = Memory.dataPtr(self.data);
bytes memory slice = Memory.toBytes(addr + self.offset, len);
self.offset += len;
return slice;
}
function substr(
bytes memory self,
uint256 startIndex
) internal pure returns (bytes memory) {
require(startIndex <= self.length);
uint256 len = self.length - startIndex;
uint256 addr = Memory.dataPtr(self);
return Memory.toBytes(addr + startIndex, len);
}
function substr(
bytes memory self,
uint256 startIndex,
uint256 len
) internal pure returns (bytes memory) {
require(startIndex + len <= self.length);
if (len == 0) {
return "";
}
uint256 addr = Memory.dataPtr(self);
return Memory.toBytes(addr + startIndex, len);
}
function concat(
bytes memory self,
bytes memory other
) internal pure returns (bytes memory) {
bytes memory ret = new bytes(self.length + other.length);
uint256 src;
uint256 srcLen;
(src, srcLen) = Memory.fromBytes(self);
uint256 src2;
uint256 src2Len;
(src2, src2Len) = Memory.fromBytes(other);
uint256 dest;
(dest, ) = Memory.fromBytes(ret);
uint256 dest2 = dest + srcLen;
Memory.copy(src, dest, srcLen);
Memory.copy(src2, dest2, src2Len);
return ret;
}
function toBytes32(bytes memory self) internal pure returns (bytes32 out) {
require(self.length >= 32, "Bytes:: toBytes32: data is to short.");
assembly {
out := mload(add(self, 32))
}
}
function toBytes16(
bytes memory self,
uint256 offset
) internal pure returns (bytes16 out) {
for (uint256 i = 0; i < 16; i++) {
out |= bytes16(bytes1(self[offset + i]) & 0xFF) >> (i * 8);
}
}
function toBytes8(
bytes memory self,
uint256 offset
) internal pure returns (bytes8 out) {
for (uint256 i = 0; i < 8; i++) {
out |= bytes8(bytes1(self[offset + i]) & 0xFF) >> (i * 8);
}
}
function toBytes4(
bytes memory self,
uint256 offset
) internal pure returns (bytes4) {
bytes4 out;
for (uint256 i = 0; i < 4; i++) {
out |= bytes4(self[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function toBytes2(
bytes memory self,
uint256 offset
) internal pure returns (bytes2) {
bytes2 out;
for (uint256 i = 0; i < 2; i++) {
out |= bytes2(self[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function removeLeadingZero(
bytes memory data
) internal pure returns (bytes memory) {
uint256 length = data.length;
uint256 startIndex = 0;
for (uint256 i = 0; i < length; i++) {
if (data[i] != 0) {
startIndex = i;
break;
}
}
return substr(data, startIndex);
}
function removeEndingZero(
bytes memory data
) internal pure returns (bytes memory) {
uint256 length = data.length;
uint256 endIndex = 0;
for (uint256 i = length - 1; i >= 0; i--) {
if (data[i] != 0) {
endIndex = i;
break;
}
}
return substr(data, 0, endIndex + 1);
}
function reverse(
bytes memory inbytes
) internal pure returns (bytes memory) {
uint256 inlength = inbytes.length;
bytes memory outbytes = new bytes(inlength);
for (uint256 i = 0; i <= inlength - 1; i++) {
outbytes[i] = inbytes[inlength - i - 1];
}
return outbytes;
}
}
文件 4 的 24:DendrETHAdapter.sol
pragma solidity ^0.8.20;
import { ILightClient, LightClientUpdate } from "./interfaces/IDendrETH.sol";
import { SSZ } from "../Telepathy/libraries/SimpleSerialize.sol";
import { Merkle } from "../Electron/lib/Merkle.sol";
import { Receipt } from "../Electron/lib/Receipt.sol";
import { BlockHashAdapter } from "../BlockHashAdapter.sol";
contract DendrETHAdapter is BlockHashAdapter {
bytes32 internal constant MESSAGE_DISPATCHED_EVENT_SIG =
0x218247aabc759e65b5bb92ccc074f9d62cd187259f2a0984c3c9cf91f67ff7cf;
address public immutable DENDRETH_ADDRESS;
address public immutable SOURCE_YAHO;
uint256 public immutable SOURCE_CHAIN_ID;
error FinalizedBlockHeaderNotAvailable(bytes32 finalizedHeader);
error InvalidSlot();
error InvalidBlockNumberProof();
error InvalidBlockHashProof();
error InvalidReceiptsRoot();
error ErrorParseReceipt();
error InvalidEventSignature();
error InvalidEventSource();
modifier onlyFinalizedHeaderIsInLightClient(bytes32 finalizedBlockHeader) {
_checkFinalizedHeaderIsInLightClient(finalizedBlockHeader);
_;
}
constructor(address dendrETHAddress, uint256 sourceChainId, address sourceYaho) {
DENDRETH_ADDRESS = dendrETHAddress;
SOURCE_CHAIN_ID = sourceChainId;
SOURCE_YAHO = sourceYaho;
}
function storeBlockHeader(
bytes32 finalizedBlockHeader,
uint256 blockNumber,
bytes32[] calldata blockNumberProof,
bytes32 blockHash,
bytes32[] calldata blockHashProof
) external onlyFinalizedHeaderIsInLightClient(finalizedBlockHeader) {
if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, finalizedBlockHeader)) {
revert InvalidBlockNumberProof();
}
if (!SSZ.verifyBlockHash(blockHash, blockHashProof, finalizedBlockHeader)) {
revert InvalidBlockHashProof();
}
_storeHash(SOURCE_CHAIN_ID, blockNumber, blockHash);
}
function storeBlockHeader(
uint256 blockNumber,
bytes32[] calldata blockNumberProof,
bytes32 blockHash,
bytes32[] calldata blockHashProof,
LightClientUpdate calldata update
) external {
ILightClient lightClient = ILightClient(DENDRETH_ADDRESS);
lightClient.lightClientUpdate(update);
bytes32 finalizedHeaderRoot = lightClient.finalizedHeaderRoot();
if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, finalizedHeaderRoot)) {
revert InvalidBlockNumberProof();
}
if (!SSZ.verifyBlockHash(blockHash, blockHashProof, finalizedHeaderRoot)) {
revert InvalidBlockHashProof();
}
_storeHash(SOURCE_CHAIN_ID, blockNumber, blockHash);
}
function verifyAndStoreDispatchedMessage(
bytes32 srcFinalizedHeader,
uint64 srcSlot,
bytes32[] calldata slotProof,
uint64 txSlot,
bytes32[] memory receiptsRootProof,
bytes32 receiptsRoot,
bytes[] memory receiptProof,
bytes memory txIndexRLPEncoded,
uint256 logIndex
) external onlyFinalizedHeaderIsInLightClient(srcFinalizedHeader) {
if (!SSZ.verifySlot(srcSlot, slotProof, srcFinalizedHeader)) {
revert InvalidSlot();
}
bool isValidReceiptsRoot = Merkle.verifyReceiptsRoot(
receiptsRootProof,
receiptsRoot,
srcSlot,
txSlot,
srcFinalizedHeader
);
if (!isValidReceiptsRoot) revert InvalidReceiptsRoot();
Receipt.ParsedReceipt memory parsedReceipt = Receipt.parseReceipt(
receiptsRoot,
receiptProof,
txIndexRLPEncoded,
logIndex
);
if (!parsedReceipt.isValid) revert ErrorParseReceipt();
if (bytes32(parsedReceipt.topics[0]) != MESSAGE_DISPATCHED_EVENT_SIG) revert InvalidEventSignature();
if (parsedReceipt.eventSource != SOURCE_YAHO) revert InvalidEventSource();
uint256 messageId = uint256(parsedReceipt.topics[1]);
bytes32 messageHash = keccak256(parsedReceipt.data);
_storeHash(SOURCE_CHAIN_ID, messageId, messageHash);
}
function _checkFinalizedHeaderIsInLightClient(bytes32 finalizedBlockHeader) internal view {
ILightClient lightClient = ILightClient(DENDRETH_ADDRESS);
uint256 currentIndex = lightClient.currentIndex();
uint256 i = currentIndex;
bool found = false;
do {
if (finalizedBlockHeader == lightClient.finalizedHeaders(i)) {
found = true;
break;
}
if (i == 0) {
i = 32;
}
i--;
} while (i != currentIndex);
if (!found) {
revert FinalizedBlockHeaderNotAvailable(finalizedBlockHeader);
}
}
}
文件 5 的 24:EthereumTrieDB.sol
pragma solidity 0.8.20;
import "../Node.sol";
import "../Bytes.sol";
import {NibbleSliceOps} from "../NibbleSlice.sol";
import "./RLPReader.sol";
library EthereumTrieDB {
using RLPReader for bytes;
using RLPReader for RLPReader.RLPItem;
using RLPReader for RLPReader.Iterator;
bytes constant HASHED_NULL_NODE =
hex"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421";
function decodeNodeKind(
bytes memory encoded
) external pure returns (NodeKind memory) {
NodeKind memory node;
ByteSlice memory input = ByteSlice(encoded, 0);
if (Bytes.equals(encoded, HASHED_NULL_NODE)) {
node.isEmpty = true;
return node;
}
RLPReader.RLPItem[] memory itemList = encoded.toRlpItem().toList();
uint256 numItems = itemList.length;
if (numItems == 0) {
node.isEmpty = true;
return node;
} else if (numItems == 2) {
bytes memory key = itemList[0].toBytes();
uint256 prefix;
assembly {
let first := shr(248, mload(add(key, 32)))
prefix := shr(4, first)
}
if (prefix == 2 || prefix == 3) {
node.isLeaf = true;
} else {
node.isExtension = true;
}
} else if (numItems == 17) {
node.isBranch = true;
} else {
revert("Invalid data");
}
node.data = input;
return node;
}
function decodeLeaf(
NodeKind memory node
) external pure returns (Leaf memory) {
Leaf memory leaf;
RLPReader.RLPItem[] memory decoded = node
.data
.data
.toRlpItem()
.toList();
bytes memory data = decoded[1].toBytes();
leaf.key = NibbleSlice(Bytes.substr(decoded[0].toBytes(), 1), 0);
leaf.value = NodeHandle(false, bytes32(0), true, data);
return leaf;
}
function decodeExtension(
NodeKind memory node
) external pure returns (Extension memory) {
Extension memory extension;
RLPReader.RLPItem[] memory decoded = node
.data
.data
.toRlpItem()
.toList();
bytes memory data = decoded[1].toBytes();
uint8 isOdd = uint8(decoded[0].toBytes()[0] >> 4) & 0x01;
extension.key = NibbleSlice(
Bytes.substr(decoded[0].toBytes(), (isOdd + 1) % 2),
isOdd
);
extension.node = NodeHandle(
true,
Bytes.toBytes32(data),
false,
new bytes(0)
);
return extension;
}
function decodeBranch(
NodeKind memory node
) external pure returns (Branch memory) {
Branch memory branch;
RLPReader.RLPItem[] memory decoded = node
.data
.data
.toRlpItem()
.toList();
NodeHandleOption[16] memory childrens;
for (uint256 i = 0; i < 16; i++) {
bytes memory dataAsBytes = decoded[i].toBytes();
if (dataAsBytes.length != 32) {
childrens[i] = NodeHandleOption(
false,
NodeHandle(false, bytes32(0), false, new bytes(0))
);
} else {
bytes32 data = Bytes.toBytes32(dataAsBytes);
childrens[i] = NodeHandleOption(
true,
NodeHandle(true, data, false, new bytes(0))
);
}
}
if (isEmpty(decoded[16].toBytes())) {
branch.value = NodeHandleOption(
false,
NodeHandle(false, bytes32(0), false, new bytes(0))
);
} else {
branch.value = NodeHandleOption(
true,
NodeHandle(false, bytes32(0), true, decoded[16].toBytes())
);
}
branch.children = childrens;
return branch;
}
function isEmpty(bytes memory item) internal pure returns (bool) {
return item.length > 0 && (item[0] == 0xc0 || item[0] == 0x80);
}
}
文件 6 的 24:IAdapter.sol
pragma solidity ^0.8.0;
interface IAdapter {
error ConflictingBlockHeader(uint256 blockNumber, bytes32 blockHash, bytes32 storedBlockHash);
error InvalidBlockHeaderRLP();
event HashStored(uint256 indexed id, bytes32 indexed hash);
function getHash(uint256 domain, uint256 id) external view returns (bytes32 hash);
}
文件 7 的 24:IBlockHashAdapter.sol
pragma solidity ^0.8.0;
import { IAdapter } from "./IAdapter.sol";
interface IBlockHashAdapter is IAdapter {
function proveAncestralBlockHashes(uint256 chainId, bytes[] memory blockHeaders) external;
}
文件 8 的 24:IDendrETH.sol
pragma solidity ^0.8.20;
struct LightClientUpdate {
bytes32 attestedHeaderRoot;
uint256 attestedHeaderSlot;
bytes32 finalizedHeaderRoot;
bytes32 finalizedExecutionStateRoot;
uint256[2] a;
uint256[2][2] b;
uint256[2] c;
}
interface ILightClient {
function currentIndex() external view returns (uint256);
function optimisticHeaderRoot() external view returns (bytes32);
function optimisticHeaderSlot() external view returns (uint256);
function finalizedHeaderRoot() external view returns (bytes32);
function executionStateRoot() external view returns (bytes32);
function optimisticHeaders(uint256 index) external view returns (bytes32);
function optimisticSlots(uint256 index) external view returns (uint256);
function finalizedHeaders(uint256 index) external view returns (bytes32);
function executionStateRoots(uint256 index) external view returns (bytes32);
function lightClientUpdate(LightClientUpdate calldata update) external payable;
}
文件 9 的 24:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1, "Math: mulDiv overflow");
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
文件 10 的 24:Memory.sol
pragma solidity 0.8.20;
library Memory {
uint256 internal constant WORD_SIZE = 32;
function equals(
uint256 addr,
uint256 addr2,
uint256 len
) internal pure returns (bool equal) {
assembly {
equal := eq(keccak256(addr, len), keccak256(addr2, len))
}
}
function equals(
uint256 addr,
uint256 len,
bytes memory bts
) internal pure returns (bool equal) {
require(bts.length >= len);
uint256 addr2;
assembly {
addr2 := add(bts, 32)
}
return equals(addr, addr2, len);
}
function dataPtr(bytes memory bts) internal pure returns (uint256 addr) {
assembly {
addr := add(bts, 32)
}
}
function toBytes(
uint256 addr,
uint256 len
) internal pure returns (bytes memory bts) {
bts = new bytes(len);
uint256 btsptr;
assembly {
btsptr := add(bts, 32)
}
copy(addr, btsptr, len);
}
function toBytes(bytes32 self) internal pure returns (bytes memory bts) {
bts = new bytes(32);
assembly {
mstore(add(bts, 32), self)
}
}
function copy(uint256 src, uint256 dest, uint256 len) internal pure {
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
dest += WORD_SIZE;
src += WORD_SIZE;
}
uint256 mask = len == 0
? 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
: 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
function fromBytes(
bytes memory bts
) internal pure returns (uint256 addr, uint256 len) {
len = bts.length;
assembly {
addr := add(bts, 32)
}
}
}
文件 11 的 24:Merkle.sol
pragma solidity ^0.8.20;
library Merkle {
uint256 internal constant SLOTS_PER_HISTORICAL_ROOT = 8192;
function restoreMerkleRoot(
bytes32[] memory branch,
bytes32 leaf,
uint256 index
) internal pure returns (bytes32 root) {
require(index < 2 ** branch.length, "invalid leaf index");
bytes32 combineHash = leaf;
uint256 curIndex = index;
for (uint256 i = 0; i < branch.length; ) {
if (curIndex % 2 == 0) combineHash = sha256(bytes.concat(combineHash, branch[i]));
else combineHash = sha256(bytes.concat(branch[i], combineHash));
curIndex /= 2;
unchecked {
i++;
}
}
root = combineHash;
}
function verifyReceiptsRoot(
bytes32[] memory receiptsRootBranch,
bytes32 receiptsRoot,
uint64 lcSlot,
uint64 txSlot,
bytes32 headerRoot
) internal pure returns (bool) {
uint256 index;
if (txSlot == lcSlot) {
index = 6435;
} else if (lcSlot - txSlot <= SLOTS_PER_HISTORICAL_ROOT) {
uint256[] memory historicalRootGindexes = new uint256[](2);
historicalRootGindexes[0] = 37;
historicalRootGindexes[1] = calculateArrayGindex(txSlot % SLOTS_PER_HISTORICAL_ROOT);
uint256[] memory receiptGindexes = new uint256[](3);
receiptGindexes[0] = 11;
receiptGindexes[1] = concatGindices(historicalRootGindexes);
receiptGindexes[2] = 6435;
index = concatGindices(receiptGindexes);
} else if (lcSlot - txSlot > SLOTS_PER_HISTORICAL_ROOT) {
revert("txSlot lags by >8192 blocks. Not supported.");
} else {
revert("txSlot can't be greater than lightclient slot");
}
bytes32 computedRoot = restoreMerkleRoot(receiptsRootBranch, receiptsRoot, calculateIndex(index));
return computedRoot == headerRoot;
}
function concatGindices(uint256[] memory gindices) public pure returns (uint256) {
uint256 result = 1;
for (uint i = 0; i < gindices.length; i++) {
uint256 gindex = gindices[i];
uint256 gindexWithoutLeadingOne = gindex & ((1 << (bitLength(gindex) - 1)) - 1);
result = (result << (bitLength(gindex) - 1)) | gindexWithoutLeadingOne;
}
return result;
}
function bitLength(uint256 number) internal pure returns (uint256) {
if (number == 0) {
return 0;
}
uint256 length = 0;
while (number > 0) {
length++;
number >>= 1;
}
return length;
}
function calculateArrayGindex(uint256 elementIndex) internal pure returns (uint256) {
uint256 gindex = 1;
uint256 depth = 0;
while ((1 << depth) < SLOTS_PER_HISTORICAL_ROOT) {
depth++;
}
for (uint256 d = 0; d < depth; d++) {
gindex = (gindex << 1) | ((elementIndex >> (depth - d - 1)) & 1);
}
return gindex;
}
function calculateIndex(uint256 gindex) internal pure returns (uint256 index) {
uint256 depth = floorLog2(gindex);
index = gindex % (2 ** depth);
}
function floorLog2(uint256 x) internal pure returns (uint256) {
require(x > 0, "Input must be greater than zero");
uint256 result = 0;
while (x > 1) {
x >>= 1;
result++;
}
return result;
}
}
文件 12 的 24:MerklePatricia.sol
pragma solidity 0.8.20;
import "./trie/Node.sol";
import "./trie/Option.sol";
import "./trie/NibbleSlice.sol";
import "./trie/TrieDB.sol";
import "./trie/substrate/SubstrateTrieDB.sol";
import "./trie/ethereum/EthereumTrieDB.sol";
import "./Types.sol";
library MerklePatricia {
function VerifySubstrateProof(
bytes32 root,
bytes[] memory proof,
bytes[] memory keys
) public pure returns (StorageValue[] memory) {
StorageValue[] memory values = new StorageValue[](keys.length);
TrieNode[] memory nodes = new TrieNode[](proof.length);
for (uint256 i = 0; i < proof.length; i++) {
nodes[i] = TrieNode(keccak256(proof[i]), proof[i]);
}
for (uint256 i = 0; i < keys.length; i++) {
values[i].key = keys[i];
NibbleSlice memory keyNibbles = NibbleSlice(keys[i], 0);
NodeKind memory node = SubstrateTrieDB.decodeNodeKind(
TrieDB.get(nodes, root)
);
for (uint256 j = 1; j > 0; j++) {
NodeHandle memory nextNode;
if (TrieDB.isLeaf(node)) {
Leaf memory leaf = SubstrateTrieDB.decodeLeaf(node);
if (NibbleSliceOps.eq(leaf.key, keyNibbles)) {
values[i].value = TrieDB.load(nodes, leaf.value);
}
break;
} else if (TrieDB.isNibbledBranch(node)) {
NibbledBranch memory nibbled = SubstrateTrieDB
.decodeNibbledBranch(node);
uint256 nibbledBranchKeyLength = NibbleSliceOps.len(
nibbled.key
);
if (!NibbleSliceOps.startsWith(keyNibbles, nibbled.key)) {
break;
}
if (
NibbleSliceOps.len(keyNibbles) == nibbledBranchKeyLength
) {
if (Option.isSome(nibbled.value)) {
values[i].value = TrieDB.load(
nodes,
nibbled.value.value
);
}
break;
} else {
uint256 index = NibbleSliceOps.at(
keyNibbles,
nibbledBranchKeyLength
);
NodeHandleOption memory handle = nibbled.children[
index
];
if (Option.isSome(handle)) {
keyNibbles = NibbleSliceOps.mid(
keyNibbles,
nibbledBranchKeyLength + 1
);
nextNode = handle.value;
} else {
break;
}
}
} else if (TrieDB.isEmpty(node)) {
break;
}
node = SubstrateTrieDB.decodeNodeKind(
TrieDB.load(nodes, nextNode)
);
}
}
return values;
}
function ReadChildProofCheck(
bytes32 root,
bytes[] memory proof,
bytes[] memory keys,
bytes memory childInfo
) public pure returns (StorageValue[] memory) {
bytes memory prefix = bytes(":child_storage:default:");
bytes memory key = bytes.concat(prefix, childInfo);
bytes[] memory _keys = new bytes[](1);
_keys[0] = key;
StorageValue[] memory values = VerifySubstrateProof(root, proof, _keys);
bytes32 childRoot = bytes32(values[0].value);
require(childRoot != bytes32(0), "Invalid child trie proof");
return VerifySubstrateProof(childRoot, proof, keys);
}
function VerifyEthereumProof(
bytes32 root,
bytes[] memory proof,
bytes[] memory keys
) public pure returns (StorageValue[] memory) {
StorageValue[] memory values = new StorageValue[](keys.length);
TrieNode[] memory nodes = new TrieNode[](proof.length);
for (uint256 i = 0; i < proof.length; i++) {
nodes[i] = TrieNode(keccak256(proof[i]), proof[i]);
}
for (uint256 i = 0; i < keys.length; i++) {
values[i].key = keys[i];
NibbleSlice memory keyNibbles = NibbleSlice(keys[i], 0);
NodeKind memory node = EthereumTrieDB.decodeNodeKind(
TrieDB.get(nodes, root)
);
for (uint256 j = 1; j > 0; j++) {
NodeHandle memory nextNode;
if (TrieDB.isLeaf(node)) {
Leaf memory leaf = EthereumTrieDB.decodeLeaf(node);
uint256 offset = keyNibbles.offset % 2 == 0
? keyNibbles.offset / 2
: keyNibbles.offset / 2 + 1;
keyNibbles = NibbleSlice(
NibbleSliceOps.bytesSlice(keyNibbles.data, offset),
0
);
if (NibbleSliceOps.eq(leaf.key, keyNibbles)) {
values[i].value = TrieDB.load(nodes, leaf.value);
}
break;
} else if (TrieDB.isExtension(node)) {
Extension memory extension = EthereumTrieDB.decodeExtension(
node
);
if (NibbleSliceOps.startsWith(keyNibbles, extension.key)) {
uint256 cutNibble = keyNibbles.offset +
NibbleSliceOps.len(extension.key);
keyNibbles = NibbleSlice(
NibbleSliceOps.bytesSlice(
keyNibbles.data,
cutNibble / 2
),
cutNibble % 2
);
nextNode = extension.node;
} else {
break;
}
} else if (TrieDB.isBranch(node)) {
Branch memory branch = EthereumTrieDB.decodeBranch(node);
if (NibbleSliceOps.isEmpty(keyNibbles)) {
if (Option.isSome(branch.value)) {
values[i].value = TrieDB.load(
nodes,
branch.value.value
);
}
break;
} else {
NodeHandleOption memory handle = branch.children[
NibbleSliceOps.at(keyNibbles, 0)
];
if (Option.isSome(handle)) {
keyNibbles = NibbleSliceOps.mid(keyNibbles, 1);
nextNode = handle.value;
} else {
break;
}
}
} else if (TrieDB.isEmpty(node)) {
break;
}
node = EthereumTrieDB.decodeNodeKind(
TrieDB.load(nodes, nextNode)
);
}
}
return values;
}
}
文件 13 的 24:NibbleSlice.sol
pragma solidity 0.8.20;
struct NibbleSlice {
bytes data;
uint256 offset;
}
library NibbleSliceOps {
uint256 internal constant NIBBLE_PER_BYTE = 2;
uint256 internal constant BITS_PER_NIBBLE = 4;
function len(NibbleSlice memory nibble) internal pure returns (uint256) {
return nibble.data.length * NIBBLE_PER_BYTE - nibble.offset;
}
function mid(
NibbleSlice memory self,
uint256 i
) internal pure returns (NibbleSlice memory) {
return NibbleSlice(self.data, self.offset + i);
}
function isEmpty(NibbleSlice memory self) internal pure returns (bool) {
return len(self) == 0;
}
function eq(
NibbleSlice memory self,
NibbleSlice memory other
) internal pure returns (bool) {
return len(self) == len(other) && startsWith(self, other);
}
function at(
NibbleSlice memory self,
uint256 i
) internal pure returns (uint256) {
uint256 ix = (self.offset + i) / NIBBLE_PER_BYTE;
uint256 pad = (self.offset + i) % NIBBLE_PER_BYTE;
uint8 data = uint8(self.data[ix]);
return (pad == 1) ? data & 0x0F : data >> BITS_PER_NIBBLE;
}
function startsWith(
NibbleSlice memory self,
NibbleSlice memory other
) internal pure returns (bool) {
return commonPrefix(self, other) == len(other);
}
function commonPrefix(
NibbleSlice memory self,
NibbleSlice memory other
) internal pure returns (uint256) {
uint256 self_align = self.offset % NIBBLE_PER_BYTE;
uint256 other_align = other.offset % NIBBLE_PER_BYTE;
if (self_align == other_align) {
uint256 self_start = self.offset / NIBBLE_PER_BYTE;
uint256 other_start = other.offset / NIBBLE_PER_BYTE;
uint256 first = 0;
if (self_align != 0) {
if (
(self.data[self_start] & 0x0F) !=
(other.data[other_start] & 0x0F)
) {
return 0;
}
++self_start;
++other_start;
++first;
}
bytes memory selfSlice = bytesSlice(self.data, self_start);
bytes memory otherSlice = bytesSlice(other.data, other_start);
return biggestDepth(selfSlice, otherSlice) + first;
} else {
uint256 s = min(len(self), len(other));
uint256 i = 0;
while (i < s) {
if (at(self, i) != at(other, i)) {
break;
}
++i;
}
return i;
}
}
function biggestDepth(
bytes memory a,
bytes memory b
) internal pure returns (uint256) {
uint256 upperBound = min(a.length, b.length);
uint256 i = 0;
while (i < upperBound) {
if (a[i] != b[i]) {
return i * NIBBLE_PER_BYTE + leftCommon(a[i], b[i]);
}
++i;
}
return i * NIBBLE_PER_BYTE;
}
function leftCommon(bytes1 a, bytes1 b) internal pure returns (uint256) {
if (a == b) {
return 2;
} else if (uint8(a) & 0xF0 == uint8(b) & 0xF0) {
return 1;
} else {
return 0;
}
}
function bytesSlice(
bytes memory _bytes,
uint256 _start
) internal pure returns (bytes memory) {
uint256 bytesLength = _bytes.length;
uint256 _length = bytesLength - _start;
require(bytesLength >= _start, "slice_outOfBounds");
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
tempBytes := mload(0x40)
let lengthmod := and(_length, 31)
let mc := add(
add(tempBytes, lengthmod),
mul(0x20, iszero(lengthmod))
)
let end := add(mc, _length)
for {
let cc := add(
add(
add(_bytes, lengthmod),
mul(0x20, iszero(lengthmod))
),
_start
)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
mstore(0x40, and(add(mc, 31), not(31)))
}
default {
tempBytes := mload(0x40)
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function min(uint256 a, uint256 b) private pure returns (uint256) {
return (a < b) ? a : b;
}
}
文件 14 的 24:Node.sol
pragma solidity 0.8.20;
import "./NibbleSlice.sol";
import "./Bytes.sol";
struct NodeKind {
bool isEmpty;
bool isLeaf;
bool isHashedLeaf;
bool isNibbledValueBranch;
bool isNibbledHashedValueBranch;
bool isNibbledBranch;
bool isExtension;
bool isBranch;
uint256 nibbleSize;
ByteSlice data;
}
struct NodeHandle {
bool isHash;
bytes32 hash;
bool isInline;
bytes inLine;
}
struct Extension {
NibbleSlice key;
NodeHandle node;
}
struct Branch {
NodeHandleOption value;
NodeHandleOption[16] children;
}
struct NibbledBranch {
NibbleSlice key;
NodeHandleOption value;
NodeHandleOption[16] children;
}
struct ValueOption {
bool isSome;
bytes value;
}
struct NodeHandleOption {
bool isSome;
NodeHandle value;
}
struct Leaf {
NibbleSlice key;
NodeHandle value;
}
struct TrieNode {
bytes32 hash;
bytes node;
}
文件 15 的 24:Option.sol
pragma solidity 0.8.20;
import "./Node.sol";
library Option {
function isSome(ValueOption memory val) internal pure returns (bool) {
return val.isSome == true;
}
function isSome(NodeHandleOption memory val) internal pure returns (bool) {
return val.isSome == true;
}
}
文件 16 的 24:RLPReader.sol
pragma solidity >=0.5.10 <0.9.0;
library RLPReader {
uint8 constant STRING_SHORT_START = 0x80;
uint8 constant STRING_LONG_START = 0xb8;
uint8 constant LIST_SHORT_START = 0xc0;
uint8 constant LIST_LONG_START = 0xf8;
uint8 constant WORD_SIZE = 32;
struct RLPItem {
uint256 len;
uint256 memPtr;
}
struct Iterator {
RLPItem item;
uint256 nextPtr;
}
function next(Iterator memory self) internal pure returns (RLPItem memory) {
require(hasNext(self));
uint256 ptr = self.nextPtr;
uint256 itemLength = _itemLength(ptr);
self.nextPtr = ptr + itemLength;
return RLPItem(itemLength, ptr);
}
function hasNext(Iterator memory self) internal pure returns (bool) {
RLPItem memory item = self.item;
return self.nextPtr < item.memPtr + item.len;
}
function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
uint256 memPtr;
assembly {
memPtr := add(item, 0x20)
}
return RLPItem(item.length, memPtr);
}
function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
require(isList(self));
uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);
return Iterator(self, ptr);
}
function rlpLen(RLPItem memory item) internal pure returns (uint256) {
return item.len;
}
function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {
uint256 offset = _payloadOffset(item.memPtr);
uint256 memPtr = item.memPtr + offset;
uint256 len = item.len - offset;
return (memPtr, len);
}
function payloadLen(RLPItem memory item) internal pure returns (uint256) {
(, uint256 len) = payloadLocation(item);
return len;
}
function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
require(isList(item));
uint256 items = numItems(item);
RLPItem[] memory result = new RLPItem[](items);
uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
uint256 dataLen;
for (uint256 i = 0; i < items; i++) {
dataLen = _itemLength(memPtr);
result[i] = RLPItem(dataLen, memPtr);
memPtr = memPtr + dataLen;
}
return result;
}
function isList(RLPItem memory item) internal pure returns (bool) {
if (item.len == 0) return false;
uint8 byte0;
uint256 memPtr = item.memPtr;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < LIST_SHORT_START) return false;
return true;
}
function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {
uint256 ptr = item.memPtr;
uint256 len = item.len;
bytes32 result;
assembly {
result := keccak256(ptr, len)
}
return result;
}
function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {
(uint256 memPtr, uint256 len) = payloadLocation(item);
bytes32 result;
assembly {
result := keccak256(memPtr, len)
}
return result;
}
function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
bytes memory result = new bytes(item.len);
if (result.length == 0) return result;
uint256 ptr;
assembly {
ptr := add(0x20, result)
}
copy(item.memPtr, ptr, item.len);
return result;
}
function toBoolean(RLPItem memory item) internal pure returns (bool) {
require(item.len == 1);
uint256 result;
uint256 memPtr = item.memPtr;
assembly {
result := byte(0, mload(memPtr))
}
if (result == 0 || result == STRING_SHORT_START) {
return false;
} else {
return true;
}
}
function toAddress(RLPItem memory item) internal pure returns (address) {
require(item.len == 21);
return address(uint160(toUint(item)));
}
function toUint(RLPItem memory item) internal pure returns (uint256) {
require(item.len > 0 && item.len <= 33);
(uint256 memPtr, uint256 len) = payloadLocation(item);
uint256 result;
assembly {
result := mload(memPtr)
if lt(len, 32) { result := div(result, exp(256, sub(32, len))) }
}
return result;
}
function toUintStrict(RLPItem memory item) internal pure returns (uint256) {
require(item.len == 33);
uint256 result;
uint256 memPtr = item.memPtr + 1;
assembly {
result := mload(memPtr)
}
return result;
}
function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
require(item.len > 0);
(uint256 memPtr, uint256 len) = payloadLocation(item);
bytes memory result = new bytes(len);
uint256 destPtr;
assembly {
destPtr := add(0x20, result)
}
copy(memPtr, destPtr, len);
return result;
}
function numItems(RLPItem memory item) private pure returns (uint256) {
if (item.len == 0) return 0;
uint256 count = 0;
uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
uint256 endPtr = item.memPtr + item.len;
while (currPtr < endPtr) {
currPtr = currPtr + _itemLength(currPtr);
count++;
}
return count;
}
function _itemLength(uint256 memPtr) private pure returns (uint256) {
uint256 itemLen;
uint256 byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) {
itemLen = 1;
} else if (byte0 < STRING_LONG_START) {
itemLen = byte0 - STRING_SHORT_START + 1;
} else if (byte0 < LIST_SHORT_START) {
assembly {
let byteLen := sub(byte0, 0xb7)
memPtr := add(memPtr, 1)
let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen)))
itemLen := add(dataLen, add(byteLen, 1))
}
} else if (byte0 < LIST_LONG_START) {
itemLen = byte0 - LIST_SHORT_START + 1;
} else {
assembly {
let byteLen := sub(byte0, 0xf7)
memPtr := add(memPtr, 1)
let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen)))
itemLen := add(dataLen, add(byteLen, 1))
}
}
return itemLen;
}
function _payloadOffset(uint256 memPtr) private pure returns (uint256) {
uint256 byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) {
return 0;
} else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {
return 1;
} else if (byte0 < LIST_SHORT_START) {
return byte0 - (STRING_LONG_START - 1) + 1;
} else {
return byte0 - (LIST_LONG_START - 1) + 1;
}
}
function copy(uint256 src, uint256 dest, uint256 len) private pure {
if (len == 0) return;
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
src += WORD_SIZE;
dest += WORD_SIZE;
}
if (len > 0) {
uint256 mask = 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
}
}
文件 17 的 24:Receipt.sol
pragma solidity ^0.8.20;
import "@polytope-labs/solidity-merkle-trees/src/MerklePatricia.sol";
import { RLPReader } from "@polytope-labs/solidity-merkle-trees/src/trie/ethereum/RLPReader.sol";
library Receipt {
error UnsupportedTxType();
struct ParsedReceipt {
bool isValid;
bytes32[] topics;
bytes data;
address eventSource;
}
using RLPReader for RLPReader.RLPItem;
function parseReceipt(
bytes32 receiptsRoot,
bytes[] memory receiptProof,
bytes memory txIndexRLP,
uint256 logIndex
) internal pure returns (ParsedReceipt memory) {
bytes32[] memory eventTopics;
bytes memory eventData;
address eventSource;
ParsedReceipt memory parsedReceipt = ParsedReceipt({
isValid: false,
topics: eventTopics,
data: eventData,
eventSource: eventSource
});
bytes[] memory keys = new bytes[](1);
keys[0] = txIndexRLP;
bytes memory value = MerklePatricia.VerifyEthereumProof(receiptsRoot, receiptProof, keys)[0].value;
uint256 offset;
if (value[0] == 0x01 || value[0] == 0x02) {
offset = 1;
} else if (value[0] >= 0xc0) {
offset = 0;
} else {
revert UnsupportedTxType();
}
uint256 memPtr;
assembly {
memPtr := add(value, add(0x20, mul(0x01, offset)))
}
RLPReader.RLPItem[] memory receiptItems = RLPReader.RLPItem(value.length - offset, memPtr).toList();
if (receiptItems.length != 4) return parsedReceipt;
RLPReader.RLPItem[] memory logs = receiptItems[3].toList();
if (logIndex >= logs.length) return parsedReceipt;
RLPReader.RLPItem[] memory targetLog = logs[logIndex].toList();
eventSource = targetLog[0].toAddress();
RLPReader.RLPItem[] memory topicsItems = targetLog[1].toList();
bytes32[] memory topics_ = new bytes32[](topicsItems.length);
for (uint256 i = 0; i < topicsItems.length; ) {
topics_[i] = bytes32(topicsItems[i].toBytes());
unchecked {
i++;
}
}
eventTopics = topics_;
eventData = targetLog[2].toBytes();
return ParsedReceipt({ isValid: true, topics: eventTopics, data: eventData, eventSource: eventSource });
}
}
文件 18 的 24:ScaleCodec.sol
pragma solidity 0.8.20;
import {Bytes, ByteSlice} from "../Bytes.sol";
library ScaleCodec {
function decodeUint256(bytes memory data) internal pure returns (uint256) {
uint256 number;
for (uint256 i = data.length; i > 0; i--) {
number =
number +
uint256(uint8(data[i - 1])) *
(2 ** (8 * (i - 1)));
}
return number;
}
function decodeUintCompact(
ByteSlice memory data
) internal pure returns (uint256 v) {
uint8 b = Bytes.readByte(data);
uint8 mode = b % 4;
uint256 value;
if (mode == 0) {
value = b >> 2;
} else if (mode == 1) {
uint8 bb = Bytes.readByte(data);
uint64 r = bb;
r <<= 6;
r += b >> 2;
value = r;
} else if (mode == 2) {
uint8 b2 = Bytes.readByte(data);
uint8 b3 = Bytes.readByte(data);
uint8 b4 = Bytes.readByte(data);
uint32 x1 = uint32(b) | (uint32(b2) << 8);
uint32 x2 = x1 | (uint32(b3) << 16);
uint32 x3 = x2 | (uint32(b4) << 24);
x3 >>= 2;
value = uint256(x3);
} else if (mode == 3) {
uint8 l = (b >> 2) + 4;
require(l <= 8, "unexpected prefix decoding Compact<Uint>");
return decodeUint256(Bytes.read(data, l));
} else {
revert("Code should be unreachable");
}
return value;
}
function decodeUintCompact(
bytes memory data
) internal pure returns (uint256 v, uint8 m) {
uint8 b = readByteAtIndex(data, 0);
uint8 mode = b & 3;
uint256 value;
if (mode == 0) {
value = b >> 2;
} else if (mode == 1) {
uint8 bb = readByteAtIndex(data, 1);
uint64 r = bb;
r <<= 6;
r += b >> 2;
value = r;
} else if (mode == 2) {
uint8 b2 = readByteAtIndex(data, 1);
uint8 b3 = readByteAtIndex(data, 2);
uint8 b4 = readByteAtIndex(data, 3);
uint32 x1 = uint32(b) | (uint32(b2) << 8);
uint32 x2 = x1 | (uint32(b3) << 16);
uint32 x3 = x2 | (uint32(b4) << 24);
x3 >>= 2;
value = uint256(x3);
} else if (mode == 3) {
uint8 l = b >> 2;
require(
l > 32,
"Not supported: number cannot be greater than 32 bytes"
);
} else {
revert("Code should be unreachable");
}
return (value, mode);
}
function encodeUintCompact(uint256 v) internal pure returns (bytes memory) {
if (v < 64) {
return abi.encodePacked(uint8(v << 2));
} else if (v < 2 ** 14) {
return abi.encodePacked(reverse16(uint16(((v << 2) + 1))));
} else if (v < 2 ** 30) {
return abi.encodePacked(reverse32(uint32(((v << 2) + 2))));
} else {
bytes memory valueBytes = Bytes.removeEndingZero(
abi.encodePacked(reverse256(v))
);
uint256 length = valueBytes.length;
uint8 prefix = uint8(((length - 4) << 2) + 3);
return abi.encodePacked(prefix, valueBytes);
}
}
function readByteAtIndex(
bytes memory data,
uint8 index
) internal pure returns (uint8) {
return uint8(data[index]);
}
function reverse256(uint256 input) internal pure returns (uint256 v) {
v = input;
v =
((v &
0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >>
8) |
((v &
0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) <<
8);
v =
((v &
0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >>
16) |
((v &
0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) <<
16);
v =
((v &
0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >>
32) |
((v &
0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) <<
32);
v =
((v &
0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >>
64) |
((v &
0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) <<
64);
v = (v >> 128) | (v << 128);
}
function reverse128(uint128 input) internal pure returns (uint128 v) {
v = input;
v =
((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00) >> 8) |
((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
v =
((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000) >> 16) |
((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
v =
((v & 0xFFFFFFFF00000000FFFFFFFF00000000) >> 32) |
((v & 0x00000000FFFFFFFF00000000FFFFFFFF) << 32);
v = (v >> 64) | (v << 64);
}
function reverse64(uint64 input) internal pure returns (uint64 v) {
v = input;
v = ((v & 0xFF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF) << 8);
v = ((v & 0xFFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF) << 16);
v = (v >> 32) | (v << 32);
}
function reverse32(uint32 input) internal pure returns (uint32 v) {
v = input;
v = ((v & 0xFF00FF00) >> 8) | ((v & 0x00FF00FF) << 8);
v = (v >> 16) | (v << 16);
}
function reverse16(uint16 input) internal pure returns (uint16 v) {
v = input;
v = (v >> 8) | (v << 8);
}
function encode256(uint256 input) internal pure returns (bytes32) {
return bytes32(reverse256(input));
}
function encode128(uint128 input) internal pure returns (bytes16) {
return bytes16(reverse128(input));
}
function encode64(uint64 input) internal pure returns (bytes8) {
return bytes8(reverse64(input));
}
function encode32(uint32 input) internal pure returns (bytes4) {
return bytes4(reverse32(input));
}
function encode16(uint16 input) internal pure returns (bytes2) {
return bytes2(reverse16(input));
}
function encodeBytes(
bytes memory input
) internal pure returns (bytes memory) {
return abi.encodePacked(encodeUintCompact(input.length), input);
}
}
文件 19 的 24:SignedMath.sol
pragma solidity ^0.8.0;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
文件 20 的 24:SimpleSerialize.sol
pragma solidity ^0.8.20;
library SSZ {
uint256 internal constant EXECUTION_PAYLOAD_BLOCK_NUMBER_INDEX = 6438;
uint256 internal constant EXECUTION_PAYLOAD_BLOCK_HASH_INDEX = 6444;
uint256 internal constant SLOT_INDEX = 8;
function toLittleEndian(uint256 _v) internal pure returns (bytes32) {
_v =
((_v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) |
((_v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
_v =
((_v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) |
((_v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
_v =
((_v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) |
((_v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);
_v =
((_v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) |
((_v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);
_v = (_v >> 128) | (_v << 128);
return bytes32(_v);
}
function restoreMerkleRoot(
bytes32 _leaf,
uint256 _index,
bytes32[] memory _branch
) internal pure returns (bytes32) {
require(2 ** (_branch.length + 1) > _index, "incorrect branch length or index size");
bytes32 value = _leaf;
uint256 i = 0;
while (_index != 1) {
if (_index % 2 == 1) {
value = sha256(bytes.concat(_branch[i], value));
} else {
value = sha256(bytes.concat(value, _branch[i]));
}
_index /= 2;
i++;
}
return value;
}
function isValidMerkleBranch(
bytes32 _leaf,
uint256 _index,
bytes32[] memory _branch,
bytes32 _root
) internal pure returns (bool) {
bytes32 restoredMerkleRoot = restoreMerkleRoot(_leaf, _index, _branch);
return _root == restoredMerkleRoot;
}
function verifyBlockNumber(
uint256 _blockNumber,
bytes32[] memory _blockNumberProof,
bytes32 _headerRoot
) internal pure returns (bool) {
return
isValidMerkleBranch(
toLittleEndian(_blockNumber),
EXECUTION_PAYLOAD_BLOCK_NUMBER_INDEX,
_blockNumberProof,
_headerRoot
);
}
function verifyBlockHash(
bytes32 _blockHash,
bytes32[] memory _blockHashProof,
bytes32 _headerRoot
) internal pure returns (bool) {
return isValidMerkleBranch(_blockHash, EXECUTION_PAYLOAD_BLOCK_HASH_INDEX, _blockHashProof, _headerRoot);
}
function verifySlot(uint256 _slot, bytes32[] memory _slotProof, bytes32 _headerRoot) internal pure returns (bool) {
return isValidMerkleBranch(toLittleEndian(_slot), SLOT_INDEX, _slotProof, _headerRoot);
}
}
文件 21 的 24:Strings.sol
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
文件 22 的 24:SubstrateTrieDB.sol
pragma solidity 0.8.20;
import "../Node.sol";
import "../Bytes.sol";
import {NibbleSliceOps} from "../NibbleSlice.sol";
import {ScaleCodec} from "./ScaleCodec.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
library SubstrateTrieDB {
uint8 public constant FIRST_PREFIX = 0x00 << 6;
uint8 public constant PADDING_BITMASK = 0x0F;
uint8 public constant EMPTY_TRIE = FIRST_PREFIX | (0x00 << 4);
uint8 public constant LEAF_PREFIX_MASK = 0x01 << 6;
uint8 public constant BRANCH_WITH_MASK = 0x03 << 6;
uint8 public constant BRANCH_WITHOUT_MASK = 0x02 << 6;
uint8 public constant ALT_HASHING_LEAF_PREFIX_MASK =
FIRST_PREFIX | (0x01 << 5);
uint8 public constant ALT_HASHING_BRANCH_WITH_MASK =
FIRST_PREFIX | (0x01 << 4);
uint8 public constant NIBBLE_PER_BYTE = 2;
uint256 public constant NIBBLE_SIZE_BOUND = uint256(type(uint16).max);
uint256 public constant BITMAP_LENGTH = 2;
uint256 public constant HASH_lENGTH = 32;
function decodeNodeKind(
bytes memory encoded
) internal pure returns (NodeKind memory) {
NodeKind memory node;
ByteSlice memory input = ByteSlice(encoded, 0);
uint8 i = Bytes.readByte(input);
if (i == EMPTY_TRIE) {
node.isEmpty = true;
return node;
}
uint8 mask = i & (0x03 << 6);
if (mask == LEAF_PREFIX_MASK) {
node.nibbleSize = decodeSize(i, input, 2);
node.isLeaf = true;
} else if (mask == BRANCH_WITH_MASK) {
node.nibbleSize = decodeSize(i, input, 2);
node.isNibbledValueBranch = true;
} else if (mask == BRANCH_WITHOUT_MASK) {
node.nibbleSize = decodeSize(i, input, 2);
node.isNibbledBranch = true;
} else if (mask == EMPTY_TRIE) {
if (i & (0x07 << 5) == ALT_HASHING_LEAF_PREFIX_MASK) {
node.nibbleSize = decodeSize(i, input, 3);
node.isHashedLeaf = true;
} else if (i & (0x0F << 4) == ALT_HASHING_BRANCH_WITH_MASK) {
node.nibbleSize = decodeSize(i, input, 4);
node.isNibbledHashedValueBranch = true;
} else {
revert("Unallowed encoding");
}
}
node.data = input;
return node;
}
function decodeNibbledBranch(
NodeKind memory node
) internal pure returns (NibbledBranch memory) {
NibbledBranch memory nibbledBranch;
ByteSlice memory input = node.data;
bool padding = node.nibbleSize % NIBBLE_PER_BYTE != 0;
if (padding && (padLeft(uint8(input.data[input.offset])) != 0)) {
revert("Bad Format!");
}
uint256 nibbleLen = ((node.nibbleSize +
(NibbleSliceOps.NIBBLE_PER_BYTE - 1)) /
NibbleSliceOps.NIBBLE_PER_BYTE);
nibbledBranch.key = NibbleSlice(
Bytes.read(input, nibbleLen),
node.nibbleSize % NIBBLE_PER_BYTE
);
bytes memory bitmapBytes = Bytes.read(input, BITMAP_LENGTH);
uint16 bitmap = uint16(ScaleCodec.decodeUint256(bitmapBytes));
NodeHandleOption memory valueHandle;
if (node.isNibbledHashedValueBranch) {
valueHandle.isSome = true;
valueHandle.value.isHash = true;
valueHandle.value.hash = Bytes.toBytes32(
Bytes.read(input, HASH_lENGTH)
);
} else if (node.isNibbledValueBranch) {
uint256 len = ScaleCodec.decodeUintCompact(input);
valueHandle.isSome = true;
valueHandle.value.isInline = true;
valueHandle.value.inLine = Bytes.read(input, len);
}
nibbledBranch.value = valueHandle;
for (uint256 i = 0; i < 16; i++) {
NodeHandleOption memory childHandle;
if (valueAt(bitmap, i)) {
childHandle.isSome = true;
uint256 len = ScaleCodec.decodeUintCompact(input);
if (len == HASH_lENGTH) {
childHandle.value.isHash = true;
childHandle.value.hash = Bytes.toBytes32(
Bytes.read(input, HASH_lENGTH)
);
} else {
childHandle.value.isInline = true;
childHandle.value.inLine = Bytes.read(input, len);
}
}
nibbledBranch.children[i] = childHandle;
}
return nibbledBranch;
}
function decodeLeaf(
NodeKind memory node
) internal pure returns (Leaf memory) {
Leaf memory leaf;
ByteSlice memory input = node.data;
bool padding = node.nibbleSize % NIBBLE_PER_BYTE != 0;
if (padding && padLeft(uint8(input.data[input.offset])) != 0) {
revert("Bad Format!");
}
uint256 nibbleLen = (node.nibbleSize +
(NibbleSliceOps.NIBBLE_PER_BYTE - 1)) /
NibbleSliceOps.NIBBLE_PER_BYTE;
bytes memory nibbleBytes = Bytes.read(input, nibbleLen);
leaf.key = NibbleSlice(nibbleBytes, node.nibbleSize % NIBBLE_PER_BYTE);
NodeHandle memory handle;
if (node.isHashedLeaf) {
handle.isHash = true;
handle.hash = Bytes.toBytes32(Bytes.read(input, HASH_lENGTH));
} else {
uint256 len = ScaleCodec.decodeUintCompact(input);
handle.isInline = true;
handle.inLine = Bytes.read(input, len);
}
leaf.value = handle;
return leaf;
}
function decodeSize(
uint8 first,
ByteSlice memory encoded,
uint8 prefixMask
) internal pure returns (uint256) {
uint8 maxValue = uint8(255 >> prefixMask);
uint256 result = uint256(first & maxValue);
if (result < maxValue) {
return result;
}
result -= 1;
while (result <= NIBBLE_SIZE_BOUND) {
uint256 n = uint256(Bytes.readByte(encoded));
if (n < 255) {
return result + n + 1;
}
result += 255;
}
return NIBBLE_SIZE_BOUND;
}
function padLeft(uint8 b) internal pure returns (uint8) {
return b & ~PADDING_BITMASK;
}
function valueAt(uint16 bitmap, uint256 i) internal pure returns (bool) {
return bitmap & (uint16(1) << uint16(i)) != 0;
}
}
文件 23 的 24:TrieDB.sol
pragma solidity 0.8.20;
import "./Node.sol";
library TrieDB {
function get(
TrieNode[] memory nodes,
bytes32 hash
) internal pure returns (bytes memory) {
for (uint256 i = 0; i < nodes.length; i++) {
if (nodes[i].hash == hash) {
return nodes[i].node;
}
}
revert("Incomplete Proof!");
}
function load(
TrieNode[] memory nodes,
NodeHandle memory node
) internal pure returns (bytes memory) {
if (node.isInline) {
return node.inLine;
} else if (node.isHash) {
return get(nodes, node.hash);
}
return bytes("");
}
function isNibbledBranch(
NodeKind memory node
) internal pure returns (bool) {
return (node.isNibbledBranch ||
node.isNibbledHashedValueBranch ||
node.isNibbledValueBranch);
}
function isExtension(NodeKind memory node) internal pure returns (bool) {
return node.isExtension;
}
function isBranch(NodeKind memory node) internal pure returns (bool) {
return node.isBranch;
}
function isLeaf(NodeKind memory node) internal pure returns (bool) {
return (node.isLeaf || node.isHashedLeaf);
}
function isEmpty(NodeKind memory node) internal pure returns (bool) {
return node.isEmpty;
}
function isHash(NodeHandle memory node) internal pure returns (bool) {
return node.isHash;
}
function isInline(NodeHandle memory node) internal pure returns (bool) {
return node.isInline;
}
}
文件 24 的 24:Types.sol
pragma solidity 0.8.20;
struct StorageValue {
bytes key;
bytes value;
}
struct Node {
uint256 k_index;
bytes32 node;
}
struct MmrLeaf {
uint256 k_index;
uint256 leaf_index;
bytes32 hash;
}
struct Iterator {
uint256 offset;
bytes32[] data;
}
{
"compilationTarget": {
"contracts/adapters/DendrETH/DendrETHAdapter.sol": "DendrETHAdapter"
},
"evmVersion": "paris",
"libraries": {
"@polytope-labs/solidity-merkle-trees/src/MerklePatricia.sol:MerklePatricia": "0x3f94989763a27caeaf1f7aef4df2752cd5b58a5a"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 10000
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"dendrETHAddress","type":"address"},{"internalType":"uint256","name":"sourceChainId","type":"uint256"},{"internalType":"address","name":"sourceYaho","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"storedBlockHash","type":"bytes32"}],"name":"ConflictingBlockHeader","type":"error"},{"inputs":[],"name":"ErrorParseReceipt","type":"error"},{"inputs":[{"internalType":"bytes32","name":"finalizedHeader","type":"bytes32"}],"name":"FinalizedBlockHeaderNotAvailable","type":"error"},{"inputs":[],"name":"InvalidBlockHashProof","type":"error"},{"inputs":[],"name":"InvalidBlockHeaderRLP","type":"error"},{"inputs":[],"name":"InvalidBlockNumberProof","type":"error"},{"inputs":[],"name":"InvalidEventSignature","type":"error"},{"inputs":[],"name":"InvalidEventSource","type":"error"},{"inputs":[],"name":"InvalidReceiptsRoot","type":"error"},{"inputs":[],"name":"InvalidSlot","type":"error"},{"inputs":[],"name":"UnsupportedTxType","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"HashStored","type":"event"},{"inputs":[],"name":"DENDRETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SOURCE_CHAIN_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SOURCE_YAHO","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"domain","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"bytes[]","name":"blockHeaders","type":"bytes[]"}],"name":"proveAncestralBlockHashes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"finalizedBlockHeader","type":"bytes32"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes32[]","name":"blockNumberProof","type":"bytes32[]"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32[]","name":"blockHashProof","type":"bytes32[]"}],"name":"storeBlockHeader","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes32[]","name":"blockNumberProof","type":"bytes32[]"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32[]","name":"blockHashProof","type":"bytes32[]"},{"components":[{"internalType":"bytes32","name":"attestedHeaderRoot","type":"bytes32"},{"internalType":"uint256","name":"attestedHeaderSlot","type":"uint256"},{"internalType":"bytes32","name":"finalizedHeaderRoot","type":"bytes32"},{"internalType":"bytes32","name":"finalizedExecutionStateRoot","type":"bytes32"},{"internalType":"uint256[2]","name":"a","type":"uint256[2]"},{"internalType":"uint256[2][2]","name":"b","type":"uint256[2][2]"},{"internalType":"uint256[2]","name":"c","type":"uint256[2]"}],"internalType":"struct LightClientUpdate","name":"update","type":"tuple"}],"name":"storeBlockHeader","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"srcFinalizedHeader","type":"bytes32"},{"internalType":"uint64","name":"srcSlot","type":"uint64"},{"internalType":"bytes32[]","name":"slotProof","type":"bytes32[]"},{"internalType":"uint64","name":"txSlot","type":"uint64"},{"internalType":"bytes32[]","name":"receiptsRootProof","type":"bytes32[]"},{"internalType":"bytes32","name":"receiptsRoot","type":"bytes32"},{"internalType":"bytes[]","name":"receiptProof","type":"bytes[]"},{"internalType":"bytes","name":"txIndexRLPEncoded","type":"bytes"},{"internalType":"uint256","name":"logIndex","type":"uint256"}],"name":"verifyAndStoreDispatchedMessage","outputs":[],"stateMutability":"nonpayable","type":"function"}]