Upgrades to StorageHub version v0.3.3. This upgrade requires both a
runtime and client upgrade.
---------
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
## Summary
- Increase `MaxBatchConfirmStorageRequests` runtime constant from 10 to
100
- Applied across all runtime environments: mainnet, stagenet, and
testnet
## Test plan
- [x] Verify builds pass for all runtime configurations
## Summary
This PR integrate the slashing feature with EigenLayer. With this PR,
slashing can now be relayed to our Datahaven AVS and then executed
within EigenLayer. In addition some refactoring of the original slashing
pallet has been done.
## Motivation
To avoid misbehaving actor in the network, Datahaven has implemented a
slashing pallet in which offenses can be reported and then if adequate
can lead to a sanction on the misbehaving node. It incentive nodes to
only follow good behavior in addition to the reward incentive. The
rewards flow is managed directly into EigenLayer (see
https://github.com/datahaven-xyz/datahaven/pull/351).
## Slashing flow
<img width="2355" height="946" alt="Slashing Flow"
src="https://github.com/user-attachments/assets/c1ddc3dc-2a7e-429d-94e0-1e02a3f65246"
/>
## What changes
* Implemented `slashValidatorsOperator` in `DataHavenServiceManager`. It
received all the slashing requests batched (every new era the queued
slashing are being relayed from substrate to Ethereum). It handle the
slashing of the operators reported into the Validator set.
* Added a `slashes_adapter.rs` utility file to remove the duplication
for each runtime. In addition, we made use of the `sol!` macro from
alloy to encode the calldata for the Ethereum call. This avoid rewriting
encoding logic and allow to remove the hardcoded selector value used to
call the slashing function.
* Added some tests in solidity to test the registering and slashing of
an operator in Ethereum via Eigen Layer.
* Added e2e tests that test the injection of a slash request, it being
relayed via the snowbridge relayer and executed by our Datahaven AVS.
## What could be better
* We are only deploying one strategy for now so it is hardcoded in the
slashing flow. We should be able to update the pallet in case we are
adding a new strategy. So communication from Ethereum should be relayed.
* We don't have error being return in case the slashing fail. Which
could happen if we don't have the right number of strategy or the
validator is not registered... etc.
* More tests for the unhappy path
This PR upgrades the StorageHub version to
[v0.3.1](https://github.com/Moonsong-Labs/storage-hub/releases/tag/v0.3.1).
The changes applied are the ones suggested in the corresponding release
notes, which in short are:
- Adding the `get_number_of_active_users_of_provider` runtime API to the
`PaymentStreams` pallet runtime APIs.
- Supporting `--max-open-forests` CLI param (has defaults).
- Supporting Prometheus telemetry.
IMPORTANT: This upgrade requires a Runtime upgrade as well as a Client
upgrade.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Upgrade to StorageHub version 0.3.0. This is a minor release, including
breaking changes.
## ⚠️ Breaking Changes ⚠️
The changes applied in this PR are according to the suggested changes in
StorageHub's [v0.3.0
release](https://github.com/Moonsong-Labs/storage-hub/releases/tag/v0.3.0)
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
## Summary
Use block authorship as direct proof of liveness for the 30% liveness
component of validator rewards. Validators who author at least one block
in a session are considered online and receive the full liveness bonus.
## Problem
The rewards pallet was checking validator liveness via ImOnline
**after** the session had rotated - at which point ImOnline had already
cleared its `AuthoredBlocks` storage. This caused all validators to
appear offline, resulting in only ~70% of expected rewards being
allocated (missing the 30% liveness bonus).
## Solution
Use **block authorship as the proxy for liveness**:
- A validator who authored at least one block is definitively online
- Liveness is determined directly in `award_session_performance_points`
via `blocks_authored > 0`
- No dependency on external liveness checks (ImOnline)
### Rewards Formula
- **60%** Block authorship (proportional to blocks produced)
- **30%** Liveness (full bonus if authored ≥1 block, zero otherwise)
- **10%** Base reward (for being in the validator set)
### Files Changed
- `pallets/external-validators-rewards/src/lib.rs` - Core logic changes
- `pallets/external-validators-rewards/src/mock.rs` - Test mock updates
- `pallets/external-validators-rewards/src/tests.rs` - Test updates
- `runtime/{mainnet,testnet,stagenet}/src/configs/mod.rs` - Config
updates
## Testing
- All 76 pallet tests pass
- Local testing should show correct points per session (e.g., 3200
points for 2 validators with 10 blocks)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
## Summary
This PR replaces the percentage-based compounding inflation model with a
**linear (non-compounding) inflation model** where a fixed amount of
tokens is minted annually, regardless of current total supply.
### Key Changes
- **`ExternalRewardsEraInflationProvider`** now calculates per-era
inflation from a fixed annual amount instead of a percentage of current
total issuance
- New **`InflationAnnualAmount`** runtime parameter using the formula:
`5_000_000 * HAVE * SUPPLY_FACTOR`
- Consistent configuration across all runtimes using `SUPPLY_FACTOR`
### Inflation Configuration
| Runtime | SUPPLY_FACTOR | Genesis Supply | Annual Inflation | Per-Era
Inflation |
|---------|---------------|----------------|------------------|-------------------|
| **Mainnet** | 100 | 10B HAVE | 500M HAVE (5%) | ~342,231 HAVE |
| **Stagenet** | 1 | 100M HAVE | 5M HAVE (5%) | ~3,422 HAVE |
| **Testnet** | 1 | 100M HAVE | 5M HAVE (5%) | ~3,422 HAVE |
### Benefits
- **Predictable rewards**: Validators and stakers receive consistent
emissions
- **Publicly auditable**: All emissions recorded on-chain
- **Non-compounding**: Same absolute amount minted each year (not
percentage of growing supply)
- **Governance-upgradeable**: `InflationAnnualAmount` can be changed via
runtime parameters
### Comparison: Before vs After
| Aspect | Before (Compounding) | After (Linear) |
|--------|---------------------|----------------|
| Formula | 5% × current_supply | Fixed 500M HAVE |
| Year 1 (10B supply) | 500M HAVE | 500M HAVE |
| Year 2 (10.5B supply) | 525M HAVE | 500M HAVE |
| Year 10 | ~814M HAVE | 500M HAVE |
## ⚠️ Breaking Changes ⚠️
- **Runtime parameter renamed**: `InflationTargetedAnnualRate` (Perbill)
→ `InflationAnnualAmount` (Balance)
- Old: percentage-based rate applied to current total issuance
- New: fixed annual amount in base units (wei)
- **`ExternalRewardsEraInflationProvider` type parameters changed**:
- Removed: `Balances` (fungible::Inspect) and `AnnualRate`
(Get<Perbill>)
- Added: `AnnualAmount` (Get<u128>)
- **Inflation behavior change**: Inflation is now linear (fixed amount)
instead of compounding (percentage of supply)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Gonza Montiel <gonzamontiel@users.noreply.github.com>
## Summary
Building on #304, this PR implements two complementary mechanisms to
improve validator incentives and network performance:
1. **Performance-Based Validator Rewards** (session-level)
2. **Inflation Scaling** (era-level)
## Reward Model Comparison
### Old Model (main branch) vs New Model
| Metric | Old Model (20 pts/block) | New Model (320 pts/block pool) |
|--------|--------------------------|--------------------------------|
| **Per Block** | Author: 20 pts, Others: 0 | Author: ~196 pts, Others:
~4 pts each |
| **Formula** | Direct author reward | 60% authoring + 30% liveness +
10% base |
| **Per Session** (600 blocks, 32 validators) | 12,000 total pts |
192,000 total pts |
| **Per Validator/Session** (uniform) | ~375 pts | ~6,000 pts |
| **Per Validator/Era** (6 sessions) | ~2,250 pts | ~36,000 pts |
| **Offline Validator** | 0 pts | ~600 pts/session (base only) |
| **Over-performer (150% blocks)** | 150% of fair share | Up to 130%
reward (soft cap) |
### Key Differences
- **Pool-based**: New model adds 320 points to a shared pool per block,
distributed via formula
- **Liveness rewarded**: 30% of rewards go to validators who are online
(heartbeat OR block authorship)
- **Base guarantee**: 10% ensures all active validators receive minimum
rewards
- **Soft cap**: Prevents extreme over-performance rewards (max 150% of
fair share credited)
## Performance-Based Validator Rewards
Introduces a **60/30/10 reward formula** that rewards validators based
on their contribution during each session:
- **60%** based on block production (with soft cap allowing up to 150%
of fair share)
- **30%** based on liveness (ImOnline heartbeat OR block authorship)
- **10%** guaranteed base reward for all active validators
### Key Features
- Tracks individual validator block authorship per session
- Calculates fair share dynamically: `fair_share = total_blocks /
total_validator_count`
- Fair share uses **total** validator count (including whitelisted)
since all validators occupy block slots
- **Soft cap**: Over-performers can earn credit up to 150% of their fair
share (configurable via `OperatorRewardsFairShareCap` at 50%)
- With 60% BlockAuthoringWeight, this gives over-performers up to **30%
bonus reward**
- **BasePointsPerBlock**: Defines points added to pool per block
produced (default: 320)
- Integrates with SessionManager for automatic point awards at session
end
- Excludes whitelisted validators from rewards (but includes them in
fair share calculation)
- Slashing check disabled but hook retained for future use
- Points accumulate across sessions within an era
### Dynamic Parameters (Governance-Adjustable)
- `OperatorRewardsBlockAuthoringWeight`: Weight for block authoring
(default: 60%)
- `OperatorRewardsLivenessWeight`: Weight for liveness (default: 30%)
- `OperatorRewardsFairShareCap`: Soft cap percentage above fair share
(default: 50%)
## Inflation Scaling
Implements **dynamic inflation scaling** that adjusts total inflation
based on network block production:
- **Minimum**: 20% of base inflation (network halt protection)
- **Maximum**: 100% of base inflation (caps at expected blocks)
- **Linear scaling** between minimum and maximum based on performance
### Scaling Examples
- 0% blocks produced → 20% inflation (safety floor)
- 50% blocks produced → 60% inflation
- 100% blocks produced → 100% inflation
- >100% blocks produced → capped at 100%
### Configuration
- **ExpectedBlocksPerEra**: Computed as `SessionsPerEra ×
EpochDurationInBlocks`
- **MinInflationPercent**: 20%
- **MaxInflationPercent**: 100%
## Combined Effect
These mechanisms work together to create a comprehensive incentive
structure:
1. **Session rewards** encourage individual validator performance and
uptime
2. **Era inflation scaling** incentivizes collective network health
3. **Minimum inflation floor** protects against network halt
4. **Soft cap** allows over-performers to earn up to 30% bonus while
preventing extreme centralization
## Implementation Details
### Pallet Changes
- Add `BlocksAuthoredInSession` storage for per-validator tracking
- Add `BlocksProducedInEra` storage for total network tracking (cleaned
up with HistoryDepth)
- Add `note_block_author()` function called on block production
- Add `award_session_performance_points()` function with configurable
60/30/10 formula
- Add `calculate_scaled_inflation()` function for era-level scaling
- Update `on_era_end()` to use scaled inflation
- Integrate with SessionManager via wrapper types
- Defensive weight validation: proportionally scales if sum > 100%
### Configuration Parameters
- `ValidatorSet`: Provides active validator list
- `LivenessCheck`: Uses `ImOnline::is_online()` (heartbeat OR block
authorship)
- `SlashingCheck`: Integration with slashing pallet (currently disabled)
- `BasePointsPerBlock`: Points added to pool per block (default: 320)
- `BlockAuthoringWeight`: Dynamic parameter (60%)
- `LivenessWeight`: Dynamic parameter (30%)
- `FairShareCap`: Dynamic parameter (50%)
- `ExpectedBlocksPerEra`: Computed from session/epoch config
- `MinInflationPercent`: 20%
- `MaxInflationPercent`: 100%
### Runtime Updates
- Full configuration added to mainnet, testnet, and stagenet runtimes
- Dynamic parameters added to `runtime_params.rs` for governance control
- Uses `prod_or_fast!()` macro for environment-specific parameters
- `ValidatorIsOnline` uses `ImOnline::is_online()` for accurate liveness
detection
## Testing
- **76 tests passing** ✅
- Comprehensive coverage of both mechanisms
### Test Coverage
- Inflation scaling at 0%, 25%, 50%, 75%, 100%, >100% blocks
- Session performance with 60/30/10 formula
- Fair share calculations with soft cap (150%)
- Whitelisted validator exclusion from rewards (with correct fair share
using total count)
- Total points verification (sum of individual = total)
- Whitelisted over-producer scenarios
- Overflow protection (large block counts, near-u32::MAX)
- End-to-end session to era flow
- MockLivenessCheck mirrors ImOnline behavior (block authorship =
online)
- Multiple eras with different performance levels
- Edge cases (zero participation, single validator, large numbers)
- BlocksProducedInEra cleanup on era start
## ⚠️ Breaking Changes ⚠️
### Reward Distribution
Previously, rewards were distributed equally among all validators
regardless of their contribution. Now:
- **Performance-based**: Validators earn rewards proportional to their
block production (60%), liveness (30%), and a guaranteed base (10%)
- **Pool-based**: `BasePointsPerBlock` defines points added to pool per
block (320), distributed via formula
- **Fair share uses total validators**: Ensures non-whitelisted aren't
penalized for whitelisted validators' block slots
- **Soft cap**: Block production rewards allow up to 150% of fair share
(50% cap = 30% bonus with 60% weight)
- **Slashing check disabled**: Hook retained for future use, but
currently not applied
### Inflation Mechanism
Previously, the full calculated inflation was minted each era. Now:
- **Scaled by performance**: Total inflation scales between 20%-100%
based on actual blocks produced vs expected
- **Safety floor**: Even with zero blocks, 20% of inflation is still
minted to prevent complete halt
- **Network incentive**: Collective block production directly impacts
total rewards available
### Pallet Configuration
The `pallet-external-validators-rewards` Config now requires additional
types:
- `BlockAuthoringWeight`, `LivenessWeight`, `FairShareCap` for reward
formula
- `ValidatorSet`, `LivenessCheck`, `SlashingCheck` for validator
tracking
- `ExpectedBlocksPerEra`, `MinInflationPercent`, `MaxInflationPercent`
for inflation scaling
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
### Context
The function `v2_sendMessage()` on Snowbridge Gateway contract is
**permissionless** (I'm shocked this is the design choice). Any
EOA/contract on Ethereum can build a message and send it through our DH
bridge. While we don't change our Snowbridge fork, then this will
continue to be the case.
### Problem
We use `v2_sendMessage()` to send **permissioned** operations to our
chain. For instance: update our validator set message (coming next,
_slashing-related_ messages). So we do need to restrict the processing
of the incoming messages on the Substrate side.
### Fix
- I've added a check to `EigenLayerMessageProcessor` that enforces
`message.origin` to be only a configured `AuthorisedOrigin`.
- I've added an `AuthorisedOrigin` to
`pallet_external_validators::Config`
- I've configured the `AuthorisedOrigin` to be
`DatahavenServiceManagerAddress` in all three runtimes
### Stages
- [x] Implementation
- [x] Runtime integration tests
- [x] Collect `DatahavenServiceManagerAddress` parameter for e2e tests
to work
Fixes https://github.com/datahaven-xyz/sr-datahaven/issues/12
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
We have two instances of `pallet_collective`
- `pallet_collective_treasury_council`
- `pallet_collective_technical_committee`
Our weights template automatically generates an implementation for
`pallet_collective_treasury_council::WeightInfo` or
`pallet_collective_technical_committee::WeightInfo`, which don't exist,
making the compilation fail right after running benches.
I created aliases for both pallet names, and added a small tweak to the
template so it does not break anymore.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
## DataHaven Native Transfer Precompile
Implements EVM precompile at address
`0x00000000000000000000000000000007F5` (2073) to expose
`pallet-datahaven-native-transfer` functionality to the EVM layer.
### Features
- **Transfer to Ethereum**: Locks native tokens and sends them via
Snowbridge to Ethereum addresses
- **Pause/Unpause**: Admin controls to halt/resume transfers
- **View Functions**: Query paused state, total locked balance, and
sovereign account address
### Implementation
- Precompile using `#[precompile_utils::precompile]` macro with proper
gas accounting
- 15+ test cases covering success/failure scenarios
- Solidity interface with NatSpec documentation for contract integration
Enables seamless cross-chain transfers of DataHaven native tokens to
Ethereum L1.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
## ⚠️ Breaking Changes ⚠️
Upgrades to SH version 0.2.0. Breaking changes for this version are
outlined in the corresponding
[release](https://github.com/Moonsong-Labs/storage-hub/releases/tag/v0.2.0).
Particularly, in this PR, the following breaking changes are implemented
for DH node operators:
### Breaking CLI changes vs `main`
- **Fisherman vs provider role**
- `--fisherman` now has `conflicts_with = "provider"`
(`FishermanConfigurations::fisherman`).
- Any existing scripts that started a node with both `--provider` and
`--fisherman` will now fail clap validation.
- **Removed / replaced fisherman tuning flags**
- The following flags no longer exist and will cause errors if still
used:
- `--fisherman-incomplete-sync-max` (field
`fisherman_incomplete_sync_max`)
- `--fisherman-incomplete-sync-page-size` (field
`fisherman_incomplete_sync_page_size`)
- `--fisherman-sync-mode-min-blocks-behind` (field
`fisherman_sync_mode_min_blocks_behind`)
- They are replaced by:
- `--fisherman-batch-interval-seconds`
(`fisherman_batch_interval_seconds`, default `60`)
- `--fisherman-batch-deletion-limit` (`fisherman_batch_deletion_limit`,
default `1000`)
- **MSP DB wiring no longer piggybacks on the indexer DB**
- Previously, enabling the indexer (`IndexerConfigurations`) also wired
its DB pool into the MSP move‑bucket path via
`with_indexer_db_pool(maybe_indexer_db_pool)`.
- Now, MSP DB access is **only** configured if you pass the new
`--msp-database-url` provider flag; the indexer’s `--indexer` /
`--indexer-database-url` no longer implicitly provide DB access to MSP
logic. This will change behaviour for MSP nodes that relied on just the
indexer flags.
### New / additive CLI flags (non‑breaking but behaviourally relevant)
- **Provider flags**
- `--pending-db-url` (`pending_db_url`, env `SH_PENDING_DB_URL`) for
persisting pending extrinsics.
- `--internal-buffer-size` (`internal_buffer_size`, default `1024`) for
DB chunk batching during file transfer.
- **Reordered but unchanged**
- `--msp-distribute-files` still exists (bool flag), just moved within
`ProviderConfigurations`; name and type are unchanged, but now also
explicitly toggles `enable_msp_distribute_files` only when
`provider_type == msp`.
Set `GasLimitPovSizeRatio` to 0 across all runtime environments
(mainnet, stagenet, testnet) since DataHaven operates as a solo chain
and doesn't need to account for Proof-of-Validity size constraints that
parachains require.
## ⚠️ Breaking Changes ⚠️
- `GasLimitPovSizeRatio` is now set to 0 across all runtimes
- Gas calculations will no longer account for POV size constraints
## Summary
Removes old runtime migrations that have already been executed on
Stagenet and Testnet environments, reducing code complexity and
maintenance burden.
## Changes
### Migration Cleanup
- **Removed `evm_alias::EvmAliasMigration`** (~532 lines)
- Multi-block migration that renamed the Frontier EVM pallet alias from
`Evm` to `EVM`
- Migrated AccountCodes, AccountCodesMetadata, and AccountStorages
- **Removed `evm_chain_id::EvmChainIdMigration`**
- Single-step migration that updated stored EVM chain IDs to match new
configuration
- Applied to testnet (55931) and stagenet (55932)
### Runtime Updates
- **Simplified `MultiBlockMigrationList`** to empty tuple `()` in
`runtime/common/src/migrations.rs`
- **Updated all runtime configs** to use simplified migration list:
- `runtime/mainnet/src/configs/mod.rs`
- `runtime/stagenet/src/configs/mod.rs`
- `runtime/testnet/src/configs/mod.rs`
- Removed `Runtime` type parameter from migration configurations
### What Remains
- `pallet_migrations` infrastructure stays in place for future
migrations
- Migration test file (`mainnet/tests/migrations.rs`) preserved for
testing pallet administrative functions
- Configuration types and constants (cursor/identifier lengths,
handlers)
## Impact
- **Code reduction**: 532 lines removed
- **No functional change**: These migrations have already executed
successfully
- **Future-ready**: Migration infrastructure remains for new migrations
when needed
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
## Summary
Replaced the `DefaultFailedMigrationHandler` (which completely froze the
chain on migration failures) with `EnterSafeModeOnFailedMigration`
across all three runtimes (mainnet, stagenet, testnet). When a migration
fails, the chain now automatically enters SafeMode instead of freezing,
allowing governance to intervene and fix issues while preventing regular
user transactions.
## Problem
Previously, when a runtime migration failed, the chain would use
`FreezeChainOnFailedMigration`, which completely halted all operations
including governance functions. This made it impossible to recover from
migration failures without manual intervention at the node level.
## Solution
Implemented `EnterSafeModeOnFailedMigration` which:
- **Enters SafeMode** when a migration fails: the chain remains
_indefinitely_ under safe mode until it is disabled, either with Sudo or
Governance.
- **Allows governance operations** to continue (Sudo, SafeMode, TxPause,
Preimage, Scheduler, etc.)
- **Blocks regular user transactions** to prevent interaction with
potentially inconsistent storage
- **Falls back to freezing** if SafeMode cannot be entered
## Changes
### Core Implementation
- **`runtime/common/src/migrations.rs`**: Added
`FailedMigrationHandler<SafeMode>` type alias that wraps
`EnterSafeModeOnFailedMigration` with comprehensive documentation
- **All three runtimes** (`mainnet`, `stagenet`, `testnet`):
- Updated `pallet_migrations::Config::FailedMigrationHandler` to use
`FailedMigrationHandler<SafeMode>`
- Removed obsolete TODO comments
### Tests
Added comprehensive migration failure tests to all three runtimes:
- **`failed_migration_enters_safe_mode`**: Verifies SafeMode is
activated, expiry is set, and event is emitted
- **`safe_mode_allows_governance_during_migration_failure`**: Confirms
governance can exit SafeMode after migration failure
- **`migrations_force_calls_are_root_only`**: Existing test for
migration management permissions
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
## Summary
- Enables BEEFY equivocation reporting which was previously disabled
(set to `()`)
- Configures `pallet_beefy::EquivocationReportSystem` in all three
runtimes (mainnet, stagenet, testnet)
- Without this fix, validators could sign conflicting BEEFY commitments
without any slashing consequences
## Problem
The `EquivocationReportSystem` type in `pallet_beefy::Config` was set to
`()`, which completely disabled BEEFY equivocation reporting. This is a
security issue because:
1. BEEFY validators could sign two different commitments at the same
block height (equivocation)
2. There was no mechanism to report and slash such misbehavior
3. This undermines the security guarantees of the BEEFY consensus
protocol
## Solution
Configure the proper equivocation report system using the same pattern
as BABE and GRANDPA:
```rust
type EquivocationReportSystem =
pallet_beefy::EquivocationReportSystem<Self, Offences, Historical, ReportLongevity>;
```
This uses:
- `Offences` pallet to record equivocations
- `Historical` pallet for validator proof verification
- `ReportLongevity` parameter (based on bonding duration) for the
reporting window
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
This PR introduces a configurable inflation system for validator rewards
with an annual target rate and optional treasury allocation.
## Changes
### Inflation Mechanism
- **Annual inflation rate runtime parameter**: Set to 5% default
- **EraInflationProvider**: Calculates per-era inflation based on total
issuance and annual rate
- Formula: `per_era_inflation = (total_issuance × annual_rate) /
eras_per_year`
### Treasury Allocation
- **InflationTreasuryProportion parameter**: Set to 20% default
- **ExternalRewardsInflationHandler**: Mints inflation and distributes
between:
- 80% to rewards account (for validator rewards)
- 20% to treasury account
- Treasury receives allocation via `mul_floor()`, with remainder going
to rewards to ensure no tokens lost to rounding
### Runtime Integration
- Configured across all three runtimes: mainnet, testnet, and stagenet
- Consistent parameters across all environments
### Testing
- Updated all tests to account for 80/20 split between rewards and
treasury
- Added precision tolerance (±1 unit) for Perbill rounding edge cases
---------
Co-authored-by: Claude <noreply@anthropic.com>
Upgrades to StorageHub release
[v0.1.4](https://github.com/Moonsong-Labs/storage-hub/releases/tag/v0.1.4).
## ⚠️ Breaking Changes ⚠️
- A DB migration for the indexer DB. Should be auto-applied by the
indexer node on startup, if this is not disabled by the env var
`SH_INDEXER_DB_AUTO_MIGRATE`. By default, it applies them.
- A new runtime API (`shp_tx_implicits_runtime_api::TxImplicitsApi`)
needed for StorageHub's Blockchain Service to build transactions using
the runtime spec version from the currently run runtime.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Update the 3 DataHaven environments' chain IDs & native token ticker as
follows:
* **Mainnet**
* **Chain ID**: 55930
* **Ticker**: HAVE
* **TestNet**
* **Chain ID**: 55931
* **Ticker**: MOCK
* **Stagenet**
* **Chain ID**: 55932
* **Ticker**: STAGE
The PR includes a storage migration for the Stagenet & Testnet
environments, that are already live, to update the EVM Chain ID stored
in the `pallet-evm-chain-id` pallet.
Note: the token symbol will only be updated with the genesis config
presets or newly generated chain specs. For already live networks, the
existing chain spec must be updated (i.e. the tokenSymbol property
changed) and used by all nodes in the network. This change in the chain
spec will not alter the chain genesis so it safe to do (in the very
early stages of the chain obviously).
---------
Co-authored-by: Claude <noreply@anthropic.com>
## Add FreeHeadersInterval parameter to Ethereum client config
Configure parameter `FreeHeadersInterval` set to `32` (1 epoch = 6.4
minutes) across `mainnet`, `stagenet`, and `testnet` configurations.
### Rationale
1. Aligns with Ethereum's epoch change, so it's easier to identify in
which epoch we are in
2. It's the value used in Snowbridge's test configuration
The value can be changed via pallet parameters.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Upgrade to SH release
[v0.1.1](https://github.com/Moonsong-Labs/storage-hub/releases/tag/v0.1.1)
---------
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
Co-authored-by: Ahmad Kaouk <ahmadkaouk.93@gmail.com>
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Following up https://github.com/datahaven-xyz/datahaven/pull/265, we
also need to add Timestamp to the whitelisted Runtime calls.
- [x] Add `RuntimeCall::Timestamp` to `SafeModeWhitelistedCalls`
- [x] Add safe mode test to check it produces blocks
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
### Add missing weights for BABE, GRANDPA, and Randomness
#### Summary
Adds generated weights and wires them into the runtime for the BABE,
GRANDPA, and Randomness pallets to replace defaults and ensure accurate
execution costs across networks.
#### What’s changed
- **New weights added** for `pallet_grandpa`, `pallet_babe` and
`pallet_randomness`
- **Runtime configs updated to use new weights**
- `operator/runtime/mainnet/src/configs/mod.rs`
- `operator/runtime/stagenet/src/configs/mod.rs`
- `operator/runtime/testnet/src/configs/mod.rs`
#### For follow-up PRS
- fix `pallet_identity` failure at running benchmarks
- fix `pallet_collective` benchmarking missmatch (related to
https://github.com/paritytech/polkadot-sdk/pull/6435)
- add `pallet_session_benchmarking` without including `pallet_staking`
(or some workaround)
- add StorageHub weights to our benchmarked pallets (`pallet_nfts`,
`pallet_storage_providers`, `pallet_payment_streams`,
`pallet_proofs_dealer`, `pallet_file_system`, `pallet_bucket_nfts`, etc)
## Summary
- Replace the legacy “estimated transaction length” heuristic in the EVM
`call` runtime API across mainnet, stagenet, and testnet with a direct
`GasWeightMapping::gas_to_weight` lookup. The resulting weight is now
always forwarded to the runner (`Some(weight_limit)`), so zero-gas
requests no longer slip through without a cap.
- Update the EVM `create` runtime API the same way. Previously it always
passed `None` for `weight_limit`, effectively running contract-deploy
dry-runs without any weight ceiling; we now map the gas limit and pass
the explicit weight instead.
- For both `call` and `create`, set the proof-size base cost to `None`
to match our solo-chain assumption that PoV size isn’t budgeted in these
simulated paths.
## Why
We use these runtime APIs when serving `eth_call` and `eth_estimateGas`.
The old behavior meant a zero gas limit (or any `create` dry-run) ran
with unlimited weight, diverging from what the extrinsic path enforces.
Passing the mapped weight—zero included—keeps RPC simulations aligned
with real execution, while dropping the proof-size estimate removes a
guessy value we don’t charge on-chain.
Add defensive validation to ensure the Ethereum sovereign account has
sufficient balance before unlocking tokens. This addresses an audit
finding where the lack of explicit balance checking created an
unreliable security control that depended on implicit runtime behavior.
Changes:
- Add InsufficientSovereignBalance error variant for clear error
messaging
- Add explicit balance check in unlock_tokens before transfer
- Update tests across all runtimes (testnet, stagenet, mainnet) to
validate the specific error is returned when sovereign account has
insufficient funds
The explicit check provides better error messages that can propagate
through the Ethereum bridge and makes debugging sovereign account
balance issues easier.
# Fix: Safe Mode Whitelisted Calls - enable block production
## Problem
The safe mode whitelist was missing critical runtime calls needed for
block production, generating this error:
```
2025-10-29 17:29:48 Proposing failed: Import failed: Extrinsic is not valid: TransactionValidityError::Invalid(InvalidTransaction::BadMandatory)
```
The SafeMode filter needs to include all RuntimeCalls that have
inherents marked as `DispatchClass::Mandatory`, as you can see
[here](bbc435c766/substrate/frame/executive/src/lib.rs (L806)).
If a single inherent is missing the whole block will not be valid,
causing the chain to stall.
## Solution
Bisect all the calls to find the culprit, until find it was the pallet
Randomness. I included it in `SafeModeWhitelistedCalls` and blocks are
being produced in SafeMode.
In this PR we set the slashing mode value in the genesis config. For the
3 different runtime we specify the slashing mode : `mainnet/testnet` is
set to `Disabled` and for `stagenet` to `LogOnly`.
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
## 🔨 Add Slashing Support for Runtime
This PR introduces the slashing functionality for the DataHaven runtime,
enabling punitive measures against misbehaving validators.
### Features
- Deferred slashing with configurable veto periods
- Cross-chain slashing message delivery trough Snowbridge
- Governance controls for slashing parameters and emergency cancellation
We introduced the `external-validator-slashes` pallet, which allows to
slash validators that misbehave. The slashing is triggered when an
offence is reported via the offence pallet (which is already
implemented). The message is sent through Snowbrige's outbound queue and
the real slashing happens in the contracts side, which will come in a
follow up PR.
There is a configurable window of time between the time the validator is
being reported, and the time the slash is triggered. This allows that in
case of an error we are still able to cancel the slashing, using a sudo
account.
For convenience, we also have extrinsics for corner cases:
- **`force_inject_slash`**: Root-only function to manually inject
slashes for specific validators with custom percentages. Useful for
emergency situations or governance-directed slashing outside normal
offence detection
- **`cancel_deferred_slash`**: Allows governance to cancel pending
slashes during the defer period by specifying era and slash indices.
Provides safety mechanism against false positives or malicious slash
reports
- **`set_slashing_mode`**: Configurable slashing behavior with three
modes - `Enabled` (normal operation), `LogOnly` (track offences without
applying slashes), and `Disabled` (completely halt slashing). Critical
for emergency response and testing
---------
Co-authored-by: Gonza Montiel <gon.montiel@gmail.com>
Co-authored-by: Gonza Montiel <gonzamontiel@users.noreply.github.com>