Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(protocol): fix LibTrieProof.verifyMerkleProof by RLP-encoding the byte32 value first #16018

Merged
merged 2 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions packages/protocol/contracts/libs/LibTrieProof.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@

pragma solidity ^0.8.24;

import { RLPReader } from "../thirdparty/optimism/rlp/RLPReader.sol";
import { SecureMerkleTrie } from "../thirdparty/optimism/trie/SecureMerkleTrie.sol";
import "../thirdparty/optimism/rlp/RLPReader.sol";
import "../thirdparty/optimism/rlp/RLPWriter.sol";
import "../thirdparty/optimism/trie/SecureMerkleTrie.sol";

/**
* @title LibTrieProof
*/
/// @title LibTrieProof
library LibTrieProof {
// The consensus format representing account is RLP encoded in the
// following order: nonce, balance, storageHash, codeHash.
Expand All @@ -35,7 +34,7 @@ library LibTrieProof {
bytes32 rootHash,
address addr,
bytes32 slot,
bytes memory value,
bytes32 value,
bytes[] memory accountProof,
bytes[] memory storageProof
)
Expand All @@ -58,7 +57,10 @@ library LibTrieProof {
}

bool verified = SecureMerkleTrie.verifyInclusionProof(
bytes.concat(slot), value, storageProof, bytes32(storageRoot)
bytes.concat(slot),
RLPWriter.writeUint(uint256(value)),
storageProof,
bytes32(storageRoot)
);

if (!verified) revert LTP_INVALID_INCLUSION_PROOF();
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/signal/SignalService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ contract SignalService is EssentialContract, ISignalService {
hop.rootHash,
signalService,
getSignalSlot(chainId, app, signal),
bytes.concat(value),
value,
hop.accountProof,
hop.storageProof
);
Expand Down
163 changes: 163 additions & 0 deletions packages/protocol/contracts/thirdparty/optimism/rlp/RLPWriter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/// @custom:attribution https://github.com/bakaoh/solidity-rlp-encode
/// @title RLPWriter
/// @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's
/// RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor
/// modifications to improve legibility.
library RLPWriter {
/// @notice RLP encodes a byte string.
/// @param _in The byte string to encode.
/// @return out_ The RLP encoded string in bytes.
function writeBytes(bytes memory _in) internal pure returns (bytes memory out_) {
if (_in.length == 1 && uint8(_in[0]) < 128) {
out_ = _in;
} else {
out_ = abi.encodePacked(_writeLength(_in.length, 128), _in);
}
}

/// @notice RLP encodes a list of RLP encoded byte byte strings.
/// @param _in The list of RLP encoded byte strings.
/// @return list_ The RLP encoded list of items in bytes.
function writeList(bytes[] memory _in) internal pure returns (bytes memory list_) {
list_ = _flatten(_in);
list_ = abi.encodePacked(_writeLength(list_.length, 192), list_);
}

/// @notice RLP encodes a string.
/// @param _in The string to encode.
/// @return out_ The RLP encoded string in bytes.
function writeString(string memory _in) internal pure returns (bytes memory out_) {
out_ = writeBytes(bytes(_in));
}

/// @notice RLP encodes an address.
/// @param _in The address to encode.
/// @return out_ The RLP encoded address in bytes.
function writeAddress(address _in) internal pure returns (bytes memory out_) {
out_ = writeBytes(abi.encodePacked(_in));
}

/// @notice RLP encodes a uint.
/// @param _in The uint256 to encode.
/// @return out_ The RLP encoded uint256 in bytes.
function writeUint(uint256 _in) internal pure returns (bytes memory out_) {
out_ = writeBytes(_toBinary(_in));
}

/// @notice RLP encodes a bool.
/// @param _in The bool to encode.
/// @return out_ The RLP encoded bool in bytes.
function writeBool(bool _in) internal pure returns (bytes memory out_) {
out_ = new bytes(1);
out_[0] = (_in ? bytes1(0x01) : bytes1(0x80));
}

/// @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.
/// @param _len The length of the string or the payload.
/// @param _offset 128 if item is string, 192 if item is list.
/// @return out_ RLP encoded bytes.
function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory out_) {
if (_len < 56) {
out_ = new bytes(1);
out_[0] = bytes1(uint8(_len) + uint8(_offset));
} else {
uint256 lenLen;
uint256 i = 1;
while (_len / i != 0) {
lenLen++;
i *= 256;
}

out_ = new bytes(lenLen + 1);
out_[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);
for (i = 1; i <= lenLen; i++) {
out_[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256));
}
}
}

/// @notice Encode integer in big endian binary form with no leading zeroes.
/// @param _x The integer to encode.
/// @return out_ RLP encoded bytes.
function _toBinary(uint256 _x) private pure returns (bytes memory out_) {
bytes memory b = abi.encodePacked(_x);

uint256 i = 0;
for (; i < 32; i++) {
if (b[i] != 0) {
break;
}
}

out_ = new bytes(32 - i);
for (uint256 j = 0; j < out_.length; j++) {
out_[j] = b[i++];
}
}

/// @custom:attribution https://github.com/Arachnid/solidity-stringutils
/// @notice Copies a piece of memory to another location.
/// @param _dest Destination location.
/// @param _src Source location.
/// @param _len Length of memory to copy.
function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure {
uint256 dest = _dest;
uint256 src = _src;
uint256 len = _len;

for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}

uint256 mask;
unchecked {
mask = 256 ** (32 - len) - 1;
}
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}

/// @custom:attribution https://github.com/sammayo/solidity-rlp-encoder
/// @notice Flattens a list of byte strings into one byte string.
/// @param _list List of byte strings to flatten.
/// @return out_ The flattened byte string.
function _flatten(bytes[] memory _list) private pure returns (bytes memory out_) {
if (_list.length == 0) {
return new bytes(0);
}

uint256 len;
uint256 i = 0;
for (; i < _list.length; i++) {
len += _list[i].length;
}

out_ = new bytes(len);
uint256 flattenedPtr;
assembly {
flattenedPtr := add(out_, 0x20)
}

for (i = 0; i < _list.length; i++) {
bytes memory item = _list[i];

uint256 listPtr;
assembly {
listPtr := add(item, 0x20)
}

_memcpy(flattenedPtr, listPtr, item.length);
flattenedPtr += _list[i].length;
}
}
}
40 changes: 40 additions & 0 deletions packages/protocol/test/libs/LibTrieProof.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,44 @@ contract TestLibTrieProof is TaikoTest {

assertEq(storageRoot2, storageRoot);
}

function test_jeff_slot_value_not_1() public {
// signal service address on internal testnet l1
address addr = 0x83e383dec6E3C2CD167E3bF6aA8c36F0e55Ad910;
// signalService.getStorageSlot(event.srcchainid, event.Raw.Address [the bridge address on
// L1], event.MsgHash)
bytes32 slot = 0x07bfd8daaa640fc5f384ee9b5c1f8984e3075701525ff86aa1c6fe62b09fc2bc;
// block.Root() of the block used to get the proof
bytes32 stateRoot = 0x0883e3ee355161a08c1696409375ea33f4bb53a9121bc90bc4d69c4f285382aa;

bytes[] memory accountProof = new bytes[](3);
// eth_getProof responds some bytes
accountProof[0] =
hex"f90211a0f776494ecffe03ad2af2426ee4fb5ae66c012c03ea3955d5b40a52fe7c6b8df6a0ef4a67411e4accae9bbb05bbcc17d036432de4e3ee0b0d02a04ee6a67db9c1a5a06c4c8f2b3206553ec83f1081a6742edff2f7b7830d3ba4166872c4f3f32bae0ba0aa2e8d96490616498fa142ba7c6a628e2839b9b182c9995992ecf1c1d346784fa0f8d7262d0abdf5d084338a640322c4dd45b1484a630331922afa60256917058aa0e49099e467972084cd70025874c6ae0a6841159aec02f39384de2d9ae7460986a02ad2a355fe840ae1bfe7843616d6bb027c1fd478918cc956e0ca7b61ec0044d0a061ec8e714d951772d74765ae997bd25f3982ea8a0c4dda8baa1e47adbd5a3975a039e5f7e8298126da1e7d6f42b1f20846d68ff40dc857b0dd251d2791c0345589a065f4d771a35d862a10b2a2da6d7d6c1e082cd59280cbab1c8e6aaf89069e72dca07851c1d2a801228a1adb24b61a5b4e1d4e12c5043a0af1b1790cd79b281c43a0a031acf4e7bd8cfb52c19cb512fb2578f416cbcf28cd3b4387d7b6107a17d4ff31a09e8def26ad9cf07bfbba2cf4a3fad0fe4075030b9a67acbecbfa5b7bdc8620cca07174a59e7f5b71a1a20f8c4a232100c1303378a7eb5dd523904d5305e20ee7dca0199ae8cd6d2b09717d59b5106ef31b451b30d777296b4afb43db9327117471eca09193465aefe93e209d05f892f77002dd5c2e74d4eed502ebae3acb7db1e33acc80";
accountProof[1] =
hex"f8f1a0b4df476cf7a24306eb6b96d0a8fe974b88e035d93e6716cf56e3f6bacee15c88808080a09265834cbd374b79cc4f97cdab16770f4434bce18ff9724970bff1c91d54f2f1a0e13b8847e8cfc7fd465a61a64b732d940d8f87ed65828e1004e46fb4256aba48a05a7b35dc9c135fc4df95c4b02179719a3505d201fb590212cf41c31eae1ceb6980a07c46a7878ac08b149792973e8a17982311f3c997624aed0fde76ba45d9a1ba41a0ebfe5b284e549d79c976f878d93266d238d9ea3254d0ef9c199d2c5a12067de48080a05d5e60bc5b531718ba65199b06b68087c640472ef4b3afb7e4b857280edbf2e580808080";
accountProof[2] =
hex"f869a02024e130452851ed161bc592f5949e62d0e9b45d447bdfeef098148a98e92454b846f8440180a09a86a68eec0b73092dc0028cb4afb05332e85df8af2c9b0f67bbb750a4ada35da0dc679fd48cf611aa38e906adc93928c5f8f6fae534978ea2fa4f5935f5ed1b2c";

bytes[] memory storageProof = new bytes[](5);
storageProof[0] =
hex"f90211a062880ba06fb396ad4e16f01d22ca7a1ae677e3fe428817928db30e2cae96b97ca0aa57a805600be2304ffdd527bd3dc9e91161233dc59afb71c1aab542eafe70caa03bc6c86a4c6b49305b95b3812a162f7e6bec891b287ef291e9c468071ef0c4ada08ac85ec9872d9e6f5b4c6e72154158df88d44163457cf0bbf2134e385c871a4ea0f35f3c83fbd9da738bbfea1bc87b073d3b64abdecb6294b61cf3eb535eabefdea0905c9b0e1755d389f306f026ccb71f8f7e54cd68720cc1c76682504eeb7bceaea06867477d77649657f698380e66844a7ed14818e8aad9f4ac5748963ede640e0aa0caa272deb3227cb8b0765a718ac85bbc7ee93a04bc0a2cb9c5509c9394470eb3a01689508cc26d870b0183c13bee39ed5342bf32464813f872d7ea4e5bc5f79845a0b578886ee673adcdf7b219cd13d9d641f8e15dd9ec6c9345435e7968bc6bcc82a0fbd86d32d6c60089268373be401211c3b606efeb550659b9e43458007dce2eb6a035d73d30ad77c85ef247ab8473f71314a9d175c1e9a0ce73a78a103a3766f54ca0c08386bed5af43c7cadb42d9df7ba3b94886f483e8a2e66aaef7391a15ab51cba002ce1e689b6193a6d3a8c822b0b0076dfdf732fd045a4dc122ec3879fe3de70ea0db27c27a802c40acbde50e5c357e5327a91242e6550fe461eec10ac136ddddcea0ad6d871b4c62042c68f0ecfdb986a24ea7d850563bbd3d27f6916bc3ddd170a480";
storageProof[1] =
hex"f90211a05c9b8f83e3c03e07271225e2ebce1cbe9e7db3b14d2724ec6efe9cf8fce6fc06a0dbd4cd41e027eefe208271111ea3e99cb39b4645e7e166d084d62f427a9313ada0cc65078735257beecceb9c74985901fa16e8e9fb228ce6aaa62aedb282a1795fa012f4c2ae88c8f0396048da6a095d0fa2c8b86398651cd37a72d68d88d25ff19ea037cda349771733bba3681eda450fee72f5e3dcbb6b8f2acf4a2bd145d0bfad6da0ef1359be1a9f658e580c968b92029dbf62ce7a56932c10acce28b25bf7206665a037d9790673a2be78a1555bee7d37ab10d1b8d94d1f12bb011b7cc7257bf13004a0dd9b4774c203afaaeb098ab623ce32f1df6f8ff0ac1bbcb78e358b7a242cd19aa0dde51d1f37baae98d02b2e35c81030f17407fc31304ab72cf999bb2c7e8abff3a0f8672c12a366e074d6f42c2c7b0c5cc010bc4ec703c65e3b58c4fbfee18e89c2a057ba424e40bd1c6a8e7d494703f392e834d8ca7696759e2c0216ebd18bcf662fa01eafd299e8a772c056e6919eeb67bf7e1098129855234e942cfc18aaf364d39ea0df6b60bdf553e1511f445fdcf1fb7aadc23bf390eeb11145c9e2742552c2ed6da02e79f5afb8c177c40737cea4aed39fe3c0269f5a8989e02c07a0135594b83bb1a035535dac85afa0e4848c0186cc8687bc7d2de0215b97ea43e65c8e4da0a52517a08ce682327123eb41b4d49ef283ffe11d1da1b9d7163e892b775a63dd31072ec080";
storageProof[2] =
hex"f90211a0f40a5ee1ce9d240682f7f7af3c5950bba267b4b78e46c954d2b0f8d77da43a23a058e05fe5ccced350c75f8d4c495cd3db51c2d6215573df35178e32ddd7458ff9a06ce4c63e3b3d650248fe6b8d4efb02f5e460406a006ce732318cd5907a54625ba0b0c5eb8747f10eba341df8f0be99a8433654a4621cd0fcbd6ea24f6a5c3d3a82a0e98d81a5b3bc5f25ea24671e6b947bf2aa68c093d7c3bc946b6e71beb9f46df3a00b51ebdd2337cce7ae87e81412c668d305aefcfe25bbb46cc80b48520844adafa0312ebc38d28bbbcf414ed6c48cfb94d26be82bebf06795ca1ed8f088e340210fa066babdf1ddd352c84662fc3ba586a8dc1048bb4d99eea14b62cb389bff71e6fda08e9bde33f5da83fd3fbdc2c1358c67e321fccce1633039c44a689231a38c3a5ca0cc1d1601726ab0b999cf08fe2a87c29e480c97cb501601591c9a9cf0a0ab63dea0a6547a4b3a8647df43e5b81c5224284d4bf19bab142ed58fb28f5a7ff768ee2ca0b804617fff71909c150ae899e64c3cc07c73ea0b92e32a6033ce84a94a78cea9a0a207d46501ca64b8e3514b071d220f38eb545347cb1837f7acbf801d4e3f20fca0083b56370fe68526c7a36714ddb3e98c0ffc8c3d653e254de50e81a6548ddf03a057777667c151137326519774b769a478fa2f1a95df75e70f8972de7a50e25613a061aa71f8b8ea84ea22ed462f83cda58656815a941b458247f14f26b9f7104e1980";
storageProof[3] =
hex"f9013180a0bc1d276fab8bdca46e499a62df0598844a81dd822e5873a57cda01191549b1fca02e7323a53a6103bb95f23070328af116852a340bb8ce85780414f0ee46930f52a0632f43d1fd3bdd8d2e603fca74d2af51c60c1d23fe64cddb02a983779a4bacf1a011d0b3e5a1f1a3dd42b6f6ac95bd34a8044a25a5e99e33cebf730333438047438080a09937213f98b982f56a05cf65bf9113618da12308da8bf5a95c715456d0b91a0ca013844416bff2fdea9d9419e88f58a78728c14bd4e7ba678545ad33224bbea4f080a0de8762bd1bb07b389404f9d925f3bff2f6ea8675b8e89d089cfad9e21f2384b180a0e2be312f35cc32b95912918aa41fbd324a21b7a4acb39fc349b1e4768ca56e9080a052b7d13546e19995f0a3a422a980b8ff101be9494a68562c1e5266933ed25f7b8080";
storageProof[4] =
hex"f8429f20228b7509ed753c777c7f96e7105bab2dc7c2ceacb0ff8611edbd2189f583a1a00a793aea9233fc987a8f710991f16b576e23b67a15874faab4e18192aad8fd17";

LibTrieProof.verifyMerkleProof(
stateRoot,
addr,
slot,
hex"0a793aea9233fc987a8f710991f16b576e23b67a15874faab4e18192aad8fd17",
accountProof,
storageProof
);
}
}
Loading