Conversation
This comment was marked as resolved.
This comment was marked as resolved.
damiannolan
left a comment
There was a problem hiding this comment.
I will have to review and look into this in much more depth but from what I understand applying changes to the state here outside of the EVM and recomputing the root would be a problem for us in our zk prover, as we depend on RSP which applies transactions using a block builder and computes new roots based on that.
So to me, that would suggest that this implementation would fall outside the scope of that and lead to a divergence of state roots
I share this concern. Manually mutating the state root rather than taking the resulting state root from the execution of the EVM transactions could make it impossible to replay the transactions in ZK, unless all of the operations can be re-applied and the same state root can be derived. Also I wonder about the implications this has for Edit: Or is the original state root still exposed and used for |
|
still looking into how to change this without manipulating state outside the evm level |
liamsi
left a comment
There was a problem hiding this comment.
Just some nitpicks / typos while reading through the code
damiannolan
left a comment
There was a problem hiding this comment.
I did not review the ev-revm code in detail. I don't have intimate knowledge of evm internals but given the ADR and my higher level understanding this all computes and makes sense to me.
I think this approach leveraging reward_beneficiary() is much better than the previous, first drafted design and integrates better overall with the prover arch we have been working with.
We will have to allocate time to dedicate to testing this once its merged and ev-reth is happy with it.
Is it possible to get a git tag cut with the ev-reth code before this PR is merged? If its just an alpha or beta tag that's totally fine.
crates/node/src/builder.rs
Outdated
| /// EVM configuration (potentially wrapped with base fee redirect) | ||
| pub evm_config: WrappedEthEvmConfig, |
There was a problem hiding this comment.
Would it make more sense to call this type alias EvolveEvmConfig ?
| /// EVM configuration (potentially wrapped with base fee redirect) | |
| pub evm_config: WrappedEthEvmConfig, | |
| /// EVM configuration (with optional base fee redirect) | |
| pub evm_config: EvolveEvmConfig, |
etc/ev-reth-genesis.json
Outdated
| "terminalTotalDifficulty": 0, | ||
| "terminalTotalDifficultyPassed": true | ||
| "terminalTotalDifficultyPassed": true, | ||
| "ev_reth": { |
There was a problem hiding this comment.
nit, all configuration fields are camelCase in these genesis files and this is snake_case.
Maybe we could consider something else, e.g. just evolve
There was a problem hiding this comment.
This ADR is helpful, thank you! 🙏🏻
So this just deals strictly with the base fee, correct? The "tip" still goes to a potentially different or potentially the same coinbase/beneficiary still?
total_fee = gas_price * gas_used
base_fee = block.baseFeePerGas * gas_used
tip = total_fee - base_fee
base fee -> burn || reward_beneficiary(baseFeeSink)
tip -> coinbase/beneficiary
crates/node/src/builder.rs
Outdated
| use tracing::debug; | ||
| use tracing::{debug, info}; | ||
|
|
||
| type WrappedEthEvmConfig = EthEvmConfig<ChainSpec, EvEvmFactory<EthEvmFactory>>; |
There was a problem hiding this comment.
I believe this is what we need in order to operate succinct/rsp. As this should implement the following trait: https://github.com/paradigmxyz/reth/blob/main/crates/evm/evm/src/lib.rs#L184
From what I've looked at this is what matters - as this has the full set of API calls wired with the essential overrides. It would require a definition similar to this but with the EvEvmFactory wired in: https://github.com/succinctlabs/rsp/blob/main/crates/executor/client/src/executor.rs#L151-L161
We will have to test from our side but this seems to be the integration point I was looking for.
| let gas = exec_result.gas(); | ||
| let spent = gas.spent_sub_refunded(); | ||
|
|
||
| if let (Some(redirect), true) = (self.redirect, spent != 0) { |
There was a problem hiding this comment.
Should we log sth if redirect is None or spent is 0? Or is the expectation that there will always be gas spent or a redirect in place? either way, I think it would be good to improve the introspecatibility here.
|
|
||
| /// Validates the configuration | ||
| pub const fn validate(&self) -> Result<(), ConfigError> { | ||
| Ok(()) |
There was a problem hiding this comment.
Are we sure the extra added sink can't be invalid in some way (like an invalid address)? Shouldn't this be checked here?
There was a problem hiding this comment.
Thinking about this further: if setting the addr to 0xffffffffffffffffffffffffffffffffffffffff or other special addresses this might defeat the purpose. I think we should do further validation on the sink addr.
There was a problem hiding this comment.
why would it defeat the purpose? setting it to a predefined special address should be fine
liamsi
left a comment
There was a problem hiding this comment.
There is a few issues with factory.rs when trying to get this PR to compile and run tests locally. I think this should be fixed before approving this PR. I left a few other rather non-blocking comments. The design makes sense to me. The code base is new to me though and I can't really say much about prover compatibility but if @damiannolan says this works for the prover part, that's good.
|
Once this branch is compiling and we can run an ev-reth instance with it using the base fee redirect then I'm happy to allocate time to testing it with the prover based on what I mentioned in #48 (comment) |
liamsi
left a comment
There was a problem hiding this comment.
I think a few more tests and this can be merged.
| self.inner.reimburse_caller(evm, exec_result) | ||
| } | ||
|
|
||
| fn reward_beneficiary( |
There was a problem hiding this comment.
Ideally, we would add a test that this method behaves as expected in the happy and unhappy paths or rather that the integration works correctly. I see the tests in for redirect.apply in base_fee.rs but would it be possible to test the redirect itself without too much hassle? (Like some minimal Context::mainnet() with EmptyDB or sth?) Please ignore if this is too complex. As mentioned I'm not too familiar with the code base.
| ## Test Cases | ||
|
|
||
| * Unit tests cover the redirect logic inside `BaseFeeRedirect` and verify the handler credits both the sink and block beneficiary as expected (`crates/ev-revm/src/base_fee.rs`, `crates/ev-revm/src/factory.rs`). | ||
| * Integration smoke tests should execute payload-building runs with and without the `config.ev_reth.baseFeeSink` field present to confirm state roots differ only when the redirect is active. |
There was a problem hiding this comment.
If I understand the tests in common.rs correctly, the config and the resulting fixture there does not use base_fee_sink. I think it would be good to add this param there too.
|
|
||
| We introduced a new `ev-revm` crate that mirrors Optimism’s `op-revm` layout but adds an `EvEvm` wrapper. The wrapper: | ||
|
|
||
| * Stores the optional `BaseFeeRedirect` policy and a flag indicating whether inspection is active. |
There was a problem hiding this comment.
Question regarding this flag:
ev-reth/crates/ev-revm/src/evm.rs
Lines 305 to 309 in 52ddc52
The redirection of fees works in both cases, right?
| } | ||
|
|
||
| let amount = U256::from(base_fee) * U256::from(gas_used); | ||
| if amount.is_zero() { |
There was a problem hiding this comment.
Can this even be zero after the check above?
if gas_used == 0 || base_fee == 0 {
return Ok(U256::ZERO);
}| i, gas_used | ||
| ); | ||
| } | ||
| Err(err) => { |
There was a problem hiding this comment.
I'm not sure if this is a dumb question but do we need to make sure that the sink is also credited here? I would assume this is not necessary as this code existed before and did not require a particular burn for fees instead.
| .load_account(self.fee_sink) | ||
| .map_err(BaseFeeRedirectError::Database)?; | ||
| journal | ||
| .balance_incr(self.fee_sink, amount) |
There was a problem hiding this comment.
Question: What is the expected behaviour if the sender is equal to the sink? (Just trying to think of any edge cases).
There was a problem hiding this comment.
it would be a free transaction as the fee would just be moved from the users wallet back to the users wallet
|
|
||
| /// Validates the configuration | ||
| pub const fn validate(&self) -> Result<(), ConfigError> { | ||
| Ok(()) |
There was a problem hiding this comment.
Thinking about this further: if setting the addr to 0xffffffffffffffffffffffffffffffffffffffff or other special addresses this might defeat the purpose. I think we should do further validation on the sink addr.
|
marking it for r4r tested locally, ill address the issues and try to identify possible issues |
c19b45e to
6fb0eef
Compare
Description
Type of Change
Related Issues
Fixes #(issue)
Checklist
Testing
Additional Notes