refactor initialization - #13
Conversation
|
run |
|
There are a lot of public functions that should be external. I will clean that up in a separate PR after these all get merged. |
|
I noticed there aren't any changes to the Chainweb.t.sol file. This is the reason one of the tests if failing. Usually making code changes should means adding or modifying test cases. |
| * script that utilizes this contract. It is safe to call this functions on | ||
| * an uninitialized chain. | ||
| */ | ||
| function switchChain(uint256 chainId) public { |
There was a problem hiding this comment.
I don't think we should mix switchChain with setup chains.
Because we use different ways for seting up chains in test and scripts mode. that was why I have created two setup functions.
Also deployChainWebChainIdContract and deploySha512_256Precompile should happen only for test because the script can run agains normal devnet not only anvil.
I will move fork creation to the setup function instead that I think can fix the nonce issue
There was a problem hiding this comment.
The chainweb chainid contract is deployed only in the tests. The function includes a check that deploys it only if it is not already present. Including this check seems the most robust approach to me.
deploySha512_256Precompile is tricky, because it is a precompile. Even if it is present on the forked chain, it wouldn't be available on the fork itself and still needs to be mocked.
However, as mentioned in the PR description, this PR is still a draft, and I intend to move the SHA512 precompile to a separate PR. So, anything related to the SHA512/256 will be removed from this PR (if we decide to move forward with it at all).
hswopeams
left a comment
There was a problem hiding this comment.
See comments for requested changes.
| address constant SHA512_256_ADDRESS = 0x0000000000000000000000000000000000000420; | ||
|
|
||
|
|
||
| contract Sha512_256Precompile { |
There was a problem hiding this comment.
This contract name is not compliant with solidity standards. It should be Sha512256Precompile;
There was a problem hiding this comment.
Sha512256Precompile is as name obfuscates that 512 and 256 are separate numbers. Would something like Sha512t256Precompile be acceptable?
There was a problem hiding this comment.
Generally, as pointed out in the PR message, the SHA512_256 precompile addition is still in Draft mode and will be moved to a separate PR. The code is not yet final and subject to change.
I will incorporate any comments from this review in the follow up PR.
| assembly { | ||
| let success := 0x00 | ||
| let memPtr := 0x20 | ||
| let ptr := add(memPtr, 0x60) |
There was a problem hiding this comment.
In assembly, you need to be careful with memory management. It's easy to exceed or overwrite memory. You should check the max offset. If it exceeds the current free memory pointer (0x40), you should update it. Something like this after setting ptr:
// Calculate paddedLen: rounds up calldatasize() to the next multiple of 32 bytes (EVM word size).
// This ensures memory operations are word-aligned and safe for copying/returning data.
let paddedLen := shl(5, shr(5, add(calldatasize(), 31)))
// Calculates the highest memory address the assembly code will use for writing or copying data.
let maxOffset := add(ptr, add(0x44, paddedLen))
let freePtr := mload(0x40)
if gt(maxOffset, freePtr) {
mstore(0x40, maxOffset)
}
There was a problem hiding this comment.
yeah, the assembly needs more work. It may actually go away completely, because it does not seem to fix the issues during foundry simulation runs that I had hoped it would resolve. If it turns out that I can't get it to work without --skip-simulation we may as well implement the contract in plain solidity, which works fine in the test and dry-run environments.
| fallback(bytes calldata) external returns (bytes memory) { | ||
| assembly { | ||
| let success := 0x00 | ||
| let memPtr := 0x20 |
There was a problem hiding this comment.
Avoid using magic numbers and use constants for known values as well. See some examples below.
let MEMORY_START := 0x20 // Solidity memory starts at 0x20
let HEADER_SIZE := 0x60 // Size reserved for header, which this appears to be
let DATA_OFFSET := 0x44 // Offset for calldata after header
let memPtr := MEMORY_START
let ptr := add(memPtr, HEADER_SIZE)
| } | ||
|
|
||
| // implicitely abi decode the return value | ||
| return(add(memPtr, 0x40), 0x20) |
There was a problem hiding this comment.
Are you sure the precompile will always return 96 bytes of data? If not, the buffer could contain data from previous calls. The pointer should be initialized before the delegate call on line 43 like this:
mstore(memPtr, 0x00) // Zero out first 32 bytes of output buffer
mstore(add(memPtr, 0x20), 0x00) // Zero out second 32 bytes of output buffer
mstore(add(memPtr, 0x40), 0x00) // Zero out third 32 bytes of output buffer
There was a problem hiding this comment.
That's a good point. But, yes, int this case it always returns the exact same amount of data.
| } | ||
| } | ||
|
|
||
| function sha512_256(bytes memory input) public pure returns (bytes memory result) { |
There was a problem hiding this comment.
This function name is not compliant with solidity naming standards. It should be sha512256. The function name cannot have an underscore in the name.
There was a problem hiding this comment.
Why is this function returning bytes when the library returns bytes32? Hashes are usually bytes32 in solidity.
There was a problem hiding this comment.
Yeah, should be bytes32 now. Originally, this was to simulate the return type of the recompile, but it's not use like this any more.
| } | ||
| } | ||
|
|
||
| function sha384(bytes memory message) internal pure returns (bytes32, bytes16) { |
There was a problem hiding this comment.
Consider some input checks just to make sure people don't cause themselves problems when testing:
require(message.length <= 4096, "Input too large: may exceed block gas limit");
This would allow 4 KB of input. This could be added to sha512 and sha512_256 as well.
| ); | ||
| } | ||
|
|
||
| function padMessage(bytes memory message) internal pure returns (bytes memory) { |
There was a problem hiding this comment.
It would be good to comment on why this particular padding functionality is used. I assume it mimics sha-2.
There was a problem hiding this comment.
yes, this is part of the SHA2 implementation. This code is from the original implementation.
I think, it would be better to not copy-and-past the Sha2Ext code, but use it as a dependency.
| chainIds[i] = i + _chainwebChainIdOffset; | ||
| } | ||
| return chainIds; | ||
| function deploySha512_256Precompile() internal { |
There was a problem hiding this comment.
This function name does not conform to solidity standards. It should be deploySha512256Precompile. The name cannot contain and underscore.
Co-authored-by: Heather <42716568+hswopeams@users.noreply.github.com>
Co-authored-by: Heather <42716568+hswopeams@users.noreply.github.com>
[This PR currently builds on #12 and will be rebased when #12 is merged.]
It seems that calling
selectForkin a constructor of a script or test leads to undefined and inconsistent behavior when switching between chains/forks.This PR builds fixes this by refactoring the code such that initialization of chains is delayed until to the first call of
switchChain.Both usage patterns that are supported in the current version are also supported by this PR:
setUp()of a script or test orChainwebTestorChainwebScript.The code could be simplified considerably if we decided to drop the second approach to initialization and instead always require explicit setup via a
setUp()function.[The PR also includes code for mocking the SHA512/256 precompile that is available in the EVM sandbox and testnet networks. The precompile code needs more work and that is the reason why this PR is still in draft state. I plan to move that change into a separate PR]