Skip to content
Draft
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
33 changes: 33 additions & 0 deletions gravity/0001-local-testing-sdk.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
From 0356f774f75855d26a2d151bb3d61c2630b88d83 Mon Sep 17 00:00:00 2001
From: "xingqiang.yuan" <xingqiang.yuan@okg.com>
Date: Thu, 22 Jan 2026 10:15:23 +0800
Subject: [PATCH] local testing sdk

---
bin/gravity_node/src/consensus/mock_consensus/mock.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/bin/gravity_node/src/consensus/mock_consensus/mock.rs b/bin/gravity_node/src/consensus/mock_consensus/mock.rs
index e254d7a..37d94a3 100644
--- a/bin/gravity_node/src/consensus/mock_consensus/mock.rs
+++ b/bin/gravity_node/src/consensus/mock_consensus/mock.rs
@@ -125,7 +125,7 @@ impl MockConsensus {
}
}

- if txns.len() > max_txn_num {
+ if txns.len() >= max_txn_num {
return Self::construct_block(block_number, txns, attr, epoch);
}
}
@@ -241,6 +241,7 @@ impl MockConsensus {
.as_ref()
.unwrap()
.iter()
+ .filter(|tx| !tx.is_discarded) // Only include successfully executed transactions
.map(|tx| TxnId {
sender: ExternalAccountAddress::new(tx.sender),
seq_num: tx.nonce,
--
2.50.1 (Apple Git-155)

199 changes: 199 additions & 0 deletions gravity/0001-local-testing.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
From 09fb76e151165ce3ebc1a2db820d0e9ed5237e9f Mon Sep 17 00:00:00 2001
From: "xingqiang.yuan" <xingqiang.yuan@okg.com>
Date: Thu, 22 Jan 2026 17:29:02 +0800
Subject: [PATCH] local testing

---
.../pipe-exec-layer-ext-v2/execute/src/lib.rs | 54 ++++++++++++-------
.../execute/src/onchain_config/epoch.rs | 6 +--
.../src/onchain_config/metadata_txn.rs | 10 ++--
3 files changed, 42 insertions(+), 28 deletions(-)

diff --git a/crates/pipe-exec-layer-ext-v2/execute/src/lib.rs b/crates/pipe-exec-layer-ext-v2/execute/src/lib.rs
index 747b4192a..17b6a8f36 100644
--- a/crates/pipe-exec-layer-ext-v2/execute/src/lib.rs
+++ b/crates/pipe-exec-layer-ext-v2/execute/src/lib.rs
@@ -361,10 +361,12 @@ impl<Storage: GravityStorage> Core<Storage> {
HashedPostState::from_bundle_state::<KeccakKeyHasher>(&execution_output.state.state);
self.metrics.cache_account_state.record(write_start.elapsed());
let elapsed = start_time.elapsed();
+ let tx_count = block.body.transactions.len();
info!(target: "PipeExecService.process",
block_number=?block_number,
block_id=?block_id,
gas_used=execution_output.gas_used,
+ tx_count=tx_count,
elapsed=?elapsed,
epoch=?epoch,
"block executed"
@@ -558,7 +560,7 @@ impl<Storage: GravityStorage> Core<Storage> {
) -> (Vec<GravityEvent>, Option<(u64, Bytes)>) {
let mut gravity_events = vec![];
let mut epoch_change_result = None;
-
+
for receipt in receipts {
debug!(target: "execute_ordered_block",
number=?block_number,
@@ -577,7 +579,7 @@ impl<Storage: GravityStorage> Core<Storage> {
let validator_bytes = crate::onchain_config::types::convert_validator_set_to_bcs(solidity_validator_set);
epoch_change_result = Some((event.newEpoch.to::<u64>(), validator_bytes));
}
-
+
if let Ok(event) = ObservedJWKsUpdated::decode_log(&log) {
info!(target: "execute_ordered_block",
number=?block_number,
@@ -738,7 +740,7 @@ impl<Storage: GravityStorage> Core<Storage> {
&result.execution_output.receipts,
result.block.number,
);
-
+
// Check if any transaction (including JWK transactions) triggered a new epoch
// TODO(gravity_lightman): We need further more tests to test this branch
if let Some((new_epoch, validators)) = epoch_change_result {
@@ -755,7 +757,7 @@ impl<Storage: GravityStorage> Core<Storage> {
gravity_events.push(GravityEvent::NewEpoch(new_epoch, validators.into()));
result.epoch = new_epoch;
}
-
+
result.gravity_events.extend(gravity_events);
result
}
@@ -858,8 +860,29 @@ impl<Storage: GravityStorage> Core<Storage> {
base_fee_per_gas: u64,
gas_limit: u64,
) -> (Vec<TransactionSigned>, Vec<Address>, Vec<TxInfo>) {
- let invalid_idxs = filter_invalid_txs(db, &txs, &senders, base_fee_per_gas, gas_limit);
- if invalid_idxs.is_empty() {
+ // Find transactions that exceed gas limit (should be excluded from current block but remain in txpool)
+ let mut gas_limit_exceeded_tx_idx = txs.len();
+ let mut tx_gas_limit_sum = 0;
+ for (idx, tx) in txs.iter().enumerate() {
+ let tx_gas_limit = tx.gas_limit();
+ if tx_gas_limit_sum + tx_gas_limit > gas_limit {
+ warn!(target: "filter_invalid_txs",
+ tx_hash=?txs[idx].hash(),
+ sender=?senders[idx],
+ block_gas_limit=?gas_limit,
+ "gas limit exceeded, truncated to {}",
+ idx,
+ );
+ gas_limit_exceeded_tx_idx = idx;
+ break;
+ } else {
+ tx_gas_limit_sum += tx_gas_limit;
+ }
+ }
+
+ // Filter transactions: exclude gas limit exceeded ones from current block
+ // Don't send to discard_txs_tx - these transactions should remain in txpool for the next block
+ if gas_limit_exceeded_tx_idx == txs.len() {
let mut txs_info = Vec::with_capacity(txs.len());
for (tx, sender) in txs.iter().zip(senders.iter()) {
txs_info.push(TxInfo {
@@ -871,30 +894,21 @@ impl<Storage: GravityStorage> Core<Storage> {
}
(txs, senders, txs_info)
} else {
- let _ = self
- .discard_txs_tx
- .send(invalid_idxs.iter().map(|&idx| txs[idx].hash()).copied().collect::<Vec<_>>());
-
- let mut filtered_txs = Vec::with_capacity(txs.len() - invalid_idxs.len());
- let mut filtered_senders = Vec::with_capacity(filtered_txs.capacity());
+ let mut filtered_txs = Vec::with_capacity(gas_limit_exceeded_tx_idx);
+ let mut filtered_senders = Vec::with_capacity(gas_limit_exceeded_tx_idx);
let mut txs_info = Vec::with_capacity(txs.len());
for (i, (tx, sender)) in txs.into_iter().zip(senders.into_iter()).enumerate() {
- if invalid_idxs.contains(&i) {
- txs_info.push(TxInfo {
- tx_hash: *tx.hash(),
- sender,
- nonce: tx.nonce(),
- is_discarded: true,
- });
+ if i >= gas_limit_exceeded_tx_idx {
+ // Gas limit exceeded transactions are excluded from current block but not discarded
continue;
}
-
txs_info.push(TxInfo {
tx_hash: *tx.hash(),
sender,
nonce: tx.nonce(),
is_discarded: false,
});
+
filtered_txs.push(tx);
filtered_senders.push(sender);
}
diff --git a/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/epoch.rs b/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/epoch.rs
index f73d6eaf2..c0dbf0932 100644
--- a/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/epoch.rs
+++ b/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/epoch.rs
@@ -38,13 +38,13 @@ where
EthApi::NetworkTypes: RpcTypes<TransactionRequest = TransactionRequest>,
{
fn fetch(&self, block_number: u64) -> Bytes {
- #[cfg(feature = "pipe_test")]
+ #[cfg(not(feature = "pipe_test"))]
{
// For testing, return epoch 0
- Bytes::from(0u64.to_le_bytes().to_vec())
+ Bytes::from(1u64.to_le_bytes().to_vec())
}

- #[cfg(not(feature = "pipe_test"))]
+ #[cfg(feature = "pipe_test")]
{
let call = EpochManager::getCurrentEpochInfoCall {};
let input: Bytes = call.abi_encode().into();
diff --git a/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/metadata_txn.rs b/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/metadata_txn.rs
index a6ae59ba4..bd6c8dc0e 100644
--- a/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/metadata_txn.rs
+++ b/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/metadata_txn.rs
@@ -156,7 +156,7 @@ fn new_system_call_txn(
chain_id: None,
nonce,
gas_price,
- gas_limit: 30_000_000,
+ gas_limit: 15_000_000,
to: TxKind::Call(contract),
value: U256::ZERO,
input,
@@ -166,10 +166,10 @@ fn new_system_call_txn(
}

/// Execute a metadata contract call (blockPrologue or blockPrologueExt)
-///
+///
/// If `enable_randomness` is true, calls blockPrologueExt.
/// Otherwise, calls the legacy blockPrologue function.
-///
+///
/// Note: blockPrologueExt retrieves randomness from block.difficulty (set before this call),
/// so it doesn't need to be passed as a parameter.
pub fn transact_metadata_contract_call(
@@ -206,7 +206,7 @@ pub fn transact_metadata_contract_call(
);
let tx_env = Recovered::new_unchecked(txn.clone(), SYSTEM_CALLER).into_tx_env();
let result = evm.transact_raw(tx_env).unwrap();
-
+
let function_name = if enable_randomness { "blockPrologueExt" } else { "blockPrologue" };
assert!(
result.result.is_success(),
@@ -214,6 +214,6 @@ pub fn transact_metadata_contract_call(
function_name,
result.result
);
-
+
(MetadataTxnResult { result: result.result, txn }, result.state)
}
--
2.50.1 (Apple Git-155)

35 changes: 35 additions & 0 deletions gravity/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.PHONY: help prepare build start stop logs clean

.DEFAULT_GOAL := help

BINARY_PATH := gravity-sdk/target/release/gravity_node
LOG_FILE := gravity_node.out

help: ## Show help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-12s\033[0m %s\n", $$1, $$2}'

prepare: ## Clone repos and apply patches
@[ -d "gravity-reth" ] || (git clone -b gravity-v0.4.1 https://github.com/Galxe/gravity-reth.git && cd gravity-reth && git apply ../0001-local-testing.patch)
@[ -d "gravity-sdk" ] || git clone -b v0.4.1 https://github.com/Galxe/gravity-sdk.git && cd gravity-sdk && git apply ../0001-local-testing-sdk.patch

build: ## Build gravity_node
@cd gravity-sdk && \
grep -qF '[patch."https://github.com/Galxe/gravity-reth"]' Cargo.toml || \
(echo "" >> Cargo.toml && \
echo '[patch."https://github.com/Galxe/gravity-reth"]' >> Cargo.toml && \
echo 'greth = { path = "../gravity-reth" }' >> Cargo.toml) && \
make gravity_node

start: ## Start gravity_node
@bash scripts/start_mock.sh

stop: ## Stop gravity_node
@lsof -ti :8545 | xargs kill 2>/dev/null || true

logs: ## View logs
@tail -f $(LOG_FILE) 2>/dev/null || echo "Log file not found"

clean: stop ## Clean logs
@rm -f $(LOG_FILE) gravity_node.pid
@sleep 1 && rm -rf gravity_node

122 changes: 122 additions & 0 deletions gravity/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Gravity Node Management

A simple management tool for running Gravity Node in MOCK mode for local testing.

## Prerequisites

- `jq` - JSON processor (required for parsing configuration)
- `make` - Build automation tool
- `git` - Version control
- Rust toolchain (for building gravity_node)

## Quick Start

1. **Prepare environment** (clone repositories and apply patches):
```bash
make prepare
```

2. **Build gravity_node**:
```bash
make build
```

3. **Start gravity_node**:
```bash
make start
```

## Configuration

The node reads configuration from `my_config/reth_config.json`. This file should contain:
- `env_vars`: Environment variables to export
- `reth_args`: Command-line arguments for gravity_node

### Configuration Options

**Environment Variables:**
- `MOCK_CONSENSUS`: Enable mock consensus mode
- `MOCK_SET_ORDERED_INTERVAL_MS`: Block interval in ms (e.g., `200`)
- `MOCK_MAX_BLOCK_SIZE`: Max transactions per block
- **Native transfer (Pay) testing**: Set to `1000`
- **ERC20 token testing**: Set to `10000`

**Performance Optimization (in reth_args):**
- `gravity.disable-grevm`: `true` to disable / `false` to enable parallel EVM
- `gravity.disable-pipe-execution`: `true` to disable / `false` to enable pipeline

Examples:
```json
// Fastest mode (both enabled)
"gravity.disable-grevm": false,
"gravity.disable-pipe-execution": false

// Debug mode (both disabled)
"gravity.disable-grevm": true,
"gravity.disable-pipe-execution": true

// Grevm disabled, Pipeline enabled
"gravity.disable-grevm": true,
"gravity.disable-pipe-execution": false
```

## Available Commands

Run `make help` to see all available commands:

- `make prepare` - Clone repositories and apply patches
- `make build` - Build gravity_node binary
- `make start` - Start gravity_node in background
- `make stop` - Stop running gravity_node
- `make logs` - View real-time logs
- `make clean` - Stop node and clean log files

## Project Structure

```
gravity/
├── Makefile # Main entry point
├── README.md # This file
├── 0001-local-testing.patch # Patch for gravity-reth
├── my_config/ # Configuration files
│ └── reth_config.json # Main configuration
└── scripts/ # Helper scripts
├── prepare.sh # Setup script
├── add_patch.sh # Patch management
├── build_gravity_node.sh # Build script
└── start_mock.sh # Start script
```

## How It Works

1. **prepare**: Clones `gravity-reth` and `gravity-sdk` repositories, applies local testing patches
2. **build**: Adds Cargo.toml patch configuration (if needed) and builds the binary
3. **start**: Parses configuration, exports environment variables, and starts gravity_node in background
4. **stop**: Kills the process running on port 8545
5. **clean**: Stops the node (if running) and removes log files

## Logs

Logs are written to `gravity_node.out` in the gravity directory. View them with:
```bash
make logs
```

Or directly:
```bash
tail -f gravity_node.out
```

## Troubleshooting

- **Port 8545 already in use**: Run `make stop` first, or manually kill the process
- **Build fails**: Ensure Rust toolchain is installed and `make prepare` has been run
- **Config file not found**: Ensure `my_config/reth_config.json` exists
- **jq not found**: Install jq using the commands in Prerequisites section

## Notes

- The node runs in MOCK mode for local testing
- All scripts automatically handle directory navigation
- The build process automatically adds required Cargo.toml patches

Loading