Skip to content
Merged
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
12 changes: 12 additions & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,17 @@ default: true
MD010:
code_blocks: false
MD013: false
MD025:
front_matter_title: ""
MD024:
siblings_only: true
MD033:
allowed_elements:
- a
- div
- OAIntroduction
- OAOperation
- script
- span
- style
- CelestiaGasEstimator
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# CLAUDE.md

See [AGENTS.md](./AGENTS.md)
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

Ev-node is the basis of the Evolve Stack. For more in-depth information about Evolve, please visit our [website][docs].

<!-- markdownlint-disable MD013 -->
[![Go Report Card](https://goreportcard.com/badge/github.com/evstack/ev-node)](https://goreportcard.com/report/github.com/evstack/ev-node)
[![codecov](https://codecov.io/gh/evstack/ev-node/branch/main/graph/badge.svg?token=CWGA4RLDS9)](https://codecov.io/gh/evstack/ev-node)
[![GoDoc](https://godoc.org/github.com/evstack/ev-node?status.svg)](https://godoc.org/github.com/evstack/ev-node)
<!-- markdownlint-enable MD013 -->

> **⚠️ Version Notice**: Do not use tags or releases before v1.*. Pre-v1 releases are not stable and should be considered abandoned.

Expand Down
18 changes: 9 additions & 9 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,56 +348,56 @@ go get github.com/evstack/ev-node/core@v0.3.0

### GitHub Releases

**"Invalid tag format" error**
#### "Invalid tag format" error

- Ensure tag follows semantic versioning: `v1.2.3`
- Check for typos or incorrect format
- Valid examples: `v1.2.3`, `v1.2.3-rc.4`, `v1.2.3-beta.1`

**"Version not found in CHANGELOG.md"**
#### "Version not found in CHANGELOG.md"

- Verify CHANGELOG.md contains a section for the version
- Check version format matches exactly (e.g., `v1.2.3` vs `1.2.3`)
- Ensure CHANGELOG.md is committed and pushed

**"Claude API error"**
#### "Claude API error"

- Verify `CLAUDE_CODE_OAUTH_TOKEN` secret is configured
- Check repository permissions for GitHub Actions
- Review workflow logs for specific error messages

**Empty or incomplete release notes**
#### Empty or incomplete release notes

- Ensure CHANGELOG.md has detailed entries for the version
- Check that changelog sections (Added, Changed, Fixed, etc.) are properly formatted
- Review the draft release and manually edit if needed

### Docker Releases

**"App directory does not exist"**
#### "App directory does not exist"

- Ensure tag matches app path: `apps/evm/` → `apps/evm/v0.2.0`
- Check spelling and case sensitivity

**"Dockerfile not found"**
#### "Dockerfile not found"

- Verify Dockerfile exists at `apps/{app-path}/Dockerfile`
- Check filename is exactly `Dockerfile`

**"Image not found" in tests**
#### "Image not found" in tests

- Wait for Docker build workflow to complete
- Check workflow dependencies in Actions tab

### Go Module Releases

**Go proxy delay**
#### Go proxy delay

- Wait 5-30 minutes for propagation
- Use `go list -m` to verify availability
- Check <https://proxy.golang.org/>

**Dependency version conflicts**
#### Dependency version conflicts

- Ensure all dependencies are released before dependent modules
- Verify go.mod has correct versions
Expand Down
2 changes: 1 addition & 1 deletion apps/evm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ spamoor \

Transactions submitted to the Force Inclusion API are included in the chain at specific DA heights based on the `da_epoch_forced_inclusion` configuration in `genesis.json`. The API logs will show when the transaction will be force included:

```
```text
INF transaction successfully submitted to DA layer da_height=100
INF transaction will be force included blocks_until_inclusion=8 inclusion_at_height=110
```
2 changes: 1 addition & 1 deletion block/internal/syncing/da_retriever.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func (r *daRetriever) processBlobs(ctx context.Context, blobs [][]byte, daHeight
}
}

var events []common.DAHeightEvent
events := make([]common.DAHeightEvent, 0, len(r.pendingHeaders))

// Match headers with data and create events
for height, header := range r.pendingHeaders {
Expand Down
2 changes: 1 addition & 1 deletion docs/adr/adr-009-state-fraud-proofs.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ message ResponseGenerateFraudProof {
}
```

Note that currently the only underlying store supported by Cosmos SDK is the Merkle IAVL+ tree. As part of generating state witnesses, we added preliminary support for Deep Subtrees to this library [here](https://github.com/rollkit/iavl/tree/deepsubtrees_0.19.x). It enables import and export of partial state and adds tracing to IAVL trees. Note that documentation and exploring optimizations of Deep Subtrees is a work in progress.
Note that currently the only underlying store supported by Cosmos SDK is the Merkle IAVL+ tree. As part of generating state witnesses, we added preliminary support for Deep Subtrees to the [IAVL Deep Subtrees branch](https://github.com/rollkit/iavl/tree/deepsubtrees_0.19.x). It enables import and export of partial state and adds tracing to IAVL trees. Note that documentation and exploring optimizations of Deep Subtrees is a work in progress.

### Gossiping Fraud Proofs

Expand Down
4 changes: 2 additions & 2 deletions docs/adr/adr-012-based-sequencing.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,15 @@ When forced inclusion transactions exceed `MaxBytes`:

**Block 1**:

```
```text
Epoch [100-109] contains 3MB of transactions
Block at DA height 100: 2MB (partial)
Remaining in queue: 1MB
```

**Block 2**:

```
```text
Block at DA height 101: 1MB (remainder) + new regular txs
Queue cleared
```
Expand Down
28 changes: 14 additions & 14 deletions docs/adr/adr-019-forced-inclusion-mechanism.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ We implement a **forced inclusion mechanism** that allows users to submit transa

### High-Level Architecture

```
```text
┌─────────────────────────────────────────────────────────────────┐
│ User Actions │
├─────────────────────────────────────────────────────────────────┤
Expand Down Expand Up @@ -385,7 +385,7 @@ func (s *Syncer) verifyForcedInclusionTxs(currentState State, data *Data) error

**Smoothing Example**:

```
```text
Epoch [100-109] contains 3MB of forced inclusion transactions

Block at DA height 100:
Expand Down Expand Up @@ -551,18 +551,18 @@ graceBoundary := epochEnd + (effectiveGracePeriod * DAEpochForcedInclusion)

Configuration: `DAEpochForcedInclusion = 50`, Base grace period of 1 epoch (dynamically adjusted)

_Example 1: Normal Inclusion (Within Same Epoch)_
#### Example 1: Normal Inclusion (Within Same Epoch)

```
```text
- Forced tx submitted to DA at height 75 (epoch 51-100)
- Sequencer fetches at height 101 (next epoch start)
- Sequencer includes tx in block at DA height 105
- Result: ✅ Valid - included within same epoch
```

_Example 2: Grace Period Usage (Included in Next Epoch)_
#### Example 2: Grace Period Usage (Included in Next Epoch)

```
```text
- Forced tx submitted to DA at height 75 (epoch 51-100)
- Sequencer fetches at height 101
- DA temporarily unavailable, sequencer cannot fetch
Expand All @@ -571,9 +571,9 @@ _Example 2: Grace Period Usage (Included in Next Epoch)_
- Result: ✅ Valid - within grace period
```

_Example 3: Malicious Sequencer (Past Grace Boundary)_
#### Example 3: Malicious Sequencer (Past Grace Boundary)

```
```text
- Forced tx submitted to DA at height 75 (epoch 51-100)
- Sequencer fetches at height 101
- Sequencer deliberately omits tx
Expand All @@ -582,9 +582,9 @@ _Example 3: Malicious Sequencer (Past Grace Boundary)_
- Result: ❌ Block rejected, sequencer flagged as malicious
```

_Example 4: Low Chain Activity (Minimum Grace Period)_
#### Example 4: Low Chain Activity (Minimum Grace Period)

```
```text
- Chain is mostly empty (<20% full)
- Grace period is at minimum (0.5x base period)
- Forced tx submitted at height 75 (epoch 51-100)
Expand All @@ -593,9 +593,9 @@ _Example 4: Low Chain Activity (Minimum Grace Period)_
- Result: Faster censorship detection when block space is available
```

_Example 5: Multiple Pending Transactions_
#### Example 5: Multiple Pending Transactions

```
```text
- Tx A from epoch ending at height 100, grace boundary 150
- Tx B from epoch ending at height 150, grace boundary 200
- Current DA height: 155
Expand All @@ -604,9 +604,9 @@ _Example 5: Multiple Pending Transactions_
- Result: Block rejected due to Tx A
```

_Example 6: High Chain Activity (Extended Grace Period)_
#### Example 6: High Chain Activity (Extended Grace Period)

```
```text
- Chain is highly congested (>80% full)
- Grace period is extended (up to 3x base period)
- Forced tx submitted at height 75 (epoch 51-100)
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/da/visualizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ rpc:

Once enabled, the DA Visualizer is accessible through your node's RPC server. By default, this is:

```
```text
http://localhost:7331/da
```

Expand Down
6 changes: 3 additions & 3 deletions docs/guides/deploy/mainnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ All flows below assume usage of the proxy admin contract.

### Flow 1: Full Setup

**Basefee redirect + feevault + native mint/burn + bridge (Hyperlane)**
#### Basefee redirect + feevault + native mint/burn + bridge (Hyperlane)

#### Genesis Setup

Expand All @@ -187,8 +187,8 @@ Embed the proxy contract with an EOA address as admin. The EOA must have at leas
}
```

4. Pick a max contract size (24kb default, 128kb is a safe upgrade)
5. Pick EIP-1559 config:
1. Pick a max contract size (24kb default, 128kb is a safe upgrade)
2. Pick EIP-1559 config:

```json
{
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/deploy/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: This page provides an overview of some common ways to deploy chains

One of the benefits of building chains with Evolve is the flexibility you have as a developer to choose things like the DA layer, the settlement scheme, and the execution environment.

You can learn more about Evolve architecture [here](../../learn/specs/overview.md).
You can learn more in the [Evolve architecture overview](../../learn/specs/overview.md).

The challenge that comes with this flexibility is that there are more services that now need to be deployed and managed while running your chain.

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/deploy/testnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This tutorial is going to show you how to deploy a Evolve testnet, focusing on the architecture choices and components that make up a complete EVM-based chain deployment.

You can learn more about Evolve EVM architecture [here](../../learn/execution.md).
You can learn more in the [Evolve EVM architecture guide](../../learn/execution.md).

<!-- markdownlint-disable MD033 -->
<script setup>
Expand Down
2 changes: 2 additions & 0 deletions docs/guides/ha/cluster-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ The `grep -m1` exits as soon as the node logs `entering follower state` or `ente
### Cluster does not elect a leader

Check that:

- At least 3 out of 5 nodes are running and can reach each other on port 5001.
- The `peers` list on every node is identical and all addresses are correct.
- No firewall rule is blocking TCP on port 5001.
Expand All @@ -450,6 +451,7 @@ Stop the node, wipe both `raft_dir` and the node's block data directory, then re
Symptoms: frequent `election won` and `entering follower state` lines in the logs, block production pausing briefly every few seconds.

Causes:

- `heartbeat_timeout` is too short for your network RTT — increase it.
- Network congestion or packet loss between nodes.
- Node CPU is saturated and cannot process heartbeats in time.
Expand Down
4 changes: 4 additions & 0 deletions docs/guides/ha/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Raft transport is **plain TCP** with no built-in encryption. Before deploying:
This is the single most important infrastructure decision for cluster stability. All nodes must have roughly the same RTT to each other. The timing parameters (heartbeat timeout, election timeout) are sized for a single `RTT_MAX` value — if one node has materially higher latency than its peers, it degrades the entire cluster's ability to detect failures and elect leaders reliably.

Specifically:

- **Same region, different AZs** gives uniform 5–30ms RTT and is the validated production topology. Nodes are isolated from AZ-level failures while keeping latency uniform.
- **Cross-region nodes** introduce higher and asymmetric RTT (100ms+). Even a single high-latency node can destabilize the cluster under network stress.

Expand Down Expand Up @@ -154,6 +155,7 @@ raft:
A comma-separated list of the **other** cluster members (exclude the local node), in the format `nodeID@host:port`. The host and port must be the Raft address (`raft_addr`) of each peer as reachable from this node. Do not list the node's own `node_id` in its own `peers` field.

Raft uses this list to:

- Bootstrap the cluster on first start (when no persisted state exists).
- Know which addresses to dial when sending log entries or heartbeats.

Expand Down Expand Up @@ -286,6 +288,7 @@ raft:
The number of committed log entries that must accumulate before Raft automatically takes a snapshot of the FSM state. After a snapshot, log entries older than the snapshot are compacted away.

**Effect on operations:**

- **Lower values** (e.g., `500`): snapshots are taken frequently, keeping the log small. A restarting node receives a recent snapshot and has fewer log entries to replay, but snapshot writes happen more often, adding brief I/O bursts.
- **Higher values** (e.g., `5000`): less frequent snapshots mean less I/O overhead during normal operation, but a lagging node may have more log entries to replay when catching up.

Expand All @@ -306,6 +309,7 @@ raft:
The number of log entries to **retain after a snapshot** is taken. These entries act as a catch-up buffer: a node that missed fewer than `trailing_logs` entries since the last snapshot can replay from the log without needing to transfer the full snapshot.

**Effect on operations:**

- **Lower values** (e.g., `200`): tighter disk usage; a node that misses even a few minutes of operation must receive a full snapshot on rejoin.
- **Higher values** (e.g., `18000`): a lagging node can catch up via log replay without needing a full snapshot transfer, reducing the cost of brief outages. At 1 block/second (`block_time: "1s"`), `trailing_logs: 18000` covers ~5 hours; at 10 block/second, ~30 minutes.

Expand Down
1 change: 1 addition & 0 deletions docs/guides/quick-start.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
title: Quick start guide
description: Quickly start a chain node using the Testapp CLI.
---

Expand Down
8 changes: 5 additions & 3 deletions docs/learn/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,10 +412,12 @@ When pruning is enabled, the pruner runs at the configured interval and removes
**Batch Size Examples:**

With default settings (15 minute interval, 1 second blocks):

- Catch-up: ~1,800 blocks per run
- Normal: ~3,600 blocks per run

With high-throughput chain (15 minute interval, 100ms blocks):

- Catch-up: ~18,000 blocks per run
- Normal: ~36,000 blocks per run

Expand Down Expand Up @@ -1356,9 +1358,9 @@ _Constant:_ `FlagRaftPeers`

Raft startup mode is selected automatically from local raft configuration state:

* If the node already has persisted raft configuration in `raft.raft_dir`, it starts in rejoin mode.
* If no raft configuration exists yet, it bootstraps a cluster from configured peers.
* `raft.bootstrap` is retained for compatibility but does not control mode selection.
- If the node already has persisted raft configuration in `raft.raft_dir`, it starts in rejoin mode.
- If no raft configuration exists yet, it bootstraps a cluster from configured peers.
- `raft.bootstrap` is retained for compatibility but does not control mode selection.

`--evnode.raft.rejoin` has been removed.

Expand Down
3 changes: 3 additions & 0 deletions node/failover.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ func setupFailoverState(
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
if err := rpcserver.ConfigureHTTPServer(rpcServer); err != nil {
return nil, fmt.Errorf("error configuring RPC server: %w", err)
}
bc, err := buildComponentsFn(headerSyncService, dataSyncService)
if err != nil {
return nil, fmt.Errorf("build follower components: %w", err)
Expand Down
3 changes: 3 additions & 0 deletions node/light.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ func (ln *LightNode) Run(parentCtx context.Context) error {
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
if err := rpcserver.ConfigureHTTPServer(ln.rpcServer); err != nil {
return fmt.Errorf("error configuring RPC server: %w", err)
}

go func() {
ln.Logger.Info().Str("addr", ln.nodeConfig.RPC.Address).Msg("started RPC server")
Expand Down
2 changes: 1 addition & 1 deletion pkg/p2p/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ func (c *Client) GetPeers() ([]peer.AddrInfo, error) {
return nil, err
}

var peers []peer.AddrInfo
peers := make([]peer.AddrInfo, 0, peerLimit)
for p := range peerCh {
if p.ID == c.host.ID() {
continue
Expand Down
Loading
Loading