Skip to content

Feat (cheatcodes): Introducing ipfs cid v0 to calculate file content #10348

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

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

Ayushdubey86
Copy link
Contributor

@Ayushdubey86 Ayushdubey86 commented Apr 22, 2025

Hello @jenpaff ,it should close #9862

locally everything seems to be passing
image

can you rerun pipeline, saw in documentation it wont pass through first attempt

@grandizzy
Copy link
Collaborator

grandizzy commented Apr 22, 2025

@Ayushdubey86 you need to run cargo cheats to fix the CI failure. I pushed a commit for this and fmt here 6247228

Copy link
Collaborator

@grandizzy grandizzy left a comment

Choose a reason for hiding this comment

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

@Ayushdubey86 thank you, mind to add a test for this new cheatcode similar with tests within https://github.com/foundry-rs/foundry/tree/master/testdata/default/cheats?

@Ayushdubey86
Copy link
Contributor Author

Ayushdubey86 commented Apr 22, 2025

@Ayushdubey86 thank you, mind to add a test for this new cheatcode similar with tests within https://github.com/foundry-rs/foundry/tree/master/testdata/default/cheats?

I am lacking slight bandwidth, I'll raise pr for tests within a day or 2!:) Hope this is fine

@grandizzy
Copy link
Collaborator

@Ayushdubey86 thank you, mind to add a test for this new cheatcode similar with tests within https://github.com/foundry-rs/foundry/tree/master/testdata/default/cheats?

I am lacking slight bandwidth, I'll raise pr for tests within a day or 2!:) Hope this is fine

@sakulstra do you have a test handy to include for ipfsCidV0(string memory filepath):bytes32 cheatcode? (input file, output bytes) thanks!

@sakulstra
Copy link
Contributor

On out ffi-js tooling test we got this:

const content = `---
title: TestTitle
discussions: TestDiscussion
author: TestAuthor
---`;
    expect(await Hash.of(content)).toBe('QmYMiDJUYXGsUng5rAgwgLvZzLEMjbhaWALFbQJjC6saPv');
const bs58Hex = `0x${Buffer.from(bs58.decode(hash)).slice(2).toString('hex')}`
    expect(bs58Hex).toBe('0x94da694df5cf2e139206cddcdd6f855baa45e519c5fdbc2e6aa1cf803cfd65d5');

So i guess assertEq(ipfsCidV0('pathToFileWithContent'), 0x94da694df5cf2e139206cddcdd6f855baa45e519c5fdbc2e6aa1cf803cfd65d5)?

@grandizzy
Copy link
Collaborator

On out ffi-js tooling test we got this:

const content = `---
title: TestTitle
discussions: TestDiscussion
author: TestAuthor
---`;
    expect(await Hash.of(content)).toBe('QmYMiDJUYXGsUng5rAgwgLvZzLEMjbhaWALFbQJjC6saPv');
const bs58Hex = `0x${Buffer.from(bs58.decode(hash)).slice(2).toString('hex')}`
    expect(bs58Hex).toBe('0x94da694df5cf2e139206cddcdd6f855baa45e519c5fdbc2e6aa1cf803cfd65d5');

So i guess assertEq(ipfsCidV0('pathToFileWithContent'), 0x94da694df5cf2e139206cddcdd6f855baa45e519c5fdbc2e6aa1cf803cfd65d5)?

hey @sakulstra when I try to hash same content with ipfs-only-hash I get different value, I suppose that is because you're hashing with MemoryBlockstore here https://github.com/bgd-labs/aave-cli/blob/main/src/ipfs/onlyHash.ts#L15 ? shouldn't npx ipfs-only-hash --cid-version 0 yield the same cid v0 as in your test?

@sakulstra
Copy link
Contributor

@grandizzy i tried via npx ipfs-only-hash --cid-version 0 test where test is a file containing:

---
title: TestTitle
discussions: TestDiscussion
author: TestAuthor
---

(no new line at eof), and it emits the same hash:

npx ipfs-only-hash --cid-version 0 test
QmYMiDJUYXGsUng5rAgwgLvZzLEMjbhaWALFbQJjC6saPv

@grandizzy
Copy link
Collaborator

grandizzy commented Apr 23, 2025

npx ipfs-only-hash --cid-version 0 test

@sakulstra interesting, I get different (maybe due to OS?)

npx ipfs-only-hash --cid-version 0 test 
Qmbg681gkxVzA4ZQjXMbhiMkDyRTVfy3e5p3SAmL3Q93vB

Mind to attach your test file to give it a try?

@sakulstra
Copy link
Contributor

sakulstra commented Apr 23, 2025

Here it is:
test.txt

Pretty sure is not os related as we use the tooling accross oses.

@grandizzy
Copy link
Collaborator

Here it is: test.txt

Pretty sure is not os related as we use the tooling accross oses.

got it, yeah, get the same hash with your file

@Ayushdubey86
Copy link
Contributor Author

Have pushed test cases, do check it out!:) @grandizzy @sakulstra

@grandizzy
Copy link
Collaborator

@Ayushdubey86 for test you could add the file directly under https://github.com/foundry-rs/foundry/tree/master/testdata/fixtures/File without the need of test to create it

@Ayushdubey86
Copy link
Contributor Author

@Ayushdubey86 for test you could add the file directly under https://github.com/foundry-rs/foundry/tree/master/testdata/fixtures/File without the need of test to create it

have pushed and modified test case!

@grandizzy
Copy link
Collaborator

@Ayushdubey86 for test you could add the file directly under https://github.com/foundry-rs/foundry/tree/master/testdata/fixtures/File without the need of test to create it

have pushed and modified test case!

thanks! The path to file in test should not contain testdata: fixtures/File/test.txt

@@ -2008,6 +2008,10 @@ interface Vm {
#[cheatcode(group = Filesystem)]
function promptUint(string calldata promptText) external returns (uint256);

/// Calculates the IPFS CID V0 of a file's content.
#[cheatcode(group = Filesystem)]
function ipfsCidV0(string calldata filepath) external returns (bytes32 cid);
Copy link
Member

@DaniPopes DaniPopes Apr 23, 2025

Choose a reason for hiding this comment

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

does this have to be a path? It just reads the file then hashes it, we could just accept a bytes directly.

Also, sha256 exists in the EVM itself (precompile 0x00...02), why can this not be a simple utility function written in Solidity where it is needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point — accepting bytes directly would give more flexibility.
It depends on the user though — some might prefer to pass a filepath (especially for testing existing files).

Maybe we can support both?
I'm fine with either approach for now — happy to go with what you think makes the most sense! @sakulstra @grandizzy

Copy link
Contributor

@sakulstra sakulstra Apr 23, 2025

Choose a reason for hiding this comment

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

No, too strong opinion.
If it accepted string or similar, we would build our own wrapped which is perfectly fine either.

For us the main usecase is hashing content in external files which is why i suggested path, but i guess there could be usecases that would require hashing strings from solidity. So perhaps string input is more flexible as we could just use vm.ipfsCidV0 (vm.readFile(path)) and others can skip the file reading and hash content immediately?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@DaniPopes for sha256,

That’s a good point, and normally sha256() in Solidity would be sufficient — but this cheatcode targets a different use case.

We need to compute the SHA-256 hash of an off-chain file in the testing environment, prefix it per the multihash spec (IPFS CIDv0), and then pass that result into the EVM. Since Solidity's sha256() only operates on in-memory bytes at runtime, it can’t handle file reads or multihash formatting.
So this utility is kinda necessary

Copy link
Collaborator

@grandizzy grandizzy Apr 24, 2025

Choose a reason for hiding this comment

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

this looks to be more complex than initial draft, the only way I was able to get same CID v0 as with npx ipfs-only-hash was to use https://crates.io/crates/ipfs-cid crate which chunks it and hash last chunk https://github.com/omarabid/ipfs-cid/blob/e60fae3ee3222916da0c1dfec5eda1a4c26dec5b/src/lib.rs#L8 This uses an archived / unmaintained crate https://github.com/rs-ipfs/rust-ipfs and adds in bunch of other dependencies which would like to avoid. If we cannot get to a clean impl (that doesn't require pulling in so many deps) we should hold off on this for now.

@Ayushdubey86
Copy link
Contributor Author

I'll look into this test case failure post final design discussion!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

feat(cheatcodes): add cheatcode to calculate the IPFS CID V0 of a file content
5 participants