-
Notifications
You must be signed in to change notification settings - Fork 628
Implement zkVM compatibility #10048
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
base: master
Are you sure you want to change the base?
Implement zkVM compatibility #10048
Conversation
src/Nethermind/Nethermind.Consensus/Stateless/WitnessCollector.cs
Outdated
Show resolved
Hide resolved
src/Nethermind/Nethermind.Consensus/Stateless/WitnessGeneratingBlockHashProvider.cs
Outdated
Show resolved
Hide resolved
src/Nethermind/Nethermind.Consensus/Stateless/WitnessGeneratingBlockProcessingEnv.cs
Outdated
Show resolved
Hide resolved
src/Nethermind/Nethermind.Consensus/Stateless/WitnessGeneratingBlockProcessingEnvFactory.cs
Outdated
Show resolved
Hide resolved
src/Nethermind/Nethermind.Consensus/Stateless/WitnessGeneratingWorldState.cs
Outdated
Show resolved
Hide resolved
| static int Main(string[] args) | ||
| { | ||
| Witness witness = new Witness() | ||
| { | ||
| Codes = ToByteArrays(codes), | ||
| Headers = ToByteArrays(headers), | ||
| Keys = ToByteArrays(keys), | ||
| State = ToByteArrays(state) | ||
| }; | ||
|
|
||
| BlockHeader suggestedBlockHeader = new BlockHeader( | ||
| suggestedBlockForRpc.ParentHash, | ||
| suggestedBlockForRpc.Sha3Uncles, | ||
| suggestedBlockForRpc.Miner, | ||
| suggestedBlockForRpc.Difficulty, | ||
| suggestedBlockForRpc.Number!.Value, | ||
| suggestedBlockForRpc.GasLimit, | ||
| (ulong)suggestedBlockForRpc.Timestamp, | ||
| suggestedBlockForRpc.ExtraData, | ||
| suggestedBlockForRpc.BlobGasUsed, | ||
| suggestedBlockForRpc.ExcessBlobGas, | ||
| suggestedBlockForRpc.ParentBeaconBlockRoot, | ||
| suggestedBlockForRpc.RequestsHash) | ||
| { | ||
| StateRoot = suggestedBlockForRpc.StateRoot, | ||
| TxRoot = suggestedBlockForRpc.TransactionsRoot, | ||
| ReceiptsRoot = suggestedBlockForRpc.ReceiptsRoot, | ||
| Bloom = suggestedBlockForRpc.LogsBloom, | ||
| GasUsed = suggestedBlockForRpc.GasUsed, | ||
| MixHash = suggestedBlockForRpc.MixHash, | ||
| BaseFeePerGas = suggestedBlockForRpc.BaseFeePerGas!.Value, | ||
| WithdrawalsRoot = suggestedBlockForRpc.WithdrawalsRoot, | ||
| ParentBeaconBlockRoot = suggestedBlockForRpc.ParentBeaconBlockRoot, | ||
| RequestsHash = suggestedBlockForRpc.RequestsHash, | ||
| BlobGasUsed = suggestedBlockForRpc.BlobGasUsed, | ||
| ExcessBlobGas = suggestedBlockForRpc.ExcessBlobGas, | ||
| Hash = suggestedBlockForRpc.Hash, | ||
| }; | ||
|
|
||
| // suggestedBlockHeader.Hash = suggestedBlockHeader.CalculateHash(); | ||
|
|
||
| BlockHeader? baseBlock = null; | ||
| foreach (var header in witness.DecodedHeaders) | ||
| { | ||
| if (header.Hash == suggestedBlockHeader.ParentHash) | ||
| { | ||
| baseBlock = header; | ||
| } | ||
| } | ||
|
|
||
| if (baseBlock is null) | ||
| { | ||
| // Invalid witness headers | ||
| return 4; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a hardcoded block? Looks weird.
Can we make it proper?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LukaszRozmej I believe for ease of testing it was hardcoded. We can eventually make blocks passed through zk input arguments.
(NOT through args - current args will break NativeAOT actually).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it should be passed through arguments.
What is the difference - arguments vs args that you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There must be zkVM-specific mechanism to pass inputs/outputs. args[] can't be used because there is no actualy storage for it anywhere. Having args[] in the code will break the NativeAOT bootstrap in runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, we had the version that took in arguments for witness and block through arguments, but we need something different for zkVM (as @maximmenshikov pointed out)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think what we can do here is seperate this part in two tools?
- StatelessExecution
- this takes input through CLI and decodes it
- then call the stateless execution module with these input
- zkVM execution
- the input is hardcodesd( can be changed when we have proper logic to provide input to zkVm)
- then call the same stateless module as before
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, the 2. Will probably be different per zkVM, we already have a hook how to do it for ZISK
| #if ZKVM | ||
| 98316501; // TODO: remove ssl | ||
| #else | ||
| (uint)System.Security.Cryptography.RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be that it is solved by minipal fix, but need to double check
|
pushed a commit, things to still be done:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
| public void RegisterDecoder(ITxDecoder decoder) => RegisterDecoder(decoder.Type, decoder); | ||
|
|
||
| public void RegisterDecoder(TxType type, ITxDecoder decoder) => _decoders[(int)type] = decoder; |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RegisterDecoder method now has two overloads. The original method that takes only an ITxDecoder now delegates to the new method that takes both TxType and ITxDecoder. While this maintains backward compatibility, the implementation extracts the type from the decoder and then passes it back. Consider whether this indirection is necessary or if callers should be updated to use the explicit type parameter.
| private static readonly uint s_instanceRandom = | ||
| #if ZKVM | ||
| 2098026241U; |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fixed value 2098026241U used for zkVM appears to be arbitrary. This should be documented with a comment explaining why this specific value was chosen, or consider using a named constant with a descriptive name.
| private static readonly uint s_instanceRandom = | |
| #if ZKVM | |
| 2098026241U; | |
| #if ZKVM | |
| // Fixed, deterministic seed used in zkVM builds where randomness must be reproducible and/or secure RNG | |
| // may be restricted. The specific value is arbitrary but must remain constant across zkVM runs. | |
| private const uint ZkvmInstanceRandomSeed = 2098026241U; | |
| #endif | |
| private static readonly uint s_instanceRandom = | |
| #if ZKVM | |
| ZkvmInstanceRandomSeed; |
Note
These changes are preliminary. The idea is to start a discussion on how to apply/re-implement the required changes correctly.
Changes
Types of changes
What types of changes does your code introduce?
Testing
Requires testing
If yes, did you write tests?