Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion bin/ev-dev/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ use std::{io::Write, path::PathBuf};
use tracing::info;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

use ev_node::{EvolveArgs, EvolveChainSpecParser, EvolveNode};
use ev_node::{
EvolveArgs, EvolveChainSpecParser, EvolveNode, EvolvePayloadBuilderConfig,
EvolveProposerApiImpl, EvolveProposerApiServer,
};

#[global_allocator]
static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::new_allocator();
Expand Down Expand Up @@ -299,7 +302,16 @@ fn run_without_tui(dev_args: EvDevArgs, deploy_cfg: Option<DeployConfig>) {
let evolve_cfg = EvolveConfig::default();
let evolve_txpool =
EvolveTxpoolApiImpl::new(ctx.pool().clone(), evolve_cfg.max_txpool_bytes);
let proposer_cfg =
EvolvePayloadBuilderConfig::from_chain_spec(ctx.config().chain.as_ref())?;
let initial_next_proposer = proposer_cfg
.proposer_control_precompile_settings()
.map(|(_, _, initial_next_proposer)| initial_next_proposer)
.unwrap_or_default();
let proposer_api =
EvolveProposerApiImpl::new(ctx.provider().clone(), initial_next_proposer);
ctx.modules.merge_configured(evolve_txpool.into_rpc())?;
ctx.modules.merge_configured(proposer_api.into_rpc())?;
Ok(())
Comment on lines +305 to 315

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Proposer RPC is not registered in TUI mode.

You register proposer RPC in the non-TUI startup path, but Line 380-385 (run_with_tui) still only merges txpool. This makes evolve_getNextProposer unavailable whenever --tui is used.

Suggested fix
@@
         let _handle = builder
             .node(EvolveNode::new())
             .extend_rpc_modules(move |ctx| {
                 let evolve_cfg = EvolveConfig::default();
                 let evolve_txpool =
                     EvolveTxpoolApiImpl::new(ctx.pool().clone(), evolve_cfg.max_txpool_bytes);
+                let proposer_cfg =
+                    EvolvePayloadBuilderConfig::from_chain_spec(ctx.config().chain.as_ref())?;
+                let initial_next_proposer = proposer_cfg
+                    .proposer_control_precompile_settings()
+                    .map(|(_, _, initial_next_proposer)| initial_next_proposer)
+                    .unwrap_or_default();
+                let proposer_api =
+                    EvolveProposerApiImpl::new(ctx.provider().clone(), initial_next_proposer);
                 ctx.modules.merge_configured(evolve_txpool.into_rpc())?;
+                ctx.modules.merge_configured(proposer_api.into_rpc())?;
                 Ok(())
             })
             .launch_with_debug_capabilities()
             .await?;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/ev-dev/src/main.rs` around lines 305 - 315, The TUI startup path fails to
register the proposer RPC, so evolve_getNextProposer is unavailable when
run_with_tui is used; fix by creating and merging the proposer API in the TUI
branch the same way as the non-TUI branch: construct EvolvePayloadBuilderConfig
(or reuse proposer_cfg), derive initial_next_proposer, instantiate
EvolveProposerApiImpl (proposer_api) with ctx.provider() and the initial value,
then call ctx.modules.merge_configured(proposer_api.into_rpc()) alongside
merging evolve_txpool in the run_with_tui code path so the proposer RPC is
registered for TUI mode as well.

})
.launch_with_debug_capabilities()
Expand Down
14 changes: 13 additions & 1 deletion bin/ev-reth/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ use tracing::info;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer};
use url::Url;

use ev_node::{log_startup, EvolveArgs, EvolveChainSpecParser, EvolveNode};
use ev_node::{
log_startup, EvolveArgs, EvolveChainSpecParser, EvolveNode, EvolvePayloadBuilderConfig,
EvolveProposerApiImpl, EvolveProposerApiServer,
};

#[global_allocator]
static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::new_allocator();
Expand Down Expand Up @@ -105,9 +108,18 @@ fn main() {
let evolve_cfg = EvolveConfig::default();
let evolve_txpool =
EvolveTxpoolApiImpl::new(ctx.pool().clone(), evolve_cfg.max_txpool_bytes);
let proposer_cfg =
EvolvePayloadBuilderConfig::from_chain_spec(ctx.config().chain.as_ref())?;
let initial_next_proposer = proposer_cfg
.proposer_control_precompile_settings()
.map(|(_, _, initial_next_proposer)| initial_next_proposer)
.unwrap_or_default();
let proposer_api =
EvolveProposerApiImpl::new(ctx.provider().clone(), initial_next_proposer);

// Merge into all enabled transports (HTTP / WS)
ctx.modules.merge_configured(evolve_txpool.into_rpc())?;
ctx.modules.merge_configured(proposer_api.into_rpc())?;
Ok(())
})
.launch()
Expand Down
62 changes: 61 additions & 1 deletion crates/ev-precompiles/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Custom EVM precompiles for Evolve, providing native token supply management func

## Overview

This crate implements custom precompiled contracts that extend the EVM with Evolve-specific functionality. Currently, it provides a mint/burn precompile that allows controlled manipulation of native token supply.
This crate implements custom precompiled contracts that extend the EVM with Evolve-specific functionality. It provides a mint/burn precompile for controlled native token supply management and a proposer-control precompile for execution-owned ev-node proposer rotation.

## Mint Precompile

Expand Down Expand Up @@ -190,3 +190,63 @@ cast send --rpc-url $RPC_URL --private-key $OPERATOR_KEY \
0x000000000000000000000000000000000000f100 \
"mint(address,uint256)" 0xRECIPIENT 1000000000000000000
```

## Proposer Control Precompile

The proposer control precompile stores the ev-node proposer that should sign the next block. It is
used by the ev-node EVM execution adapter to populate ADR-023's `NextProposerAddress` from execution
state.

### Address

```
0x000000000000000000000000000000000000f101
```
Comment on lines +202 to +204

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the new fenced block.

Line 202 opens a fence without a language (```), which triggers MD040. Use ```text for the address block.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 202-202: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ev-precompiles/README.md` around lines 202 - 204, The fenced code
block containing the address 0x000000000000000000000000000000000000f101 should
include a language tag to satisfy MD040; update the fence opening from ``` to
```text so the block is fenced as text (locate the fenced block containing the
address string and add the language tag).

Source: Linters/SAST tools


### Interface

```solidity
interface IProposerControl {
function nextProposer() external view returns (address);
function setNextProposer(address proposer) external;
function admin() external view returns (address);
}
```

### Configuration

```json
{
"config": {
"evolve": {
"proposerControlAdmin": "0x1234567890123456789012345678901234567890",
"proposerControlActivationHeight": 0,
"initialNextProposer": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
}
}
}
```

For existing chains, set `proposerControlActivationHeight` to a future block and upgrade all nodes
before that height. `initialNextProposer` should be the currently active proposer so reads are stable
before the first rotation transaction.

### Operations

The configured admin rotates the next proposer with:

```bash
cast send --rpc-url $RPC_URL --private-key $ADMIN_KEY \
0x000000000000000000000000000000000000f101 \
"setNextProposer(address)" 0xNEXT_PROPOSER
```

The stored proposer can be read through either the precompile ABI or ev-reth's convenience RPC:

```bash
cast call --rpc-url $RPC_URL \
0x000000000000000000000000000000000000f101 \
"nextProposer()(address)"

cast rpc --rpc-url $RPC_URL evolve_getNextProposer latest
```
Comment on lines +208 to +252

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Update proposer ABI/docs to bytes32 to match the implemented precompile.

Lines 210-212, 241-242, and 249 currently document address, but crates/ev-precompiles/src/proposer.rs implements nextProposer()/setNextProposer as bytes32. Following the current README will produce incorrect calldata/signatures and failed calls.

Suggested doc diff
 interface IProposerControl {
-    function nextProposer() external view returns (address);
-    function setNextProposer(address proposer) external;
+    function nextProposer() external view returns (bytes32);
+    function setNextProposer(bytes32 proposer) external;
     function admin() external view returns (address);
 }

-cast send ... "setNextProposer(address)" 0xNEXT_PROPOSER
+cast send ... "setNextProposer(bytes32)" 0x<64-hex-bytes>

-cast call ... "nextProposer()(address)"
+cast call ... "nextProposer()(bytes32)"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```solidity
interface IProposerControl {
function nextProposer() external view returns (address);
function setNextProposer(address proposer) external;
function admin() external view returns (address);
}
```
### Configuration
```json
{
"config": {
"evolve": {
"proposerControlAdmin": "0x1234567890123456789012345678901234567890",
"proposerControlActivationHeight": 0,
"initialNextProposer": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
}
}
}
```
For existing chains, set `proposerControlActivationHeight` to a future block and upgrade all nodes
before that height. `initialNextProposer` should be the currently active proposer so reads are stable
before the first rotation transaction.
### Operations
The configured admin rotates the next proposer with:
```bash
cast send --rpc-url $RPC_URL --private-key $ADMIN_KEY \
0x000000000000000000000000000000000000f101 \
"setNextProposer(address)" 0xNEXT_PROPOSER
```
The stored proposer can be read through either the precompile ABI or ev-reth's convenience RPC:
```bash
cast call --rpc-url $RPC_URL \
0x000000000000000000000000000000000000f101 \
"nextProposer()(address)"
cast rpc --rpc-url $RPC_URL evolve_getNextProposer latest
```
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ev-precompiles/README.md` around lines 208 - 252, The README docs and
example ABI need to use bytes32 for proposer values to match the precompile:
update the IProposerControl interface declaration (replace address with bytes32
for nextProposer() and setNextProposer(bytes32)), change the JSON config keys
(proposerControlAdmin stays address but initialNextProposer must be a bytes32
value), and update all example CLI commands and cast calls to pass/expect a
bytes32 (and the corresponding calldata/signature) instead of an address; verify
references to nextProposer and setNextProposer in the prose reflect bytes32
semantics to avoid mismatched calldata with
crates/ev-precompiles/src/proposer.rs.

1 change: 1 addition & 0 deletions crates/ev-precompiles/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod mint;
pub mod proposer;
Loading