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
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ This project uses Protocol Buffers for consensus and node communication (except

- `make buf-lint` - Lint protobuf files to ensure they follow best practices
- `make buf-format` - Format protobuf files (this is included in `make lint`)
- `make buf-breaking` - Check for breaking changes against the master branch
- `make buf-breaking` - Check for breaking changes against the main branch

### Before Committing Changes

If you modify any `.proto` files, always run `make buf-lint` and `make buf-breaking` to ensure your changes don't introduce linting issues or breaking changes. The `buf-breaking` command compares your changes against the master branch to detect any backwards-incompatible modifications. Breaking changes should be carefully reviewed and documented as they can impact existing deployments.
If you modify any `.proto` files, always run `make buf-lint` and `make buf-breaking` to ensure your changes don't introduce linting issues or breaking changes. The `buf-breaking` command compares your changes against the main branch to detect any backwards-incompatible modifications. Breaking changes should be carefully reviewed and documented as they can impact existing deployments.

### CI

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ git config fetch.recurseSubmodules on-demand

### Prerequisites

- [Rust](https://rustup.rs/)
- [Docker](https://docs.docker.com/get-started/get-docker/)
- [Node.js](https://nodejs.org/)
- [Foundry](https://getfoundry.sh/)
- [Hardhat](https://hardhat.org/)
Expand Down Expand Up @@ -178,7 +180,7 @@ For more details, see our [Contributing Guide](CONTRIBUTING.md).
## Resources

- [Arc Network](https://www.arc.network/) - Official Arc Network website
- [Arc Documentation](https://www.arc.network/) - Official Arc developer documentation
- [Arc Documentation](https://docs.arc.network/) - Official Arc developer documentation
- [Reth](https://github.com/paradigmxyz/reth) - The underlying execution layer framework
- [Malachite](https://github.com/circlefin/malachite) - BFT consensus engine
- [Local Documentation](docs/) - Implementation guides and references
Expand Down
61 changes: 58 additions & 3 deletions crates/evm/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,9 @@ where
let beneficiary = ctx.block().beneficiary();
let basefee = ctx.block().basefee() as u128;
let effective_gas_price = ctx.tx().effective_gas_price(basefee);
let gas_used = exec_result.gas().used() as u128;
let gas_used = exec_result.gas().used();

// Calculate total fee (base fee + priority fee) instead of just priority fee
let total_fee_amount = U256::from(effective_gas_price * gas_used);
let total_fee_amount = U256::from(effective_gas_price) * U256::from(gas_used);

// Transfer the total fee to the beneficiary (both base fee and priority fee)
evm.ctx_mut()
Expand Down Expand Up @@ -505,6 +504,62 @@ mod tests {
);
}

#[test]
fn test_reward_beneficiary_large_values_no_overflow() {
let beneficiary = address!("1100000000000000000000000000000000000011");
let caller = address!("2200000000000000000000000000000000000022");
// Values that would overflow u128 when multiplied: (u128::MAX / 1000) * 2000 > u128::MAX
let gas_price = u128::MAX / 1000;
let gas_used = 2000u64;

let db: CacheDB<EmptyDBTyped<Infallible>> = CacheDB::new(EmptyDB::default());
let mut evm = Context::mainnet().with_db(db).build_mainnet();

evm.block.beneficiary = beneficiary;
evm.block.basefee = 0;
evm.tx.caller = caller;
evm.tx.gas_price = gas_price;

let interpreter_result = InterpreterResult::new(
InstructionResult::Return,
alloy_primitives::Bytes::new(),
Gas::new_spent(gas_used),
);
let call_outcome = CallOutcome::new(interpreter_result, 0..0);
let mut exec_result = FrameResult::Call(call_outcome);

let initial_balance = evm
.journaled_state
.load_account(beneficiary)
.unwrap()
.info
.balance;

let handler: ArcEvmHandler<_, EVMError<Infallible>> =
ArcEvmHandler::new(ArcHardforkFlags::default());
let result = handler.reward_beneficiary(&mut evm, &mut exec_result);

assert!(
result.is_ok(),
"reward_beneficiary should succeed with large values"
);

let expected_fee = U256::from(gas_price) * U256::from(gas_used);

let final_balance = evm
.journaled_state
.load_account(beneficiary)
.unwrap()
.info
.balance;
let balance_increase = final_balance - initial_balance;

assert_eq!(
balance_increase, expected_fee,
"Beneficiary should receive correct fee even with large values that would overflow u128"
);
}

#[derive(Debug)]
struct BlocklistTestCase {
name: &'static str,
Expand Down
64 changes: 60 additions & 4 deletions crates/precompiles/src/native_coin_authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ stateful!(run_native_coin_authority, precompile_input, hardfork_flags; {
&mut gas_counter,
)?;

// Reject minting to zero address (Zero5+)
if hardfork_flags.is_active(ArcHardfork::Zero5) && args.to == Address::ZERO {
return Err(PrecompileErrorOrRevert::new_reverted(gas_counter, ERR_ZERO_ADDRESS));
}

// Check blocklist
if is_blocklisted(&mut precompile_input.internals, args.to, &mut gas_counter, hardfork_flags)? {
return Err(PrecompileErrorOrRevert::new_reverted(gas_counter, ERR_BLOCKED_ADDRESS));
Expand Down Expand Up @@ -351,6 +356,11 @@ stateful!(run_native_coin_authority, precompile_input, hardfork_flags; {
&mut gas_counter,
)?;

// Reject burning from zero address (Zero5+)
if hardfork_flags.is_active(ArcHardfork::Zero5) && args.from == Address::ZERO {
return Err(PrecompileErrorOrRevert::new_reverted(gas_counter, ERR_ZERO_ADDRESS));
}

// Check blocklist
if is_blocklisted(&mut precompile_input.internals, args.from, &mut gas_counter, hardfork_flags)? {
return Err(PrecompileErrorOrRevert::new_reverted(gas_counter, ERR_BLOCKED_ADDRESS));
Expand Down Expand Up @@ -1034,6 +1044,29 @@ mod tests {
bytecode_address: NATIVE_COIN_AUTHORITY_ADDRESS,
..Default::default()
},
// No auth SLOAD, zero-address check precedes blocklist SLOADs
NativeCoinAuthorityTest {
name: "mint() to zero address reverts (Zero5+)",
caller: ALLOWED_CALLER_ADDRESS,
calldata: INativeCoinAuthority::mintCall {
to: Address::ZERO,
amount: U256::from(1),
}
.abi_encode()
.into(),
gas_limit: MINT_GAS_COST,
pre_zero5_gas_limit: None,
expected_revert_str: Some(ERR_ZERO_ADDRESS),
expected_result: InstructionResult::Revert,
return_data: None,
blocklisted_addresses: None,
gas_used: 0,
pre_zero5_gas_used: None,
target_address: NATIVE_COIN_AUTHORITY_ADDRESS,
bytecode_address: NATIVE_COIN_AUTHORITY_ADDRESS,
eip7708_only: true,
..Default::default()
},
// No auth SLOAD, reverts immediately
NativeCoinAuthorityTest {
name: "burn() with unauthorized caller reverts",
Expand Down Expand Up @@ -1210,6 +1243,29 @@ mod tests {
bytecode_address: NATIVE_COIN_AUTHORITY_ADDRESS,
..Default::default()
},
// No auth SLOAD, zero-address check precedes blocklist SLOADs
NativeCoinAuthorityTest {
name: "burn() from zero address reverts (Zero5+)",
caller: ALLOWED_CALLER_ADDRESS,
calldata: INativeCoinAuthority::burnCall {
from: Address::ZERO,
amount: U256::from(1),
}
.abi_encode()
.into(),
gas_limit: BURN_GAS_COST,
pre_zero5_gas_limit: None,
expected_revert_str: Some(ERR_ZERO_ADDRESS),
expected_result: InstructionResult::Revert,
return_data: None,
blocklisted_addresses: None,
gas_used: 0,
pre_zero5_gas_used: None,
target_address: NATIVE_COIN_AUTHORITY_ADDRESS,
bytecode_address: NATIVE_COIN_AUTHORITY_ADDRESS,
eip7708_only: true,
..Default::default()
},
// No auth SLOAD, reverts immediately
NativeCoinAuthorityTest {
name: "transfer() with unauthorized caller reverts",
Expand Down Expand Up @@ -1342,7 +1398,7 @@ mod tests {
bytecode_address: ADDRESS_B,
..Default::default()
},
// Zero address checks (Zero5+) happen before blocklist SLOADs, so gas_used = 0
// No auth SLOAD, zero-address check precedes blocklist SLOADs
NativeCoinAuthorityTest {
name: "transfer() to zero address reverts (Zero5+)",
caller: ALLOWED_CALLER_ADDRESS,
Expand All @@ -1360,7 +1416,7 @@ mod tests {
return_data: None,
blocklisted_addresses: None,
gas_used: 0,
pre_zero5_gas_used: Some(PRECOMPILE_SLOAD_GAS_COST),
pre_zero5_gas_used: None,
target_address: NATIVE_COIN_AUTHORITY_ADDRESS,
bytecode_address: NATIVE_COIN_AUTHORITY_ADDRESS,
eip7708_only: true,
Expand All @@ -1383,7 +1439,7 @@ mod tests {
return_data: None,
blocklisted_addresses: None,
gas_used: 0,
pre_zero5_gas_used: Some(PRECOMPILE_SLOAD_GAS_COST),
pre_zero5_gas_used: None,
target_address: NATIVE_COIN_AUTHORITY_ADDRESS,
bytecode_address: NATIVE_COIN_AUTHORITY_ADDRESS,
eip7708_only: true,
Expand All @@ -1406,7 +1462,7 @@ mod tests {
return_data: None,
blocklisted_addresses: None,
gas_used: 0,
pre_zero5_gas_used: Some(PRECOMPILE_SLOAD_GAS_COST),
pre_zero5_gas_used: None,
target_address: NATIVE_COIN_AUTHORITY_ADDRESS,
bytecode_address: NATIVE_COIN_AUTHORITY_ADDRESS,
eip7708_only: true,
Expand Down
28 changes: 28 additions & 0 deletions crates/quake/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,34 @@ The workflow runs **10 parallel jobs** (matrix indices 0–9). Each job computes

PRs labeled `test-random` will also trigger this workflow.

### The `clean` command

By default, `clean` removes all node data and configuration. The following flags control what is removed:

| Flag | Short | Description |
|------|-------|-------------|
| `--all` | `-a` | Remove everything, including monitoring services and their data. Cannot be combined with other flags. |
| `--monitoring` | `-m` | Stop monitoring services and remove their data only. |
| `--data` | `-d` | Remove only execution and consensus layer data, preserving configuration. Cannot be combined with `--execution-data` or `--consensus-data`. |
| `--execution-data` | `-x` | Remove only execution layer (Reth) data. Cannot be combined with `--data` or `--consensus-data`. |
| `--consensus-data` | `-c` | Remove only consensus layer (Malachite) data. Cannot be combined with `--data` or `--execution-data`. |

```bash
# Remove node data only (keep config, monitoring intact)
./quake clean --data

# Remove only execution layer data
./quake clean --execution-data

# Remove only consensus layer data
./quake clean --consensus-data

# Remove node data and monitoring
./quake clean --data --monitoring

# Remove everything including monitoring
./quake clean --all
```

## Manifest File Format

Expand Down
Loading
Loading