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

feat: solidity verifier usage example #16

Merged
merged 6 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "examples/eth/lib/forge-std"]
path = examples/eth/lib/forge-std
url = https://github.com/foundry-rs/forge-std
6 changes: 2 additions & 4 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ async fn generate_tx_proof(tx_hash: &str, rpc_url: &str) -> Result<(), EthTrieEr
let root = txs_mpt_handler.get_root()?;

let mpt_proof = MptProof { root, proof, index };
println!("Generated TX Proof: ");
println!("{}", serde_json::to_string(&mpt_proof).unwrap());
print!("{}", serde_json::to_string(&mpt_proof).unwrap());
Ok(())
}

Expand All @@ -98,7 +97,6 @@ async fn generate_receipt_proof(tx_hash: &str, rpc_url: &str) -> Result<(), EthT
let root = tx_receipts_mpt_handler.get_root()?;

let mpt_proof = MptProof { root, proof, index };
println!("Generated Receipt Proof: ");
println!("{}", serde_json::to_string(&mpt_proof).unwrap());
print!("{}", serde_json::to_string(&mpt_proof).unwrap());
Ok(())
}
14 changes: 14 additions & 0 deletions examples/eth/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Compiler files
cache/
out/

# Ignores development broadcast logs
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/

# Docs
docs/

# Dotenv file
.env
1 change: 1 addition & 0 deletions examples/eth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Ethereum Trie Proof: Solidity example
6 changes: 6 additions & 0 deletions examples/eth/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
1 change: 1 addition & 0 deletions examples/eth/lib/forge-std
Submodule forge-std added at 1714be
20 changes: 20 additions & 0 deletions examples/eth/src/Prover.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {MerkleTrie} from "./lib/MerkleTrie.sol";

contract Prover {
constructor() {}

function get(bytes memory _key, bytes memory _proof, bytes32 _root) public pure returns (bool, bytes memory) {
return MerkleTrie.get(_key, _proof, _root);
}

function verifyInclusionProof(bytes memory _key, bytes memory _value, bytes memory _proof, bytes32 _root)
Copy link
Member

@rkdud007 rkdud007 Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems this function is not used, can we call this function on the example? or can remove it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, removed, it's doing the same thing under the hood

public
pure
returns (bool)
{
return MerkleTrie.verifyInclusionProof(_key, _value, _proof, _root);
}
}
179 changes: 179 additions & 0 deletions examples/eth/src/lib/BytesUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

/**
* @title BytesUtils
*/
library BytesUtils {
/**
*
* Internal Functions *
*
*/
function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
unchecked {
require(_length + 31 >= _length, "slice_overflow");
require(_start + _length >= _start, "slice_overflow");
require(_bytes.length >= _start + _length, "slice_outOfBounds");

bytes memory tempBytes;

assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)

// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(_length, 31)

// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)

for {
// The multiplication in the next line has the same exact purpose
// as the one above.
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)

//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)

//zero out the 32 bytes slice we are about to return
//we need to do it because Solidity does not garbage collect
mstore(tempBytes, 0)

mstore(0x40, add(tempBytes, 0x20))
}
}

return tempBytes;
}
}

function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) {
unchecked {
if (_bytes.length - _start == 0) {
return bytes("");
}

return slice(_bytes, _start, _bytes.length - _start);
}
}

function toBytes32PadLeft(bytes memory _bytes) internal pure returns (bytes32) {
unchecked {
bytes32 ret;
uint256 len = _bytes.length <= 32 ? _bytes.length : 32;
assembly {
ret := shr(mul(sub(32, len), 8), mload(add(_bytes, 32)))
}
return ret;
}
}

function toBytes32(bytes memory _bytes) internal pure returns (bytes32) {
unchecked {
if (_bytes.length < 32) {
bytes32 ret;
assembly {
ret := mload(add(_bytes, 32))
}
return ret;
}

return abi.decode(_bytes, (bytes32)); // will truncate if input length > 32 bytes
}
}

function toUint256(bytes memory _bytes) internal pure returns (uint256) {
return uint256(toBytes32(_bytes));
}

function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) {
require(_start + 3 >= _start, "toUint24_overflow");
require(_bytes.length >= _start + 3, "toUint24_outOfBounds");
uint24 tempUint;

assembly {
tempUint := mload(add(add(_bytes, 0x3), _start))
}

return tempUint;
}

function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
require(_start + 1 >= _start, "toUint8_overflow");
require(_bytes.length >= _start + 1, "toUint8_outOfBounds");
uint8 tempUint;

assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}

return tempUint;
}

function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_start + 20 >= _start, "toAddress_overflow");
require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
address tempAddress;

assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}

return tempAddress;
}

function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
unchecked {
bytes memory nibbles = new bytes(_bytes.length * 2);

for (uint256 i = 0; i < _bytes.length; i++) {
nibbles[i * 2] = _bytes[i] >> 4;
nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16);
}

return nibbles;
}
}

function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
unchecked {
bytes memory ret = new bytes(_bytes.length / 2);

for (uint256 i = 0; i < ret.length; i++) {
ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]);
}

return ret;
}
}

function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) {
return keccak256(_bytes) == keccak256(_other);
}
}
Loading