编译器
0.8.20+commit.a1b79de6
文件 1 的 25:Bytes.sol
pragma solidity ^0.8.17;
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;
}
}
文件 2 的 25:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 25:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 4 的 25:EthereumTrieDB.sol
pragma solidity ^0.8.17;
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);
}
}
文件 5 的 25:HandlerV1.sol
pragma solidity ^0.8.17;
import {MerkleMountainRange, MmrLeaf} from "@polytope-labs/solidity-merkle-trees/src/MerkleMountainRange.sol";
import {MerklePatricia, StorageValue} from "@polytope-labs/solidity-merkle-trees/src/MerklePatricia.sol";
import {Bytes} from "@polytope-labs/solidity-merkle-trees/src/trie/Bytes.sol";
import {IConsensusClient, IntermediateState, StateMachineHeight, StateCommitment} from "@polytope-labs/ismp-solidity/IConsensusClient.sol";
import {IIsmpHost, FeeMetadata, FrozenStatus} from "@polytope-labs/ismp-solidity/IIsmpHost.sol";
import {IHandler} from "@polytope-labs/ismp-solidity/IHandler.sol";
import {
Message,
PostResponse,
PostRequest,
GetRequest,
GetResponse,
PostRequestMessage,
PostResponseMessage,
GetResponseMessage,
PostRequestTimeoutMessage,
PostResponseTimeoutMessage,
GetTimeoutMessage,
PostRequestLeaf,
PostResponseLeaf,
GetResponseLeaf
} from "@polytope-labs/ismp-solidity/Message.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
bytes constant REQUEST_RECEIPTS_STORAGE_PREFIX = hex"526571756573745265636569707473";
bytes constant RESPONSE_RECEIPTS_STORAGE_PREFIX = hex"526573706f6e73655265636569707473";
contract HandlerV1 is IHandler, ERC165, Context {
using Bytes for bytes;
using Message for PostResponse;
using Message for PostRequest;
using Message for GetRequest;
using Message for GetResponse;
error ConsensusClientExpired();
error HostFrozen();
error ChallengePeriodNotElapsed();
error StateCommitmentNotFound();
error InvalidMessageDestination();
error MessageTimedOut();
error MessageNotTimedOut();
error DuplicateMessage();
error UnknownMessage();
error InvalidProof();
modifier notFrozen(IIsmpHost host) {
FrozenStatus state = host.frozen();
if (state == FrozenStatus.Incoming || state == FrozenStatus.All) revert HostFrozen();
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IHandler).interfaceId || super.supportsInterface(interfaceId);
}
function handleConsensus(IIsmpHost host, bytes calldata proof) external notFrozen(host) {
uint256 delay = block.timestamp - host.consensusUpdateTime();
if (delay >= host.unStakingPeriod()) revert ConsensusClientExpired();
(bytes memory verifiedState, IntermediateState[] memory intermediates) = IConsensusClient(
host.consensusClient()
).verifyConsensus(host.consensusState(), proof);
host.storeConsensusState(verifiedState);
uint256 intermediatesLen = intermediates.length;
for (uint256 i = 0; i < intermediatesLen; i++) {
IntermediateState memory intermediate = intermediates[i];
uint256 latestHeight = host.latestStateMachineHeight(intermediate.stateMachineId);
if (latestHeight != 0 && intermediate.height > latestHeight) {
StateMachineHeight memory stateMachineHeight = StateMachineHeight({
stateMachineId: intermediate.stateMachineId,
height: intermediate.height
});
host.storeStateMachineCommitment(stateMachineHeight, intermediate.commitment);
}
}
}
function handlePostRequests(IIsmpHost host, PostRequestMessage calldata request) external notFrozen(host) {
uint256 timestamp = block.timestamp;
uint256 delay = timestamp - host.stateMachineCommitmentUpdateTime(request.proof.height);
uint256 challengePeriod = host.challengePeriod();
if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed();
uint256 requestsLen = request.requests.length;
MmrLeaf[] memory leaves = new MmrLeaf[](requestsLen);
for (uint256 i = 0; i < requestsLen; ++i) {
PostRequestLeaf memory leaf = request.requests[i];
if (!leaf.request.dest.equals(host.host())) revert InvalidMessageDestination();
if (timestamp >= leaf.request.timeout()) revert MessageTimedOut();
bytes32 commitment = leaf.request.hash();
if (host.requestReceipts(commitment) != address(0)) revert DuplicateMessage();
leaves[i] = MmrLeaf(leaf.kIndex, leaf.index, commitment);
}
bytes32 root = host.stateMachineCommitment(request.proof.height).overlayRoot;
if (root == bytes32(0)) revert StateCommitmentNotFound();
bool valid = MerkleMountainRange.VerifyProof(root, request.proof.multiproof, leaves, request.proof.leafCount);
if (!valid) revert InvalidProof();
for (uint256 i = 0; i < requestsLen; ++i) {
PostRequestLeaf memory leaf = request.requests[i];
host.dispatchIncoming(leaf.request, _msgSender());
}
}
function handlePostResponses(IIsmpHost host, PostResponseMessage calldata response) external notFrozen(host) {
uint256 timestamp = block.timestamp;
uint256 delay = timestamp - host.stateMachineCommitmentUpdateTime(response.proof.height);
uint256 challengePeriod = host.challengePeriod();
if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed();
uint256 responsesLength = response.responses.length;
MmrLeaf[] memory leaves = new MmrLeaf[](responsesLength);
for (uint256 i = 0; i < responsesLength; ++i) {
PostResponseLeaf memory leaf = response.responses[i];
if (timestamp >= leaf.response.timeout()) revert MessageTimedOut();
bytes32 requestCommitment = leaf.response.request.hash();
FeeMetadata memory meta = host.requestCommitments(requestCommitment);
if (meta.sender == address(0)) revert InvalidProof();
if (host.responseReceipts(leaf.response.hash()).relayer != address(0)) revert DuplicateMessage();
leaves[i] = MmrLeaf(leaf.kIndex, leaf.index, leaf.response.hash());
}
bytes32 root = host.stateMachineCommitment(response.proof.height).overlayRoot;
if (root == bytes32(0)) revert StateCommitmentNotFound();
bool valid = MerkleMountainRange.VerifyProof(root, response.proof.multiproof, leaves, response.proof.leafCount);
if (!valid) revert InvalidProof();
for (uint256 i = 0; i < responsesLength; ++i) {
PostResponseLeaf memory leaf = response.responses[i];
host.dispatchIncoming(leaf.response, _msgSender());
}
}
function handleGetResponses(IIsmpHost host, GetResponseMessage calldata message) external notFrozen(host) {
uint256 timestamp = block.timestamp;
uint256 delay = timestamp - host.stateMachineCommitmentUpdateTime(message.proof.height);
uint256 challengePeriod = host.challengePeriod();
if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed();
uint256 responsesLength = message.responses.length;
MmrLeaf[] memory leaves = new MmrLeaf[](responsesLength);
for (uint256 i = 0; i < responsesLength; ++i) {
GetResponseLeaf memory leaf = message.responses[i];
bytes32 requestCommitment = leaf.response.request.hash();
FeeMetadata memory meta = host.requestCommitments(requestCommitment);
if (meta.sender == address(0)) revert UnknownMessage();
if (host.responseReceipts(requestCommitment).relayer != address(0)) revert DuplicateMessage();
leaves[i] = MmrLeaf(leaf.kIndex, leaf.index, leaf.response.hash());
}
bytes32 root = host.stateMachineCommitment(message.proof.height).overlayRoot;
if (root == bytes32(0)) revert StateCommitmentNotFound();
bool valid = MerkleMountainRange.VerifyProof(root, message.proof.multiproof, leaves, message.proof.leafCount);
if (!valid) revert InvalidProof();
for (uint256 i = 0; i < responsesLength; ++i) {
GetResponseLeaf memory leaf = message.responses[i];
host.dispatchIncoming(leaf.response, _msgSender());
}
}
function handlePostRequestTimeouts(
IIsmpHost host,
PostRequestTimeoutMessage calldata message
) external notFrozen(host) {
uint256 delay = block.timestamp - host.stateMachineCommitmentUpdateTime(message.height);
uint256 challengePeriod = host.challengePeriod();
if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed();
StateCommitment memory state = host.stateMachineCommitment(message.height);
if (state.stateRoot == bytes32(0)) revert StateCommitmentNotFound();
uint256 timeoutsLength = message.timeouts.length;
for (uint256 i = 0; i < timeoutsLength; ++i) {
PostRequest memory request = message.timeouts[i];
if (request.timeout() > state.timestamp) revert MessageNotTimedOut();
bytes32 requestCommitment = request.hash();
FeeMetadata memory meta = host.requestCommitments(requestCommitment);
if (meta.sender == address(0)) revert UnknownMessage();
bytes[] memory keys = new bytes[](1);
keys[i] = bytes.concat(REQUEST_RECEIPTS_STORAGE_PREFIX, bytes.concat(requestCommitment));
StorageValue memory entry = MerklePatricia.VerifySubstrateProof(state.stateRoot, message.proof, keys)[0];
if (entry.value.length != 0) revert InvalidProof();
host.dispatchTimeOut(request, meta, requestCommitment);
}
}
function handlePostResponseTimeouts(
IIsmpHost host,
PostResponseTimeoutMessage calldata message
) external notFrozen(host) {
uint256 delay = block.timestamp - host.stateMachineCommitmentUpdateTime(message.height);
uint256 challengePeriod = host.challengePeriod();
if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed();
StateCommitment memory state = host.stateMachineCommitment(message.height);
if (state.stateRoot == bytes32(0)) revert StateCommitmentNotFound();
uint256 timeoutsLength = message.timeouts.length;
for (uint256 i = 0; i < timeoutsLength; ++i) {
PostResponse memory response = message.timeouts[i];
if (response.timeout() > state.timestamp) revert MessageNotTimedOut();
bytes32 responseCommitment = response.hash();
FeeMetadata memory meta = host.responseCommitments(responseCommitment);
if (meta.sender == address(0)) revert UnknownMessage();
bytes[] memory keys = new bytes[](1);
keys[i] = bytes.concat(RESPONSE_RECEIPTS_STORAGE_PREFIX, bytes.concat(responseCommitment));
StorageValue memory entry = MerklePatricia.VerifySubstrateProof(state.stateRoot, message.proof, keys)[0];
if (entry.value.length != 0) revert InvalidProof();
host.dispatchTimeOut(response, meta, responseCommitment);
}
}
function handleGetRequestTimeouts(IIsmpHost host, GetTimeoutMessage calldata message) external notFrozen(host) {
uint256 delay = block.timestamp - host.stateMachineCommitmentUpdateTime(message.height);
uint256 challengePeriod = host.challengePeriod();
if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed();
StateCommitment memory state = host.stateMachineCommitment(message.height);
if (state.stateRoot == bytes32(0)) revert StateCommitmentNotFound();
uint256 timeoutsLength = message.timeouts.length;
for (uint256 i = 0; i < timeoutsLength; ++i) {
GetRequest memory request = message.timeouts[i];
if (request.timeout() > state.timestamp) revert MessageNotTimedOut();
bytes32 commitment = request.hash();
FeeMetadata memory meta = host.requestCommitments(commitment);
if (meta.sender == address(0)) revert UnknownMessage();
bytes[] memory keys = new bytes[](1);
keys[i] = bytes.concat(REQUEST_RECEIPTS_STORAGE_PREFIX, bytes.concat(commitment));
StorageValue memory entry = MerklePatricia.VerifySubstrateProof(state.stateRoot, message.proof, keys)[0];
if (entry.value.length != 0) revert InvalidProof();
host.dispatchTimeOut(request, meta, commitment);
}
}
}
文件 6 的 25:IConsensusClient.sol
pragma solidity ^0.8.17;
import {StateMachineHeight} from "./Message.sol";
struct StateCommitment {
uint256 timestamp;
bytes32 overlayRoot;
bytes32 stateRoot;
}
struct IntermediateState {
uint256 stateMachineId;
uint256 height;
StateCommitment commitment;
}
interface IConsensusClient {
function verifyConsensus(
bytes memory trustedState,
bytes memory proof
) external returns (bytes memory, IntermediateState[] memory);
}
文件 7 的 25:IDispatcher.sol
pragma solidity ^0.8.17;
import {PostRequest, StateMachineHeight} from "./Message.sol";
struct DispatchPost {
bytes dest;
bytes to;
bytes body;
uint64 timeout;
uint256 fee;
address payer;
}
struct DispatchGet {
bytes dest;
uint64 height;
bytes[] keys;
uint64 timeout;
uint256 fee;
bytes context;
}
struct DispatchPostResponse {
PostRequest request;
bytes response;
uint64 timeout;
uint256 fee;
address payer;
}
interface IDispatcher {
function uniswapV2Router() external view returns (address);
function nonce() external view returns (uint256);
function feeToken() external view returns (address);
function perByteFee(bytes memory dest) external view returns (uint256);
function dispatch(DispatchPost memory request) external payable returns (bytes32 commitment);
function dispatch(DispatchGet memory request) external payable returns (bytes32 commitment);
function dispatch(DispatchPostResponse memory response) external payable returns (bytes32 commitment);
function fundRequest(bytes32 commitment, uint256 amount) external payable;
function fundResponse(bytes32 commitment, uint256 amount) external payable;
}
文件 8 的 25:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 9 的 25:IHandler.sol
pragma solidity ^0.8.17;
import {IIsmpHost} from "./IIsmpHost.sol";
import {PostRequestMessage, PostResponseMessage, GetResponseMessage, PostRequestTimeoutMessage, PostResponseTimeoutMessage, GetTimeoutMessage} from "./Message.sol";
interface IHandler {
function handleConsensus(IIsmpHost host, bytes memory proof) external;
function handlePostRequests(IIsmpHost host, PostRequestMessage memory request) external;
function handlePostResponses(IIsmpHost host, PostResponseMessage memory response) external;
function handleGetResponses(IIsmpHost host, GetResponseMessage memory message) external;
function handlePostRequestTimeouts(IIsmpHost host, PostRequestTimeoutMessage memory message) external;
function handlePostResponseTimeouts(IIsmpHost host, PostResponseTimeoutMessage memory message) external;
function handleGetRequestTimeouts(IIsmpHost host, GetTimeoutMessage memory message) external;
}
文件 10 的 25:IIsmpHost.sol
pragma solidity ^0.8.17;
import {StateCommitment, StateMachineHeight} from "./IConsensusClient.sol";
import {IDispatcher} from "./IDispatcher.sol";
import {PostRequest, PostResponse, GetResponse, GetRequest} from "./Message.sol";
struct FeeMetadata {
uint256 fee;
address sender;
}
struct ResponseReceipt {
bytes32 responseCommitment;
address relayer;
}
enum FrozenStatus {
None,
Incoming,
Outgoing,
All
}
interface IIsmpHost is IDispatcher {
function admin() external returns (address);
function host() external view returns (bytes memory);
function hyperbridge() external view returns (bytes memory);
function timestamp() external view returns (uint256);
function vetoes(uint256 paraId, uint256 height) external view returns (address);
function frozen() external view returns (FrozenStatus);
function stateCommitmentFee() external view returns (uint256);
function stateMachineCommitment(StateMachineHeight memory height) external payable returns (StateCommitment memory);
function stateMachineCommitmentUpdateTime(StateMachineHeight memory height) external returns (uint256);
function consensusClient() external view returns (address);
function consensusUpdateTime() external view returns (uint256);
function latestStateMachineHeight(uint256 stateMachineId) external view returns (uint256);
function consensusState() external view returns (bytes memory);
function responded(bytes32 commitment) external view returns (bool);
function requestReceipts(bytes32 commitment) external view returns (address);
function responseReceipts(bytes32 commitment) external view returns (ResponseReceipt memory);
function requestCommitments(bytes32 commitment) external view returns (FeeMetadata memory);
function responseCommitments(bytes32 commitment) external view returns (FeeMetadata memory);
function challengePeriod() external view returns (uint256);
function unStakingPeriod() external view returns (uint256);
function setFrozenState(FrozenStatus newState) external;
function storeConsensusState(bytes memory state) external;
function storeStateMachineCommitment(StateMachineHeight memory height, StateCommitment memory commitment) external;
function deleteStateMachineCommitment(StateMachineHeight memory height, address fisherman) external;
function dispatchIncoming(PostRequest memory request, address relayer) external;
function dispatchIncoming(PostResponse memory response, address relayer) external;
function dispatchIncoming(GetResponse memory response, address relayer) external;
function dispatchTimeOut(GetRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external;
function dispatchTimeOut(PostRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external;
function dispatchTimeOut(PostResponse memory timeout, FeeMetadata memory meta, bytes32 commitment) external;
}
文件 11 的 25: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);
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 * 8) < value ? 1 : 0);
}
}
}
文件 12 的 25:Memory.sol
pragma solidity ^0.8.17;
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)
}
}
}
文件 13 的 25:MerkleMountainRange.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/utils/math/Math.sol";
import "./Types.sol";
import "./MerkleMultiProof.sol";
library MerkleMountainRange {
function VerifyProof(
bytes32 root,
bytes32[] memory proof,
MmrLeaf[] memory leaves,
uint256 mmrSize
) internal pure returns (bool) {
return root == CalculateRoot(proof, leaves, mmrSize);
}
function CalculateRoot(
bytes32[] memory proof,
MmrLeaf[] memory leaves,
uint256 leafCount
) internal pure returns (bytes32) {
if (leafCount == 1 && leaves.length == 1 && leaves[0].leaf_index == 0) {
return leaves[0].hash;
}
uint256[] memory subtrees = subtreeHeights(leafCount);
uint256 length = subtrees.length;
Iterator memory peakRoots = Iterator(0, new bytes32[](length));
Iterator memory proofIter = Iterator(0, proof);
uint256 current_subtree;
for (uint256 p; p < length; ) {
uint256 height = subtrees[p];
current_subtree += 2 ** height;
MmrLeaf[] memory subtreeLeaves = new MmrLeaf[](0);
if (leaves.length > 0) {
(subtreeLeaves, leaves) = leavesForSubtree(
leaves,
current_subtree
);
}
if (subtreeLeaves.length == 0) {
if (proofIter.data.length == proofIter.offset) {
break;
} else {
push(peakRoots, next(proofIter));
}
} else if (subtreeLeaves.length == 1 && height == 0) {
push(peakRoots, subtreeLeaves[0].hash);
} else {
push(
peakRoots,
CalculateSubtreeRoot(subtreeLeaves, proofIter, height)
);
}
unchecked {
++p;
}
}
unchecked {
peakRoots.offset--;
}
while (peakRoots.offset != 0) {
bytes32 right = previous(peakRoots);
bytes32 left = previous(peakRoots);
unchecked {
++peakRoots.offset;
}
peakRoots.data[peakRoots.offset] = keccak256(
abi.encodePacked(right, left)
);
}
return peakRoots.data[0];
}
function subtreeHeights(
uint256 leavesLength
) internal pure returns (uint256[] memory) {
uint256 maxSubtrees = 64;
uint256[] memory indices = new uint256[](maxSubtrees);
uint256 i;
uint256 current = leavesLength;
for (; i < maxSubtrees; ) {
if (current == 0) {
break;
}
uint256 log = Math.log2(current);
indices[i] = log;
current = current - 2 ** log;
unchecked {
++i;
}
}
uint256 excess = maxSubtrees - i;
assembly {
mstore(indices, sub(mload(indices), excess))
}
return indices;
}
function CalculateSubtreeRoot(
MmrLeaf[] memory peakLeaves,
Iterator memory proofIter,
uint256 height
) internal pure returns (bytes32) {
uint256[] memory current_layer;
Node[] memory leaves;
(leaves, current_layer) = mmrLeafToNode(peakLeaves);
Node[][] memory layers = new Node[][](height);
for (uint256 i; i < height; ) {
uint256 nodelength = 2 ** (height - i);
if (current_layer.length == nodelength) {
break;
}
uint256[] memory siblings = siblingIndices(current_layer);
uint256[] memory diff = difference(siblings, current_layer);
uint256 length = diff.length;
layers[i] = new Node[](length);
for (uint256 j; j < length; ) {
layers[i][j] = Node(diff[j], next(proofIter));
unchecked {
++j;
}
}
current_layer = parentIndices(siblings);
unchecked {
++i;
}
}
return MerkleMultiProof.CalculateRoot(layers, leaves);
}
function difference(
uint256[] memory left,
uint256[] memory right
) internal pure returns (uint256[] memory) {
uint256 length = left.length;
uint256 rightLength = right.length;
uint256[] memory diff = new uint256[](length);
uint256 d;
for (uint256 i; i < length; ) {
bool found;
for (uint256 j; j < rightLength; ) {
if (left[i] == right[j]) {
found = true;
break;
}
unchecked {
++j;
}
}
if (!found) {
diff[d] = left[i];
d++;
}
unchecked {
++i;
}
}
uint256 excess = length - d;
assembly {
mstore(diff, sub(mload(diff), excess))
}
return diff;
}
function siblingIndices(
uint256[] memory indices
) internal pure returns (uint256[] memory) {
uint256 length = indices.length;
uint256[] memory siblings = new uint256[](length);
for (uint256 i; i < length; ) {
uint256 index = indices[i];
if (index == 0) {
siblings[i] = index + 1;
} else if (index % 2 == 0) {
siblings[i] = index + 1;
} else {
siblings[i] = index - 1;
}
unchecked {
++i;
}
}
return siblings;
}
function parentIndices(
uint256[] memory indices
) internal pure returns (uint256[] memory) {
uint256 length = indices.length;
uint256[] memory parents = new uint256[](length);
uint256 k;
for (uint256 i; i < length; i++) {
uint256 index = indices[i] / 2;
if (k > 0 && parents[k - 1] == index) {
continue;
}
parents[k] = index;
unchecked {
++k;
}
}
uint256 excess = length - k;
assembly {
mstore(parents, sub(mload(parents), excess))
}
return parents;
}
function mmrLeafToNode(
MmrLeaf[] memory leaves
) internal pure returns (Node[] memory, uint256[] memory) {
uint256 i;
uint256 length = leaves.length;
Node[] memory nodes = new Node[](length);
uint256[] memory indices = new uint256[](length);
while (i < length) {
nodes[i] = Node(leaves[i].k_index, leaves[i].hash);
indices[i] = leaves[i].k_index;
++i;
}
return (nodes, indices);
}
function leavesForSubtree(
MmrLeaf[] memory leaves,
uint256 leafIndex
) internal pure returns (MmrLeaf[] memory, MmrLeaf[] memory) {
uint256 p;
uint256 length = leaves.length;
for (; p < length; p++) {
if (leafIndex <= leaves[p].leaf_index) {
break;
}
}
uint256 len = p == 0 ? 0 : p;
MmrLeaf[] memory left = new MmrLeaf[](len);
MmrLeaf[] memory right = new MmrLeaf[](length - len);
uint256 i;
uint256 leftLength = left.length;
while (i < leftLength) {
left[i] = leaves[i];
++i;
}
uint256 j;
while (i < length) {
right[j] = leaves[i];
++i;
++j;
}
return (left, right);
}
function push(Iterator memory iterator, bytes32 data) internal pure {
iterator.data[iterator.offset] = data;
unchecked {
++iterator.offset;
}
}
function next(Iterator memory iterator) internal pure returns (bytes32) {
bytes32 data = iterator.data[iterator.offset];
unchecked {
++iterator.offset;
}
return data;
}
function previous(
Iterator memory iterator
) internal pure returns (bytes32) {
bytes32 data = iterator.data[iterator.offset];
unchecked {
--iterator.offset;
}
return data;
}
}
文件 14 的 25:MerkleMultiProof.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/utils/math/Math.sol";
import "./Types.sol";
library MerkleMultiProof {
function VerifyProof(
bytes32 root,
Node[][] memory proof,
Node[] memory leaves
) internal pure returns (bool) {
return root == CalculateRoot(proof, leaves);
}
function VerifyProofSorted(
bytes32 root,
Node[][] memory proof,
Node[] memory leaves
) internal pure returns (bool) {
return root == CalculateRootSorted(proof, leaves);
}
function CalculateRoot(
Node[][] memory proof,
Node[] memory leaves
) internal pure returns (bytes32) {
Node[] memory next_layer = new Node[](0);
proof[0] = mergeSort(leaves, proof[0]);
uint256 proof_length = proof.length;
for (uint256 height = 0; height < proof_length; height++) {
Node[] memory current_layer = new Node[](0);
if (next_layer.length == 0) {
current_layer = proof[height];
} else {
current_layer = mergeSort(proof[height], next_layer);
}
next_layer = new Node[](div_ceil(current_layer.length, 2));
uint256 p = 0;
uint256 current_layer_length = current_layer.length;
for (uint256 index = 0; index < current_layer_length; index += 2) {
if (index + 1 >= current_layer_length) {
Node memory node = current_layer[index];
node.k_index = div_floor(current_layer[index].k_index, 2);
next_layer[p] = node;
} else {
Node memory node;
node.k_index = div_floor(current_layer[index].k_index, 2);
node.node = _optimizedHash(
current_layer[index].node,
current_layer[index + 1].node
);
next_layer[p] = node;
unchecked {
p++;
}
}
}
}
require(next_layer.length == 1);
return next_layer[0].node;
}
function CalculateRootSorted(
Node[][] memory proof,
Node[] memory leaves
) internal pure returns (bytes32) {
Node[] memory next_layer = new Node[](0);
proof[0] = mergeSort(leaves, proof[0]);
uint256 proof_length = proof.length;
for (uint256 height = 0; height < proof_length; height++) {
Node[] memory current_layer = new Node[](0);
if (next_layer.length == 0) {
current_layer = proof[height];
} else {
current_layer = mergeSort(proof[height], next_layer);
}
uint256 current_layer_length = current_layer.length;
uint256 p = 0;
next_layer = new Node[](div_ceil(current_layer_length, 2));
for (uint256 index = 0; index < current_layer_length; index += 2) {
if (index + 1 >= current_layer_length) {
Node memory node = current_layer[index];
node.k_index = div_floor(current_layer[index].k_index, 2);
next_layer[p] = node;
} else {
Node memory node;
bytes32 a = current_layer[index].node;
bytes32 b = current_layer[index + 1].node;
if (a < b) {
node.node = _optimizedHash(a, b);
} else {
node.node = _optimizedHash(b, a);
}
node.k_index = div_floor(current_layer[index].k_index, 2);
next_layer[p] = node;
unchecked {
p++;
}
}
}
}
require(next_layer.length == 1);
return next_layer[0].node;
}
function div_floor(uint256 x, uint256 y) internal pure returns (uint256) {
return x / y;
}
function div_ceil(uint256 x, uint256 y) internal pure returns (uint256) {
uint256 result = x / y;
if (x % y != 0) {
unchecked {
result += 1;
}
}
return result;
}
function mergeSort(
Node[] memory arr1,
Node[] memory arr2
) internal pure returns (Node[] memory) {
uint256 i = 0;
uint256 j = 0;
uint256 k = 0;
uint256 arr1_length = arr1.length;
uint256 arr2_length = arr2.length;
uint256 out_len = arr1_length + arr2_length;
Node[] memory out = new Node[](out_len);
while (i < arr1_length && j < arr2_length) {
if (arr1[i].k_index < arr2[j].k_index) {
out[k] = arr1[i];
unchecked {
i++;
k++;
}
} else {
out[k] = arr2[j];
unchecked {
j++;
k++;
}
}
}
while (i < arr1_length) {
out[k] = arr1[i];
unchecked {
i++;
k++;
}
}
while (j < arr2_length) {
out[k] = arr2[j];
unchecked {
j++;
k++;
}
}
return out;
}
function _optimizedHash(
bytes32 node1,
bytes32 node2
) internal pure returns (bytes32 hash) {
assembly {
mstore(0x0, node1)
mstore(0x20, node2)
hash := keccak256(0x0, 0x40)
}
}
function TreeHeight(uint256 leavesCount) internal pure returns (uint256) {
uint256 height = Math.log2(leavesCount, Math.Rounding.Up);
if (!isPowerOfTwo(leavesCount)) {
unchecked {
height++;
}
}
return height;
}
function isPowerOfTwo(uint256 x) internal pure returns (bool) {
if (x == 0) {
return false;
}
return (x & (x - 1)) == 0;
}
}
文件 15 的 25:MerklePatricia.sol
pragma solidity ^0.8.17;
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;
}
}
文件 16 的 25:Message.sol
pragma solidity ^0.8.17;
import {StorageValue} from "@polytope-labs/solidity-merkle-trees/src/Types.sol";
struct StateMachineHeight {
uint256 stateMachineId;
uint256 height;
}
struct PostRequest {
bytes source;
bytes dest;
uint64 nonce;
bytes from;
bytes to;
uint64 timeoutTimestamp;
bytes body;
}
struct GetRequest {
bytes source;
bytes dest;
uint64 nonce;
address from;
uint64 timeoutTimestamp;
bytes[] keys;
uint64 height;
bytes context;
}
struct GetResponse {
GetRequest request;
StorageValue[] values;
}
struct PostResponse {
PostRequest request;
bytes response;
uint64 timeoutTimestamp;
}
struct PostRequestLeaf {
PostRequest request;
uint256 index;
uint256 kIndex;
}
struct PostResponseLeaf {
PostResponse response;
uint256 index;
uint256 kIndex;
}
struct GetResponseLeaf {
GetResponse response;
uint256 index;
uint256 kIndex;
}
struct Proof {
StateMachineHeight height;
bytes32[] multiproof;
uint256 leafCount;
}
struct PostRequestMessage {
Proof proof;
PostRequestLeaf[] requests;
}
struct GetResponseMessage {
Proof proof;
GetResponseLeaf[] responses;
}
struct GetTimeoutMessage {
GetRequest[] timeouts;
StateMachineHeight height;
bytes[] proof;
}
struct PostRequestTimeoutMessage {
PostRequest[] timeouts;
StateMachineHeight height;
bytes[] proof;
}
struct PostResponseTimeoutMessage {
PostResponse[] timeouts;
StateMachineHeight height;
bytes[] proof;
}
struct PostResponseMessage {
Proof proof;
PostResponseLeaf[] responses;
}
library Message {
function timeout(PostRequest memory req) internal pure returns (uint64) {
if (req.timeoutTimestamp == 0) {
return type(uint64).max;
} else {
return req.timeoutTimestamp;
}
}
function timeout(GetRequest memory req) internal pure returns (uint64) {
if (req.timeoutTimestamp == 0) {
return type(uint64).max;
} else {
return req.timeoutTimestamp;
}
}
function timeout(PostResponse memory res) internal pure returns (uint64) {
if (res.timeoutTimestamp == 0) {
return type(uint64).max;
} else {
return res.timeoutTimestamp;
}
}
function encode(PostRequest memory req) internal pure returns (bytes memory) {
return abi.encodePacked(req.source, req.dest, req.nonce, req.timeoutTimestamp, req.from, req.to, req.body);
}
function encode(GetRequest memory req) internal pure returns (bytes memory) {
bytes memory keysEncoding = bytes("");
uint256 len = req.keys.length;
for (uint256 i = 0; i < len; i++) {
keysEncoding = bytes.concat(keysEncoding, req.keys[i]);
}
return
abi.encodePacked(
req.source,
req.dest,
req.nonce,
req.height,
req.timeoutTimestamp,
abi.encodePacked(req.from),
keysEncoding,
req.context
);
}
function hash(PostResponse memory res) internal pure returns (bytes32) {
return keccak256(bytes.concat(encode(res.request), abi.encodePacked(res.response, res.timeoutTimestamp)));
}
function hash(PostRequest memory req) internal pure returns (bytes32) {
return keccak256(encode(req));
}
function hash(GetRequest memory req) internal pure returns (bytes32) {
return keccak256(encode(req));
}
function hash(GetResponse memory res) internal pure returns (bytes32) {
bytes memory response = bytes("");
uint256 len = res.values.length;
for (uint256 i = 0; i < len; i++) {
response = bytes.concat(response, bytes.concat(res.values[i].key, res.values[i].value));
}
return keccak256(bytes.concat(encode(res.request), response));
}
}
文件 17 的 25:NibbleSlice.sol
pragma solidity ^0.8.17;
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;
}
}
文件 18 的 25:Node.sol
pragma solidity ^0.8.17;
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;
}
文件 19 的 25:Option.sol
pragma solidity ^0.8.17;
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;
}
}
文件 20 的 25: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))
}
}
}
}
文件 21 的 25:ScaleCodec.sol
pragma solidity ^0.8.17;
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);
}
}
文件 22 的 25:Strings.sol
pragma solidity ^0.8.0;
import "./math/Math.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 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);
}
}
文件 23 的 25:SubstrateTrieDB.sol
pragma solidity ^0.8.17;
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;
}
}
文件 24 的 25:TrieDB.sol
pragma solidity ^0.8.17;
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;
}
}
文件 25 的 25:Types.sol
pragma solidity ^0.8.17;
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": {
"src/modules/HandlerV1.sol": "HandlerV1"
},
"evmVersion": "paris",
"libraries": {
"node_modules/@polytope-labs/solidity-merkle-trees/src/MerklePatricia.sol:MerklePatricia": "0x60556cc1daf7fbb0e02f7b2f684216a0d3de7132",
"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/ethereum/EthereumTrieDB.sol:EthereumTrieDB": "0x18755df4d7370de3131507f1e8b9fa2885c97e8e",
"src/consensus/Header.sol:HeaderImpl": "0xbe327087a0c330893e5a8bc5cd4799079f20a395"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin/=node_modules/openzeppelin-solidity/",
":@polytope-labs/erc6160/=node_modules/@polytope-labs/erc6160/src/",
":@polytope-labs/ismp-solidity/=node_modules/@polytope-labs/ismp-solidity/interfaces/",
":@polytope-labs/solidity-merkle-trees/=node_modules/@polytope-labs/solidity-merkle-trees/",
":@sp1-contracts/=lib/sp1-contracts/contracts/src/",
":@uniswap/v2-periphery/=node_modules/@uniswap/v2-periphery/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/",
":solidity-stringutils/=lib/solidity-stringutils/",
":sp1-contracts/=lib/sp1-contracts/contracts/",
":stringutils/=lib/solidity-stringutils/src/"
]
}
[{"inputs":[],"name":"ChallengePeriodNotElapsed","type":"error"},{"inputs":[],"name":"ConsensusClientExpired","type":"error"},{"inputs":[],"name":"DuplicateMessage","type":"error"},{"inputs":[],"name":"HostFrozen","type":"error"},{"inputs":[],"name":"InvalidMessageDestination","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"MessageNotTimedOut","type":"error"},{"inputs":[],"name":"MessageTimedOut","type":"error"},{"inputs":[],"name":"StateCommitmentNotFound","type":"error"},{"inputs":[],"name":"UnknownMessage","type":"error"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"handleConsensus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct GetRequest[]","name":"timeouts","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes[]","name":"proof","type":"bytes[]"}],"internalType":"struct GetTimeoutMessage","name":"message","type":"tuple"}],"name":"handleGetRequestTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes32[]","name":"multiproof","type":"bytes32[]"},{"internalType":"uint256","name":"leafCount","type":"uint256"}],"internalType":"struct Proof","name":"proof","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct GetRequest","name":"request","type":"tuple"},{"components":[{"internalType":"bytes","name":"key","type":"bytes"},{"internalType":"bytes","name":"value","type":"bytes"}],"internalType":"struct StorageValue[]","name":"values","type":"tuple[]"}],"internalType":"struct GetResponse","name":"response","type":"tuple"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"kIndex","type":"uint256"}],"internalType":"struct GetResponseLeaf[]","name":"responses","type":"tuple[]"}],"internalType":"struct GetResponseMessage","name":"message","type":"tuple"}],"name":"handleGetResponses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest[]","name":"timeouts","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes[]","name":"proof","type":"bytes[]"}],"internalType":"struct PostRequestTimeoutMessage","name":"message","type":"tuple"}],"name":"handlePostRequestTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes32[]","name":"multiproof","type":"bytes32[]"},{"internalType":"uint256","name":"leafCount","type":"uint256"}],"internalType":"struct Proof","name":"proof","type":"tuple"},{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"kIndex","type":"uint256"}],"internalType":"struct PostRequestLeaf[]","name":"requests","type":"tuple[]"}],"internalType":"struct PostRequestMessage","name":"request","type":"tuple"}],"name":"handlePostRequests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse[]","name":"timeouts","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes[]","name":"proof","type":"bytes[]"}],"internalType":"struct PostResponseTimeoutMessage","name":"message","type":"tuple"}],"name":"handlePostResponseTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes32[]","name":"multiproof","type":"bytes32[]"},{"internalType":"uint256","name":"leafCount","type":"uint256"}],"internalType":"struct Proof","name":"proof","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse","name":"response","type":"tuple"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"kIndex","type":"uint256"}],"internalType":"struct PostResponseLeaf[]","name":"responses","type":"tuple[]"}],"internalType":"struct PostResponseMessage","name":"response","type":"tuple"}],"name":"handlePostResponses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]