# CON-002: NetworkConstants Type

> **Authoritative requirement:** [CON-002](../NORMATIVE.md#CON-002)
> **Verification:** [VERIFICATION.md](../VERIFICATION.md)
> **Tracking:** [TRACKING.yaml](../TRACKING.yaml)
> **Spec reference:** [SPEC.md](../../../../resources/SPEC.md) — Section 4.3

---

## Summary

`NetworkConstants` is the primary type exported by the `dig-constants` crate. It wraps Chia's `ConsensusConstants` type from `chia-consensus` and provides ergonomic accessor methods for the fields most commonly needed by DIG L2 crates. Rather than exposing the full `ConsensusConstants` struct directly (which contains many Chia-specific fields irrelevant to DIG, such as proof-of-space parameters), `NetworkConstants` presents a curated interface focused on the fields that matter for L2 consensus.

The wrapper provides six primary accessors: `consensus()` returns a reference to the underlying `ConsensusConstants` for passing to `chia-consensus` functions; `genesis_challenge()` returns the network-specific 32-byte identifier; `agg_sig_me_additional_data()` returns the domain separation data for AGG_SIG_ME signatures; `max_block_cost_clvm()` returns the maximum CLVM cost per block; `cost_per_byte()` returns the cost charged per byte of CLVM program; and `max_coin_amount()` returns the maximum amount a single coin can hold.

The `NetworkConstants` type is designed to be used as a `const` value — the two canonical instances `DIG_MAINNET` and `DIG_TESTNET` are compile-time constants. This means `NetworkConstants` must be `Copy` and all its methods must be `const fn` where possible. The type is passed by reference in validation contexts and cloned cheaply due to its `Copy` implementation.

---

## Specification

### Type Definition

```rust
use chia_consensus::consensus_constants::ConsensusConstants;
use chia_protocol::Bytes32;

/// DIG L2 network constants.
/// Wraps ConsensusConstants with ergonomic accessors
/// for the fields relevant to DIG consensus.
#[derive(Debug, Clone, Copy)]
pub struct NetworkConstants {
    inner: ConsensusConstants,
}
```

### Constructor

```rust
impl NetworkConstants {
    /// Create a new NetworkConstants from a ConsensusConstants.
    /// Used internally to construct DIG_MAINNET and DIG_TESTNET.
    pub const fn new(inner: ConsensusConstants) -> Self {
        Self { inner }
    }
}
```

### Accessor Methods

```rust
impl NetworkConstants {
    /// Access the underlying ConsensusConstants for passing
    /// to chia-consensus functions that require it.
    pub const fn consensus(&self) -> &ConsensusConstants {
        &self.inner
    }

    /// The 32-byte network identifier.
    /// Unique per network (mainnet vs testnet).
    /// Used for peer identification and domain separation.
    pub const fn genesis_challenge(&self) -> &Bytes32 {
        &self.inner.genesis_challenge
    }

    /// Domain separation data for AGG_SIG_ME (opcode 49).
    /// Equal to genesis_challenge (see CON-005).
    pub const fn agg_sig_me_additional_data(&self) -> &Bytes32 {
        &self.inner.agg_sig_me_additional_data
    }

    /// Maximum CLVM execution cost per block.
    /// Spend bundles exceeding this cost are rejected.
    pub const fn max_block_cost_clvm(&self) -> u64 {
        self.inner.max_block_cost_clvm
    }

    /// Cost charged per byte of serialized CLVM program.
    /// Applied to puzzle reveals and solutions.
    pub const fn cost_per_byte(&self) -> u64 {
        self.inner.cost_per_byte
    }

    /// Maximum amount (in mojos) a single coin can hold.
    /// Typically u64::MAX or a protocol-defined limit.
    pub const fn max_coin_amount(&self) -> u64 {
        self.inner.max_coin_amount
    }
}
```

### Usage Examples

```rust
use dig_constants::{DIG_MAINNET, NetworkConstants};

// In validation context:
let context = ValidationContext {
    constants: DIG_MAINNET,
    // ...
};

// Accessing fields:
let max_cost = DIG_MAINNET.max_block_cost_clvm();
let genesis = DIG_MAINNET.genesis_challenge();
let agg_sig_data = DIG_MAINNET.agg_sig_me_additional_data();

// Passing to chia-consensus:
let result = chia_consensus::validate_clvm_and_signature(
    &bundle,
    &conditions,
    DIG_MAINNET.consensus(),  // Returns &ConsensusConstants
    cache,
);
```

### Why a Wrapper Instead of Direct ConsensusConstants

```rust
// ConsensusConstants has ~30 fields, most irrelevant to DIG:
pub struct ConsensusConstants {
    pub slot_blocks_target: u32,          // PoS: not used by DIG
    pub min_blocks_per_challenge_block: u8, // PoS: not used by DIG
    pub max_sub_slot_blocks: u32,         // PoS: not used by DIG
    pub num_sps_sub_slot: u32,            // VDF: not used by DIG
    // ... many more PoS/VDF fields ...
    pub genesis_challenge: Bytes32,       // USED by DIG
    pub max_block_cost_clvm: u64,         // USED by DIG
    pub agg_sig_me_additional_data: Bytes32, // USED by DIG
    // ...
}

// NetworkConstants exposes only what DIG needs:
// - genesis_challenge()
// - agg_sig_me_additional_data()
// - max_block_cost_clvm()
// - cost_per_byte()
// - max_coin_amount()
// - consensus() (escape hatch for full access)
```

### Trait Implementations

```rust
impl NetworkConstants {
    // Clone: derived (Copy implies Clone)
    // Copy: derived (ConsensusConstants must be Copy)
    // Debug: derived (for diagnostic output)
}

// PartialEq for testing:
impl PartialEq for NetworkConstants {
    fn eq(&self, other: &Self) -> bool {
        self.genesis_challenge() == other.genesis_challenge()
            && self.max_block_cost_clvm() == other.max_block_cost_clvm()
            && self.agg_sig_me_additional_data() == other.agg_sig_me_additional_data()
    }
}
```

---

## Acceptance Criteria

- [ ] `NetworkConstants` wraps `ConsensusConstants` and provides `consensus()`, `genesis_challenge()`, `agg_sig_me_additional_data()`, `max_block_cost_clvm()`, `cost_per_byte()`, and `max_coin_amount()` accessors.
- [ ] `NetworkConstants` implements `Debug`, `Clone`, and `Copy`.
- [ ] `consensus()` returns a reference to the inner `ConsensusConstants` for use with `chia-consensus` functions.
- [ ] The type can be used as a `const` value (used to define `DIG_MAINNET` and `DIG_TESTNET`).
- [ ] No fields from `ConsensusConstants` are re-exposed that are irrelevant to DIG L2 (PoS, VDF, plot filter fields are hidden behind `consensus()`).

---

## Implementation Notes

- **Primary file:** `dig-constants/src/network.rs` or `dig-constants/src/lib.rs`.
- **const fn:** Accessor methods should be `const fn` where possible. This enables compile-time evaluation and ensures the type works in `const` contexts.
- **Copy requirement:** For `NetworkConstants` to be `Copy`, `ConsensusConstants` must also be `Copy`. If `ConsensusConstants` is not `Copy` (e.g., if it contains heap-allocated fields), the wrapper should use `Clone` instead and the const instances would need `lazy_static!` or `once_cell`.
- **Escape hatch:** The `consensus()` method provides full access to the underlying `ConsensusConstants`. This is necessary because `chia-consensus` functions require `&ConsensusConstants`, not `&NetworkConstants`. The wrapper does not try to replace the underlying type — it adds a convenience layer.
- **Future accessors:** Additional accessors can be added as needed without breaking backward compatibility. The wrapper pattern makes this straightforward.
- **No mutation:** `NetworkConstants` is immutable. There are no setter methods. Network constants are defined at compile time and never change at runtime.

---

## Verification

### Test Plan

| Test | Type | Description | Expected Result |
|------|------|-------------|-----------------|
| Accessor correctness | Unit test | DIG_MAINNET.genesis_challenge() matches expected value | Correct Bytes32 |
| max_block_cost accessor | Unit test | DIG_MAINNET.max_block_cost_clvm() | Non-zero u64 |
| cost_per_byte accessor | Unit test | DIG_MAINNET.cost_per_byte() | Non-zero u64 |
| consensus() returns inner | Unit test | DIG_MAINNET.consensus().genesis_challenge | Same as DIG_MAINNET.genesis_challenge() |
| Copy semantics | Compile test | `let a = DIG_MAINNET; let b = a; let c = a;` | Compiles (Copy trait) |
| const context | Compile test | `const X: u64 = DIG_MAINNET.max_block_cost_clvm();` | Compiles (const fn) |

---

## Source Citations

- **SPEC.md Section 4.3**: "NetworkConstants wraps ConsensusConstants. Accessors: consensus(), genesis_challenge(), agg_sig_me_additional_data(), max_block_cost_clvm(), cost_per_byte(), max_coin_amount()."
- **chia-consensus source:** `ConsensusConstants` struct definition with all fields.
- **SPEC.md Section 4.3**: Design rationale for wrapping instead of direct exposure.

---

## References

- [CON-001](CON-001.md) — Separate dig-constants crate (where this type lives)
- [CON-003](CON-003.md) — DIG_MAINNET and DIG_TESTNET (const instances of this type)
- [CON-005](CON-005.md) — AGG_SIG additional data derivation (accessed via this type)
- [CON-006](CON-006.md) — Neutral PoS/VDF fields (hidden behind consensus() accessor)
