datahaven/contracts/deployments/state-diff.json

623 lines
537 KiB
JSON
Raw Normal View History

{
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"33": {
"address": "0x9A676e781A523b5d0C0e43731313A708CB607508",
"code": "0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f5ffd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f5f375f5f365f845af43d5f5f3e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f5f856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f5f85851115610676575f5ffd5b83861115610682575f5ffd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f5ffd5b919050565b5f602082840312156106ba575f5ffd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e8575f5ffd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f5ffd5b8301601f8101851361071c575f5ffd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c657665
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000a85233c63b9ee964add6f2cffe00fd84eb32338f",
"0x0000000000000000000000000000000000000000000000000000000000000033": "0x00000000000000000000000015d34aaf54267db7d7c367839aaf71a00a2c6a65",
"0xedc9a600799bdec0e14ee5042ef794e1b4738abf52d225059d6b470373867218": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788",
"0x0000000000000000000000000000000000000000000000000000000000000065": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x00000000000000000000000000000000000000000000000000000000000000cb": "0x0000000000000000000000009965507d1a55bcc2695c58ba16fb37d819b0a4dc"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"19": {
"address": "0x4A679253410272dd5232B3Ff7cF5dbB88f295319",
"code": "0x608060405234801561000f575f5ffd5b5060043610610148575f3560e01c8063a1060c88116100bf578063dce974b911610079578063dce974b914610334578063df5cf7231461035b578063ec76f44214610382578063f2fde38b146103b5578063f698da25146103c8578063fabc1cbc146103d0575f5ffd5b8063a1060c881461029a578063a364f4da146102ad578063a98fb355146102c0578063c825fe68146102d3578063cd6dc687146102fa578063d79aceab1461030d575f5ffd5b80635ac86ab7116101105780635ac86ab7146101fa5780635c975abb1461021d578063715018a61461022f578063886f1195146102375780638da5cb5b146102765780639926ee7d14610287575f5ffd5b8063136439dd1461014c578063374823b51461016157806349075da3146101a357806354fd4d50146101dd578063595c6a67146101f2575b5f5ffd5b61015f61015a3660046110dc565b6103e3565b005b61018e61016f366004611107565b609960209081525f928352604080842090915290825290205460ff1681565b60405190151581526020015b60405180910390f35b6101d06101b1366004611131565b609860209081525f928352604080842090915290825290205460ff1681565b60405161019a919061117c565b6101e561041d565b60405161019a91906111d0565b61015f61044d565b61018e6102083660046111e9565b606654600160ff9092169190911b9081161490565b6066545b60405190815260200161019a565b61015f610461565b61025e7f000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e81565b6040516001600160a01b03909116815260200161019a565b6033546001600160a01b031661025e565b61015f610295366004611277565b610472565b6102216102a8366004611364565b610673565b61015f6102bb3660046113a7565b6106f2565b61015f6102ce3660046113c2565b6107b9565b6102217f809c5ac049c45b7a7f050a20f00c16cf63797efbf8b1eb8d749fdfa39ff8f92981565b61015f610308366004611107565b610800565b6102217fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd81565b6102217f4ee65f64218c67b68da66fd0db16560040a6b973290b9e71912d661ee53fe49581565b61025e7f0000000000000000000000000dcd1bf9a1b36ce34237eeafef220932846bcd8281565b61015f6103903660046110dc565b335f90815260996020908152604080832093835292905220805460ff19166001179055565b61015f6103c33660046113a7565b61091c565b610221610995565b61015f6103de3660046110dc565b610a4e565b6103eb610ab4565b60665481811681146104105760405163c61dca5d60e01b815260040160405180910390fd5b61041982610b57565b5050565b60606104487f76312e302e300000000000000000000000000000000000000000000000000006610b94565b905090565b610455610ab4565b61045f5f19610b57565b565b610469610bd1565b61045f5f610c2b565b5f61047c81610c7c565b6001335f9081526098602090815260408083206001600160a01b038816845290915290205460ff1660018111156104b5576104b5611168565b036104d357604051631aa528bb60e11b815260040160405180910390fd5b6001600160a01b0383165f90815260996020908152604080832085830151845290915290205460ff161561051a57604051630d4c4c9160e21b815260040160405180910390fd5b6040516336b87bd760e11b81526001600160a01b0384811660048301527f0000000000000000000000000dcd1bf9a1b36ce34237eeafef220932846bcd821690636d70f7ae90602401602060405180830381865afa15801561057e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105a29190611430565b6105bf57604051639f88c8af60e01b815260040160405180910390fd5b6105e3836105d7853386602001518760400151610673565b84516040860151610ca7565b6001600160a01b0383165f81815260996020908152604080832086830151845282528083208054600160ff19918216811790925533808652609885528386208787529094529382902080549094168117909355519092917ff0952b1c65271d819d39983d2abb044b9cace59bcc4d4dd389f586ebdcb15b4191610666919061117c565b60405180910390a3505050565b604080517fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd60208201526001600160a01b038087169282019290925290841660608201526080810183905260a081018290525f906106e99060c00160405160208183030381529060405280519060200120610cff565b95945050505050565b5f6106fc81610c7c565b6001335f9081526098602090815260408083206001600160a01b038716845290915290205460ff16600181111561073557610735611168565b14610753576040516352df45c960e01b815260040160405180910390fd5b335f8181526098602090815260408083206001600160a01b0387168085529252808320805460ff191690555190917ff0952b1c65271d819d39983d2abb044b9cace59bcc4d4dd389f586ebdcb15b41916107ad919061117c565b60405180910390a35050565b336001600160a01b03167fa89c1dc243d8908a96dd84944bcc97d6bc6ac00dd78e20621576be6a3c94371383836040516107f492919061144f565b604051
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"38": {
"address": "0x59b670e9fA9D0A427751Af201D676719a970857b",
"code": "0x6080604052600436106101bd575f3560e01c80636691954e116100f2578063b522538a11610092578063d06d558711610062578063d06d55871461063f578063dda3346c1461065e578063ee94d67c1461067d578063f074ba621461069c575f5ffd5b8063b522538a146105ce578063c44e30dc146105ed578063c490744214610601578063c4d66de814610620575f5ffd5b80637439841f116100cd5780637439841f1461053457806374cdd7981461056957806388676cad1461059c5780639b4e4634146105bb575f5ffd5b80636691954e146104d65780636c0d2d5a146104e95780636fcd0e5314610508575f5ffd5b806342ecff2a1161015d57806352396a591161013857806352396a591461043657806354fd4d501461046a578063587533571461048b57806358eaee79146104aa575f5ffd5b806342ecff2a146102f25780634665bcda1461031857806347d283721461034b575f5ffd5b80632340e8d3116101985780632340e8d31461027a5780633474aa161461028f5780633f5fa57a146102c05780633f65cf19146102d3575f5ffd5b8063039157d2146101fb5780630b18ff661461021c5780631e51553314610258575f5ffd5b366101f7576040513481527f6fdd3dbdb173299608c0aa9f368735857c8842b581f8389238bf05bd04b3bf499060200160405180910390a1005b5f5ffd5b348015610206575f5ffd5b5061021a610215366004613a3e565b6106bb565b005b348015610227575f5ffd5b5060335461023b906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610263575f5ffd5b5061026c6109f0565b60405190815260200161024f565b348015610285575f5ffd5b5061026c60395481565b34801561029a575f5ffd5b506034546001600160401b03165b6040516001600160401b03909116815260200161024f565b61021a6102ce366004613af9565b610a11565b3480156102de575f5ffd5b5061021a6102ed366004613b37565b610d49565b3480156102fd575f5ffd5b50603a546102a890600160401b90046001600160401b031681565b348015610323575f5ffd5b5061023b7f000000000000000000000000959922be3caee4b8cd9a407cc3ac1c251c2007b181565b348015610356575f5ffd5b506103db6040805160a0810182525f80825260208201819052918101829052606081018290526080810191909152506040805160a081018252603c548152603d5462ffffff811660208301526001600160401b0363010000008204811693830193909352600160581b810460070b6060830152600160981b9004909116608082015290565b60405161024f91905f60a0820190508251825262ffffff60208401511660208301526001600160401b036040840151166040830152606083015160070b60608301526001600160401b03608084015116608083015292915050565b348015610441575f5ffd5b506102a8610450366004613c0e565b603b6020525f90815260409020546001600160401b031681565b348015610475575f5ffd5b5061047e610fd2565b60405161024f9190613c57565b348015610496575f5ffd5b50603e5461023b906001600160a01b031681565b3480156104b5575f5ffd5b506104c96104c4366004613ca6565b610ffd565b60405161024f9190613d0c565b61021a6104e4366004613af9565b61105f565b3480156104f4575f5ffd5b5061026c610503366004613c0e565b611361565b348015610513575f5ffd5b50610527610522366004613d1a565b61146f565b60405161024f9190613d31565b34801561053f575f5ffd5b506104c961054e366004613d1a565b5f90815260366020526040902054600160c01b900460ff1690565b348015610574575f5ffd5b5061023b7f000000000000000000000000c7f2cf4845c6db0e1a1e91ed41bcd0fcc1b0e14181565b3480156105a7575f5ffd5b5061021a6105b6366004613d91565b61151a565b61021a6105c9366004613dac565b61160f565b3480156105d9575f5ffd5b506105276105e8366004613ca6565b61178d565b3480156105f8575f5ffd5b5061026c61187c565b34801561060c575f5ffd5b5061021a61061b366004613e41565b611898565b34801561062b575f5ffd5b5061021a61063a366004613e6b565b6119cf565b34801561064a575f5ffd5b5061021a610659366004613e6b565b611b19565b348015610669575f5ffd5b5061021a610678366004613f56565b611bad565b348015610688575f5ffd5b50603a546102a8906001600160401b031681565b3480156106a7575f5ffd5b5061021a6106b6366004614028565b611d0c565b604051635ac86ab760e01b8152600660048201819052907f000000000000000000000000959922be3caee4b8cd9a407cc3ac1c251c2007b16001600160a01b031690635ac86ab790602401602060405180830381865afa158015610721573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610745919061408f565b156107635760405163840a48d560e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600860048201819052907f000000000000000000000000959922be3caee4b8cd9a407cc3ac1c251c2007b16001600160a01b031690635ac86ab790602401602060405180830381865afa1580156107c9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ed919061408f565b1561080b576040516384
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"26": {
"address": "0x0B306BF915C4d645ff596e518fAf3F9669b97016",
"code": "0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f5ffd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f5f375f5f365f845af43d5f5f3e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f5f856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f5f85851115610676575f5ffd5b83861115610682575f5ffd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f5ffd5b919050565b5f602082840312156106ba575f5ffd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e8575f5ffd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f5ffd5b8301601f8101851361071c575f5ffd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c657665
"storage": {
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788",
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000000000000000000000004a679253410272dd5232b3ff7cf5dbb88f295319",
"0x0000000000000000000000000000000000000000000000000000000000000033": "0x00000000000000000000000015d34aaf54267db7d7c367839aaf71a00a2c6a65",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"4": {
"address": "0x1111111111111111111111111111111111111111",
"code": "0x608060405234801561000f575f5ffd5b506004361061004a575f3560e01c80632baeceb71461004e5780638381f58a146100585780638da5cb5b14610073578063d826f88f1461009e575b5f5ffd5b6100566100a6565b005b6100605f5481565b6040519081526020015b60405180910390f35b600154610086906001600160a01b031681565b6040516001600160a01b03909116815260200161006a565b61005661010d565b5f5f54116100fb5760405162461bcd60e51b815260206004820152601f60248201527f4e756d6265722073686f756c642062652067726561746572207468616e20300060448201526064015b60405180910390fd5b60015f54610109919061016d565b5f55565b6001546001600160a01b031633146101675760405162461bcd60e51b815260206004820152601760248201527f4f6e6c792063616c6c61626c65206279206f776e65722100000000000000000060448201526064016100f2565b600a5f55565b8181038181111561018c57634e487b7160e01b5f52601160045260245ffd5b9291505056fea2646970667358221220ac5899491afd834afd223fd632497d1c0c7593961eda22f04c58db4b504999cf64736f6c634300081c0033000000",
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000000000000000000000000000000000000000000a"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"36": {
"address": "0xdf077F5F72071dF6e8B0a78071E496bA17b5Ee0c",
"code": "0x608060405260043610610036575f3560e01c8063338c5371146100415780639bb66b2814610091578063e905182a146100be575f5ffd5b3661003d57005b5f5ffd5b34801561004c575f5ffd5b506100747f0000000000000000000000009d4454b023096f34b160d6b654540c56a1f8168881565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561009c575f5ffd5b506100b06100ab3660046101ae565b6100ff565b604051610088929190610239565b3480156100c9575f5ffd5b506100f17f81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b7981565b604051908152602001610088565b5f6060336001600160a01b037f0000000000000000000000009d4454b023096f34b160d6b654540c56a1f81688161461014a576040516282b42960e81b815260040160405180910390fd5b846001600160a01b03168484604051610164929190610277565b5f60405180830381855af49150503d805f811461019c576040519150601f19603f3d011682016040523d82523d5f602084013e6101a1565b606091505b5091509150935093915050565b5f5f5f604084860312156101c0575f5ffd5b83356001600160a01b03811681146101d6575f5ffd5b9250602084013567ffffffffffffffff8111156101f1575f5ffd5b8401601f81018613610201575f5ffd5b803567ffffffffffffffff811115610217575f5ffd5b866020828401011115610228575f5ffd5b939660209190910195509293505050565b8215158152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f8301168401019150509392505050565b818382375f910190815291905056fea26469706673582212208fe760f358faedf4a90fd4b23c39c8397def11c5b035ea1406af976ecc426bbf64736f6c634300081c00330000000000",
"storage": {}
},
"24": {
"address": "0x0000BBdDc7CE488642fb579F8B00f3a590007251",
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd00",
"storage": {}
},
"41": {
"address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9",
"code": "0x73dc64a140aa3e981100a9beca4e685f962f0cf6c93014608060405260043610610090575f3560e01c8063741fad8811610063578063741fad88146101125780638257f3d514610131578063ae8a4d9814610150578063c31308d11461016f575f5ffd5b80630c86ea461461009457806325394645146100b55780635b2e9c4c146100d457806365529675146100f3575b5f5ffd5b81801561009f575f5ffd5b506100b36100ae366004610a3a565b61018e565b005b8180156100c0575f5ffd5b506100b36100cf366004610a3a565b610229565b8180156100df575f5ffd5b506100b36100ee366004610a3a565b6102af565b8180156100fe575f5ffd5b506100b361010d366004610a8f565b610337565b81801561011d575f5ffd5b506100b361012c366004610adf565b6103aa565b81801561013c575f5ffd5b506100b361014b366004610a3a565b610433565b81801561015b575f5ffd5b506100b361016a366004610a3a565b6104c4565b81801561017a575f5ffd5b506100b3610189366004610a8f565b6104ee565b7f59ef95eb9983b1a4650e1bc666384b8507689fc8aca3edd429d7e07c0ca9d2f65f6101bc84840185610baf565b8051835560208101516001840180546fffffffffffffffffffffffffffffffff19166001600160801b039092169190911790556040808201516002850155519091507f5e3c25378b5946068b94aa2ea10c4c1e215cc975f994322b159ddc9237a973d4905f90a150505050565b5f61023682840184610c6d565b80516020820151604080840151905163a3499c7360e01b8152939450732279b7a0a67db372996a5fab50d91eaa73d2ebe69363a3499c739361027e9390929091600401610d22565b5f6040518083038186803b158015610294575f5ffd5b505af41580156102a6573d5f5f3e3d5ffd5b50505050505050565b7f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c22e5f6102dd84840185610d51565b805160208201516001600160801b03908116600160801b0291161760028401556040808201516003850155519091507f4793c0cb5bef4b1fdbbfbcf17e06991844eb881088b012442af17a12ff38d5cd905f90a150505050565b5f61034482840184610d86565b90505f610353825f01516105c4565b60208301519091506001600160a01b031661038a576103858582846040015185606001516001600160801b031661061c565b6103a3565b6103a38582846020015185604001518660600151610679565b5050505050565b60408051637061726160e01b602080830191909152607d60e31b602483015282516008818403018152602890920190925280519101206103eb9084906106de565b15610408576040516282b42960e81b815260040160405180910390fd5b5f61041582840184610de4565b905061042d815f0151826020015183604001516106e9565b50505050565b7e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ab5f61046084840185610e2f565b8051835491925090839060ff19166001838181111561048157610481610e7d565b021790555080516040517f4016a1377b8961c4aa6f3a2d3de830a685ddbfe0f228ffc0208eb96304c4cf1a916104b691610e91565b60405180910390a150505050565b5f6104d182840184610eb7565b905061042d815f0151826020015183604001518460600151610762565b5f6104fb82840184610f71565b90505f61050a825f01516105c4565b90508160200151515f03610531576040516309e256f760e21b815260040160405180910390fd5b5f5f836020015180602001905181019061054b919061104f565b90925090505f82801561056057610560610e7d565b036102a6575f5f5f8380602001905181019061057c919061109f565b919450925090506001600160a01b0383166105ab576105a68a8784846001600160801b031661061c565b6105b8565b6105b88a87858585610679565b50505050505050505050565b5f8181527e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ad60205260409020546001600160a01b0316806106175760405163d3227c9b60e01b815260040160405180910390fd5b919050565b6040516001600160a01b0383166024820152604481018290525f9060640160408051601f198184030181529190526020810180516001600160e01b03166305b1137b60e01b17905290506106718486836108ad565b505050505050565b6040516001600160a01b038085166024830152831660448201526001600160801b03821660648201525f9060840160408051601f198184030181529190526020810180516001600160e01b03166309733b7b60e21b17905290506102a68587836108ad565b818114155b92915050565b5f6106f384610939565b6040516340c10f1960e01b81526001600160a01b0385811660048301526001600160801b0385166024830152919250908216906340c10f19906044015f604051808303815f87803b158015610746575f5ffd5b505af1158015610758573d5f5f3e3d5ffd5b5050505050505050565b5f8481527f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c23260205260408120547f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c22e906001600160a01b0316156107d857604051633ea7ffd960e11b815260040160405180910390fd5b5f8585856040516107e8906109e9565b6107f4939291906110e9565b604051
"storage": {}
},
"17": {
"address": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f",
"code": "0x608060405234801561000f575f5ffd5b506004361061026b575f3560e01c80637ecebe001161014b578063ca8aa7c7116100bf578063f2fde38b11610084578063f2fde38b1461062f578063f3b4a00014610642578063f698da251461064c578063fabc1cbc14610654578063fd98042314610667578063fe243a171461067a575f5ffd5b8063ca8aa7c71461059b578063cbc2bd62146105c2578063de44acb6146105d5578063df5cf723146105f5578063e7a050aa1461061c575f5ffd5b80638da5cb5b116101105780638da5cb5b1461052b57806394f649dd1461053c578063967fc0d21461054f5780639ac01d6114610562578063b5d8b5b814610575578063c665670214610588575f5ffd5b80637ecebe001461047f578063829fca731461049e578063886f1195146104b157806388c10299146104f05780638b8aac3c14610503575f5ffd5b806350ff7225116101e25780635de08ff2116101a75780635de08ff2146103fc578063663c1de41461040f578063715018a614610431578063724af4231461043957806376fb162b1461044c5780637def15641461045f575f5ffd5b806350ff72251461037c57806354fd4d50146103a4578063595c6a67146103b95780635ac86ab7146103c15780635c975abb146103f4575f5ffd5b806332e89ace1161023357806332e89ace146102f157806336a8c500146103045780633f292b081461031a5780633fb99ca51461032f57806348825e94146103425780634b6d5d6e14610369575f5ffd5b8063136439dd1461026f5780631794bb3c146102845780632d44def6146102975780632eae418c146102bd57806331f8fb4c146102d0575b5f5ffd5b61028261027d366004612e33565b6106a4565b005b610282610292366004612e5e565b6106de565b6102aa6102a5366004612eb2565b610804565b6040519081526020015b60405180910390f35b6102826102cb366004612ef0565b6108b6565b6102e36102de366004612f3e565b610982565b6040516102b4929190612fda565b6102aa6102ff36600461304b565b610b10565b61030c610b95565b6040516102b4929190613125565b610322610cb0565b6040516102b4919061317b565b61028261033d3660046131d8565b610d98565b6102aa7f4337f82d142e41f2a8c10547cd8c859bddb92262a61058e77842e24d9dea922481565b61028261037736600461321c565b610ee0565b61038f61038a366004612e5e565b61102d565b604080519283526020830191909152016102b4565b6103ac6110a1565b6040516102b49190613265565b6102826110d1565b6103e46103cf366004613277565b609854600160ff9092169190911b9081161490565b60405190151581526020016102b4565b6098546102aa565b61028261040a366004613297565b6110e5565b6103e461041d36600461321c565b60d16020525f908152604090205460ff1681565b610282611238565b6102aa610447366004612e5e565b611249565b6102aa61045a366004612eb2565b6112a6565b61047261046d366004613306565b6112f5565b6040516102b49190613320565b6102aa61048d36600461321c565b60ca6020525f908152604090205481565b6102aa6104ac366004612f3e565b611327565b6104d87f000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e81565b6040516001600160a01b0390911681526020016102b4565b6104726104fe366004612f3e565b611361565b6102aa61051136600461321c565b6001600160a01b03165f90815260ce602052604090205490565b6033546001600160a01b03166104d8565b6102e361054a36600461321c565b611498565b60cb546104d8906001600160a01b031681565b6102aa610570366004613332565b61160f565b610282610583366004613297565b6116a0565b61028261059636600461321c565b6117e7565b6104d87f00000000000000000000000068b1d87f95878fe05b998f19b66f4baba5de1aed81565b6104d86105d0366004613393565b61180a565b6105e86105e336600461321c565b61183e565b6040516102b491906133bd565b6104d87f0000000000000000000000000dcd1bf9a1b36ce34237eeafef220932846bcd8281565b6102aa61062a366004612e5e565b6118b1565b61028261063d36600461321c565b6118e4565b6104d8620e16e481565b6102aa61195a565b610282610662366004612e33565b611a13565b6102aa61067536600461321c565b611a80565b6102aa6106883660046133cf565b60cd60209081525f928352604080842090915290825290205481565b6106ac611a95565b60985481811681146106d15760405163c61dca5d60e01b815260040160405180910390fd5b6106da82611b38565b5050565b5f54610100900460ff16158080156106fc57505f54600160ff909116105b806107155750303b15801561071557505f5460ff166001145b61077d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff19166001179055801561079e575f805461ff0019166101001790555b6107a782611b38565b6107b084611b75565b6107b983611bc6565b80156107fe575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016040
feat: Implement EigenLayer Rewards V2 distribution (#351) ### Summary This PR implements the EigenLayer Rewards Distribution V2 model for DataHaven, replacing the previous merkle-root-based rewards registry approach with EigenLayer's native `OperatorDirectedRewardsSubmission` API. This enables direct integration with EigenLayer's RewardsCoordinator for validator rewards distribution. ### Motivation EigenLayer's V2 rewards model provides several advantages: - **Direct integration**: Uses EigenLayer's native `createOperatorDirectedOperatorSetRewardsSubmission` API - **Per-operator rewards**: Distributes rewards proportionally to individual operators based on their earned points - **Simplified architecture**: Removes the need for a separate RewardsRegistry contract - **Better UX**: Operators receive rewards directly through EigenLayer's established claiming mechanism ### Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ DataHaven Substrate │ ├─────────────────────────────────────────────────────────────────┤ │ Era End │ │ │ │ │ ▼ │ │ external-validators-rewards pallet │ │ │ generate_era_rewards_utils() │ │ │ • Calculate individual points per validator │ │ │ • Compute total inflation amount │ │ │ │ │ ▼ │ │ RewardsSubmissionAdapter (runtime_common) │ │ │ build() → points_to_rewards() → encode_rewards_calldata() │ │ │ │ │ ▼ │ │ Snowbridge Outbound Queue │ │ │ CallContract(ServiceManager.submitRewards(...)) │ └────│────────────────────────────────────────────────────────────┘ │ ▼ Cross-chain message via Snowbridge ┌─────────────────────────────────────────────────────────────────┐ │ Ethereum │ ├─────────────────────────────────────────────────────────────────┤ │ DataHavenServiceManager │ │ │ submitRewards(OperatorDirectedRewardsSubmission) │ │ │ • Approve wHAVE tokens to RewardsCoordinator │ │ │ │ │ ▼ │ │ EigenLayer RewardsCoordinator │ │ │ createOperatorDirectedOperatorSetRewardsSubmission() │ │ │ │ │ ▼ │ │ Operators claim rewards via EigenLayer │ └─────────────────────────────────────────────────────────────────┘ ``` ### Changes Overview #### Smart Contracts (`contracts/`) **DataHavenServiceManager.sol** - Added `submitRewards(OperatorDirectedRewardsSubmission)` function to submit rewards to EigenLayer's RewardsCoordinator - Implements `SafeERC20` for secure token approvals - Uses `onlyRewardsInitiator` modifier for access control (Snowbridge Agent) - Emits `RewardsSubmitted` and `RewardsInitiatorSet` events for tracking **IDataHavenServiceManager.sol** - Added `submitRewards()` interface for EigenLayer rewards submission - Added `setRewardsInitiator()` interface for configuring the authorized caller - Added new events: `RewardsSubmitted`, `RewardsInitiatorSet` **New Test: RewardsSubmitter.t.sol** - Comprehensive test suite covering: - Access control (only rewards initiator can submit) - Single and multiple operator rewards - Multiple consecutive submissions - Custom descriptions and different tokens #### Substrate Runtime (`operator/`) **New: `runtime/common/src/rewards_adapter.rs` (934 lines)** A generic, configurable adapter for building EigenLayer rewards messages: - **`RewardsSubmissionConfig` trait**: Runtime-agnostic configuration interface - `OutboundQueue`: Snowbridge outbound queue type - `rewards_duration()`: Reward period duration (typically 86400s) - `whave_token_address()`: wHAVE ERC20 token on Ethereum - `service_manager_address()`: ServiceManager contract address - `rewards_agent_origin()`: Snowbridge agent origin - **`RewardsSubmissionAdapter<C>`**: Generic implementation of `SendMessage` trait - **`points_to_rewards()`**: Converts validator points to token amounts - Proportional distribution based on total points - Returns remainder (dust) from integer division - Arithmetic overflow/underflow protection - **`encode_rewards_calldata()`**: ABI-encodes the `submitRewards` call - Uses `alloy-core` for type-safe Solidity ABI encoding - Validates `uint96` multiplier bounds - **Comprehensive test suite** covering: - Basic and edge-case reward calculations - Remainder/dust handling - Overflow/underflow protection - ABI encoding round-trip verification - Message building with various configurations **Modified: `pallets/external-validators-rewards/`** - **`types.rs`**: Extended `EraRewardsUtils` struct: ```rust pub struct EraRewardsUtils { pub era_index: u32, // NEW pub rewards_merkle_root: H256, pub leaves: Vec<H256>, pub leaf_index: Option<u64>, pub total_points: u128, pub individual_points: Vec<(H160, u32)>, // NEW pub inflation_amount: u128, // NEW pub era_start_timestamp: u32 // NEW } ``` - **`lib.rs`**: Updated `generate_era_rewards_utils()`: - Now accepts `inflation_amount` parameter - Extracts `individual_points` as `(H160, u32)` tuples for EigenLayer - Returns `None` when `total_points` is zero (prevents inflation with no distribution) - **`mock.rs`**: Updated test mock to use `H160` as `AccountId` (matching DataHaven's EVM-compatible account model) **Modified: Runtime Configurations** All three runtimes (mainnet, stagenet, testnet) updated: 1. **New runtime parameters** (`runtime_params.rs`): - `ServiceManagerAddress`: DataHaven ServiceManager contract on Ethereum - `WHAVETokenAddress`: wHAVE ERC20 token address - `RewardsGenesisTimestamp`: EigenLayer-aligned genesis timestamp - `RewardsDuration`: Rewards period (default: 86400 = 1 day) 2. **Refactored `RewardsSendAdapter`**: - Replaced inline implementation with `RewardsSubmissionAdapter<Config>` - Each runtime implements `RewardsSubmissionConfig` trait - Cleaner, DRY configuration ## ⚠️ Breaking Changes ⚠️ - **Runtime Parameters**: New parameters must be configured via governance before rewards submission will work: - `ServiceManagerAddress` (replaces `RewardsRegistryAddress`) - `WHAVETokenAddress` - `RewardsGenesisTimestamp` - **Contract Interface**: `submitRewards()` now accepts a full `OperatorDirectedRewardsSubmission` struct instead of a merkle root --------- Co-authored-by: Gonza Montiel <gonzamontiel@users.noreply.github.com>
2026-01-06 23:53:03 +00:00
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
feat: Implement EigenLayer Rewards V2 distribution (#351) ### Summary This PR implements the EigenLayer Rewards Distribution V2 model for DataHaven, replacing the previous merkle-root-based rewards registry approach with EigenLayer's native `OperatorDirectedRewardsSubmission` API. This enables direct integration with EigenLayer's RewardsCoordinator for validator rewards distribution. ### Motivation EigenLayer's V2 rewards model provides several advantages: - **Direct integration**: Uses EigenLayer's native `createOperatorDirectedOperatorSetRewardsSubmission` API - **Per-operator rewards**: Distributes rewards proportionally to individual operators based on their earned points - **Simplified architecture**: Removes the need for a separate RewardsRegistry contract - **Better UX**: Operators receive rewards directly through EigenLayer's established claiming mechanism ### Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ DataHaven Substrate │ ├─────────────────────────────────────────────────────────────────┤ │ Era End │ │ │ │ │ ▼ │ │ external-validators-rewards pallet │ │ │ generate_era_rewards_utils() │ │ │ • Calculate individual points per validator │ │ │ • Compute total inflation amount │ │ │ │ │ ▼ │ │ RewardsSubmissionAdapter (runtime_common) │ │ │ build() → points_to_rewards() → encode_rewards_calldata() │ │ │ │ │ ▼ │ │ Snowbridge Outbound Queue │ │ │ CallContract(ServiceManager.submitRewards(...)) │ └────│────────────────────────────────────────────────────────────┘ │ ▼ Cross-chain message via Snowbridge ┌─────────────────────────────────────────────────────────────────┐ │ Ethereum │ ├─────────────────────────────────────────────────────────────────┤ │ DataHavenServiceManager │ │ │ submitRewards(OperatorDirectedRewardsSubmission) │ │ │ • Approve wHAVE tokens to RewardsCoordinator │ │ │ │ │ ▼ │ │ EigenLayer RewardsCoordinator │ │ │ createOperatorDirectedOperatorSetRewardsSubmission() │ │ │ │ │ ▼ │ │ Operators claim rewards via EigenLayer │ └─────────────────────────────────────────────────────────────────┘ ``` ### Changes Overview #### Smart Contracts (`contracts/`) **DataHavenServiceManager.sol** - Added `submitRewards(OperatorDirectedRewardsSubmission)` function to submit rewards to EigenLayer's RewardsCoordinator - Implements `SafeERC20` for secure token approvals - Uses `onlyRewardsInitiator` modifier for access control (Snowbridge Agent) - Emits `RewardsSubmitted` and `RewardsInitiatorSet` events for tracking **IDataHavenServiceManager.sol** - Added `submitRewards()` interface for EigenLayer rewards submission - Added `setRewardsInitiator()` interface for configuring the authorized caller - Added new events: `RewardsSubmitted`, `RewardsInitiatorSet` **New Test: RewardsSubmitter.t.sol** - Comprehensive test suite covering: - Access control (only rewards initiator can submit) - Single and multiple operator rewards - Multiple consecutive submissions - Custom descriptions and different tokens #### Substrate Runtime (`operator/`) **New: `runtime/common/src/rewards_adapter.rs` (934 lines)** A generic, configurable adapter for building EigenLayer rewards messages: - **`RewardsSubmissionConfig` trait**: Runtime-agnostic configuration interface - `OutboundQueue`: Snowbridge outbound queue type - `rewards_duration()`: Reward period duration (typically 86400s) - `whave_token_address()`: wHAVE ERC20 token on Ethereum - `service_manager_address()`: ServiceManager contract address - `rewards_agent_origin()`: Snowbridge agent origin - **`RewardsSubmissionAdapter<C>`**: Generic implementation of `SendMessage` trait - **`points_to_rewards()`**: Converts validator points to token amounts - Proportional distribution based on total points - Returns remainder (dust) from integer division - Arithmetic overflow/underflow protection - **`encode_rewards_calldata()`**: ABI-encodes the `submitRewards` call - Uses `alloy-core` for type-safe Solidity ABI encoding - Validates `uint96` multiplier bounds - **Comprehensive test suite** covering: - Basic and edge-case reward calculations - Remainder/dust handling - Overflow/underflow protection - ABI encoding round-trip verification - Message building with various configurations **Modified: `pallets/external-validators-rewards/`** - **`types.rs`**: Extended `EraRewardsUtils` struct: ```rust pub struct EraRewardsUtils { pub era_index: u32, // NEW pub rewards_merkle_root: H256, pub leaves: Vec<H256>, pub leaf_index: Option<u64>, pub total_points: u128, pub individual_points: Vec<(H160, u32)>, // NEW pub inflation_amount: u128, // NEW pub era_start_timestamp: u32 // NEW } ``` - **`lib.rs`**: Updated `generate_era_rewards_utils()`: - Now accepts `inflation_amount` parameter - Extracts `individual_points` as `(H160, u32)` tuples for EigenLayer - Returns `None` when `total_points` is zero (prevents inflation with no distribution) - **`mock.rs`**: Updated test mock to use `H160` as `AccountId` (matching DataHaven's EVM-compatible account model) **Modified: Runtime Configurations** All three runtimes (mainnet, stagenet, testnet) updated: 1. **New runtime parameters** (`runtime_params.rs`): - `ServiceManagerAddress`: DataHaven ServiceManager contract on Ethereum - `WHAVETokenAddress`: wHAVE ERC20 token address - `RewardsGenesisTimestamp`: EigenLayer-aligned genesis timestamp - `RewardsDuration`: Rewards period (default: 86400 = 1 day) 2. **Refactored `RewardsSendAdapter`**: - Replaced inline implementation with `RewardsSubmissionAdapter<Config>` - Each runtime implements `RewardsSubmissionConfig` trait - Cleaner, DRY configuration ## ⚠️ Breaking Changes ⚠️ - **Runtime Parameters**: New parameters must be configured via governance before rewards submission will work: - `ServiceManagerAddress` (replaces `RewardsRegistryAddress`) - `WHAVETokenAddress` - `RewardsGenesisTimestamp` - **Contract Interface**: `submitRewards()` now accepts a full `OperatorDirectedRewardsSubmission` struct instead of a merkle root --------- Co-authored-by: Gonza Montiel <gonzamontiel@users.noreply.github.com>
2026-01-06 23:53:03 +00:00
}
},
"27": {
"address": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82",
"code": "0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f5ffd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f5f375f5f365f845af43d5f5f3e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f5f856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f5f85851115610676575f5ffd5b83861115610682575f5ffd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f5ffd5b919050565b5f602082840312156106ba575f5ffd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e8575f5ffd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f5ffd5b8301601f8101851361071c575f5ffd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c657665
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788",
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44",
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"28": {
"address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
"code": "0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f5ffd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f5f375f5f365f845af43d5f5f3e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f5f856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f5f85851115610676575f5ffd5b83861115610682575f5ffd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f5ffd5b919050565b5f602082840312156106ba575f5ffd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e8575f5ffd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f5ffd5b8301601f8101851361071c575f5ffd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c657665
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x00000000000000000000000067d269191c92caf3cd7723f116c85e6e9bf55933",
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788"
}
},
"39": {
"address": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44",
"code": "0x608060405234801561000f575f5ffd5b50600436106102b1575f3560e01c80636d70f7ae1161017b578063bb45fef2116100e4578063e4cc3f901161009e578063f698da2511610079578063f698da25146107ce578063fabc1cbc146107d6578063fd8aa88d146107e9578063fe4b84df146107fc575f5ffd5b8063e4cc3f9014610788578063eea9064b1461079b578063f0e0e676146107ae575f5ffd5b8063bb45fef2146106b9578063bfae3fd2146106e6578063c448feb8146106f9578063c978f7ac1461072d578063ca8aa7c71461074e578063da8be86414610775575f5ffd5b80639104c319116101355780639104c319146106175780639435bb431461063257806399f5371b14610645578063a178848414610665578063a33a343314610684578063b7f06ebe14610697575f5ffd5b80636d70f7ae1461057a5780636e1744481461058d578063778e55f3146105a057806378296ec5146105ca578063886f1195146105dd5780639004134714610604575f5ffd5b806354b7c96c1161021d5780635c975abb116101d75780635c975abb146104d45780635d975e88146104dc5780635dd68579146104fd57806360a0d1ce1461051e57806365da12641461053157806366d5ba9314610559575f5ffd5b806354b7c96c1461045b57806354fd4d501461046e578063595c6a6714610483578063597b36da1461048b5780635ac86ab71461049e5780635ae679a7146104c1575f5ffd5b806339b70e381161026e57806339b70e381461036a5780633c651cf2146103a95780633cdeb5e0146103bc5780633e28391d146103ea5780634657e26a1461040d5780634665bcda14610434575f5ffd5b806304a4f979146102b55780630b9f487a146102ef5780630dd8dd0214610302578063136439dd1461032257806325df922e146103375780632aa6d88814610357575b5f5ffd5b6102dc7f14bde674c9f64b2ad00eaaee4a8bed1fabef35c7507e3c5b9cfc9436909a2dad81565b6040519081526020015b60405180910390f35b6102dc6102fd366004614a7f565b61080f565b610315610310366004614b16565b610897565b6040516102e69190614b54565b610335610330366004614b8b565b610b09565b005b61034a610345366004614d20565b610b43565b6040516102e69190614dce565b610335610365366004614e30565b610ca3565b6103917f0000000000000000000000009a676e781a523b5d0c0e43731313a708cb60750881565b6040516001600160a01b0390911681526020016102e6565b6103356103b7366004614e8e565b610df7565b6103916103ca366004614ed1565b6001600160a01b039081165f908152609960205260409020600101541690565b6103fd6103f8366004614ed1565b610f4a565b60405190151581526020016102e6565b6103917f0000000000000000000000003aa5ebb10dc797cac828524e59a333d0a371443c81565b6103917f000000000000000000000000959922be3caee4b8cd9a407cc3ac1c251c2007b181565b610335610469366004614eec565b610f69565b610476610fd7565b6040516102e69190614f51565b610335611007565b6102dc61049936600461501f565b61101b565b6103fd6104ac366004615050565b606654600160ff9092169190911b9081161490565b6102dc6104cf366004615084565b61104a565b6066546102dc565b6104ef6104ea366004614b8b565b6111bc565b6040516102e69291906151b9565b61051061050b366004614ed1565b6111d9565b6040516102e692919061522b565b61033561052c366004615298565b611303565b61039161053f366004614ed1565b609a6020525f90815260409020546001600160a01b031681565b61056c610567366004614ed1565b6114ae565b6040516102e69291906152d7565b6103fd610588366004614ed1565b6117ae565b6102dc61059b366004614eec565b6117e6565b6102dc6105ae366004614eec565b609860209081525f928352604080842090915290825290205481565b6103356105d83660046152e9565b611890565b6103917f000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e81565b61034a610612366004615339565b611926565b61039173beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b610335610640366004615385565b6119fc565b610658610653366004614b8b565b611ab7565b6040516102e69190615421565b6102dc610673366004614ed1565b609f6020525f908152604090205481565b610315610692366004615433565b611bd3565b6103fd6106a5366004614b8b565b609e6020525f908152604090205460ff1681565b6103fd6106c736600461551a565b609c60209081525f928352604080842090915290825290205460ff1681565b6102dc6106f4366004614eec565b611beb565b60405163ffffffff7f00000000000000000000000000000000000000000000000000000000000000321681526020016102e6565b61074061073b366004615339565b611c27565b6040516102e6929190615544565b6103917f00000000000000000000000068b1d87f95878fe05b998f19b66f4baba5de1aed81565b610315610783366004614ed1565b611eb4565b610335610796366004615563565b611fdd565b6103356107a9366004615433565b612015565b6107c16107bc3660046155e1565b612080565b6040516102e6919061568e565b6102dc612125565b6103356107e4366004614b8b565b6121de565b6103156107f7366004614ed1565b
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"18": {
"address": "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf",
"code": "0x608060405234801561000f575f5ffd5b50600436106100f0575f3560e01c806366ae69a011610093578063a77cf3d211610063578063a77cf3d214610238578063ad209a9b1461024b578063bb51f1eb14610272578063df0dd0d514610285575f5ffd5b806366ae69a0146101b05780636f55bd32146101db5780638ab81d1314610202578063a401662b14610215575f5ffd5b806341c9634e116100ce57806341c9634e1461013e578063591d99ee146101545780635da57fe91461017b578063623b223d1461019b575f5ffd5b80630a7c8faa146100f45780632cdea7171461011e5780633666751314610136575b5f5ffd5b610100610dad60f31b81565b6040516001600160f01b031990911681526020015b60405180910390f35b61012661030f565b60405161011594939291906124a2565b610126610390565b6101465f5481565b604051908152602001610115565b6101467f000000000000000000000000000000000000000000000000000000000000000481565b61018e610189366004612572565b61040f565b60405161011591906125b9565b6101ae6101a9366004612621565b610447565b005b6001546101c3906001600160401b031681565b6040516001600160401b039091168152602001610115565b6101467f000000000000000000000000000000000000000000000000000000000000000281565b61018e610210366004612702565b6107d9565b610228610223366004612749565b6108b0565b6040519015158152602001610115565b6101ae610246366004612797565b6108bf565b6101467f000000000000000000000000000000000000000000000000000000000000001881565b6101ae6102803660046127ae565b610a37565b6102d3610293366004612797565b600a6020525f90815260409020805460018201546002909201546001600160401b0382169263ffffffff600160401b8404811693600160601b9004169185565b604080516001600160401b0396909616865263ffffffff948516602087015292909316918401919091526060830152608082015260a001610115565b6002805460035460408051600480546060602082028401810185529383018181526001600160801b0380881698600160801b9098041696948492849184018282801561037857602002820191905f5260205f20905b815481526020019060010190808311610364575b50505050508152602001600182015481525050905084565b6006805460075460408051600880546060602082028401810185529383018181526001600160801b0380881698600160801b9098041696948492849184018282801561037857602002820191905f5260205f20908154815260200190600101908083116103645750505050508152602001600182015481525050905084565b60608282101561043257604051635c85a0e760e01b815260040160405180910390fd5b61043d848484610ea1565b90505b9392505050565b5f6104518a610f2b565b8051906020012090505f61046e33835f9182526020526040902090565b905061047c818c8c8c61101d565b5f5f90505f6002905060065f015f9054906101000a90046001600160801b03166001600160801b03168d60200160208101906104b89190612843565b6001600160401b0316036104d2575060019050600661052c565b60025f015f9054906101000a90046001600160801b03166001600160801b03168d60200160208101906105059190612843565b6001600160401b03161461052c57604051636033c4fd60e11b815260040160405180910390fd5b61053b84848e8e858f8f61110c565b5f6105458e6112c2565b905082156106d657600654610564906001600160801b0316600161287d565b6001600160801b031661057d60808b0160608c01612843565b6001600160401b0316146105a3576040516263964160e91b815260040160405180910390fd5b5f6105c0826105b18c6113f4565b805190602001208b8b8b6114a8565b9050806105e05760405163128597bb60e01b815260040160405180910390fd5b60068054600160801b8082046001600160801b0390811690910291161760029081556007546003556008805460049061061c908290849061240d565b5060019182015491015550610639905060808b0160608c01612843565b600680546001600160801b0319166001600160401b039290921691909117905561066960a08b0160808c0161289c565b600680546001600160801b031663ffffffff92909216600160801b0291909117905560a08a0180356007556106b0906106a59060808d0161289c565b63ffffffff16611517565b805180516008916106c691839160200190612455565b5060208201518160010155905050505b5f8190556106e760208f018f61289c565b63ffffffff1660015f6101000a8154816001600160401b0302191690836001600160401b03160217905550600a5f8581526020019081526020015f205f5f82015f6101000a8154906001600160401b0302191690555f820160086101000a81549063ffffffff02191690555f8201600c6101000a81549063ffffffff0219169055600182015f9055600282015f905550507fd95fe1258d152dc91c81b09380498adc76ed36a6079bcb2ed31eff622ae2d0f1818f5f0160208101906107ac919061289c565b6040805192835263ffffffff90911660208301520160405180910390a15050505050505050505050505050565b60605f600a5f6107f233885f9182526020526040902090565b8152602001
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000009": "0x0000000000000000000000000000000000000000000000000000000000000002",
"0x0000000000000000000000000000000000000000000000000000000000000008": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000007": "0x697ea2a8fe5b03468548a7a413424a6292ab44a82a6f5cc594c3fa7dda7ce402",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x697ea2a8fe5b03468548a7a413424a6292ab44a82a6f5cc594c3fa7dda7ce402",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000200000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000000000000000000000000000000000000000000000002",
"0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000200000000000000000000000000000001"
}
},
"45": {
"address": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
"code": "0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c298557814602a575b5f5ffd5b5f60405190815260200160405180910390f3fea26469706673582212204906941268839d569ecaf7e18f112ade90c540d0de5142ca9f7725e57df91e0964736f6c634300081c00330000000000000000",
"storage": {}
},
"21": {
"address": "0x0000F90827F1C53a10cb7A02335B175320002935",
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000037": "0x7dba6cfd190cd676ceab572c0ea8a2de9f397df61f588974668e90e365110250",
"0x0000000000000000000000000000000000000000000000000000000000000034": "0x8c4beb67b351b6f576899b2961e2e3f654a8701446181d5bb0c02bf691aac216",
"0x000000000000000000000000000000000000000000000000000000000000003a": "0x3d3679da9629b4cbcf3faf9cd7ae517797ec91b7984eff0a4e3e2a5feec1a077",
"0x0000000000000000000000000000000000000000000000000000000000000030": "0xd98073d4f2271bc16437511a4d4f43553358cb4faeabeaa326aa9e7fd2a343a8",
"0x000000000000000000000000000000000000000000000000000000000000004a": "0x50af6778675a6e30db0584111c11dccc9946048e4ef88a6794a138478fc0087d",
"0x0000000000000000000000000000000000000000000000000000000000000024": "0xdbb108e107182aa903847566da4e97dea7c12849e41d711ff3015e7a9d7e25af",
"0x000000000000000000000000000000000000000000000000000000000000001d": "0xe519dc053717c8dc8dc205a65af318cdbb0e06a8a071f994e5a6bd1a1b3c825e",
"0x0000000000000000000000000000000000000000000000000000000000000026": "0x9cdf7ab6a05c98761f73090b8f8674ed56fd9d53dc13a3e708204d8a4e87372d",
"0x000000000000000000000000000000000000000000000000000000000000002a": "0x6c82fe27742545bd9ab2f22dbbd5dcf3bcaf06da76a88b567b4612b80c341684",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0xc2c67fb618e169cec3b5ecceb5de747ee01f36a775797dd92504163f1fa2eb1a",
"0x0000000000000000000000000000000000000000000000000000000000000012": "0x7a21b4fb1f04fc9ee8ae2b9585f8c5248ee7adb73cad020920b34d72dcf86aa9",
"0x0000000000000000000000000000000000000000000000000000000000000043": "0xdb64fa0b93af4865852cb32ada05816c70990f993d9565df3b806e15af7f1774",
"0x0000000000000000000000000000000000000000000000000000000000000046": "0x4944a97eb3f2cef53621ac688fff89485c821677a6a000cb4c587c7a7cd80a30",
"0x0000000000000000000000000000000000000000000000000000000000000020": "0xb2835abdfda964c75cb55670e70c963f945bd4ffe74453f8053d17108cc477fd",
"0x0000000000000000000000000000000000000000000000000000000000000023": "0xa090d2b60842f14ec13240bd07bf4be2f6d3faac6c0e82d1b6e9e79c91f71ca7",
"0x0000000000000000000000000000000000000000000000000000000000000048": "0x09cdc091ee3d28c27b1d81e24e200a415304990490f712280e7a9f5b7e528077",
"0x000000000000000000000000000000000000000000000000000000000000000a": "0x0c9f4bccf18f5fbe86e1891c3ea5a92f15dc928a7376dfce0aa3ed642d68af1c",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x94d0bab2834f8ad853c6d0fd6bca9a5019ff287f8607d9573cfbbaa44fa9132e",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x508921c105d59853aa52ef7fe87433b1847a5d97d61535e3189abe8aaad908b2",
"0x0000000000000000000000000000000000000000000000000000000000000028": "0x0327ac71308d01e45657fd4d8b343a2d6aeef00f80395f6511416274997cfcfb",
"0x0000000000000000000000000000000000000000000000000000000000000031": "0xd10fc0bcc990f04c1a06a2b1e72bd617a020aa0d4dc89f5f98c21233a492d27a",
"0x0000000000000000000000000000000000000000000000000000000000000004": "0x3cb864613b04eae08a873b64b3a67360f98c41ca76abf9d06bbab1e83c59a5f1",
"0x0000000000000000000000000000000000000000000000000000000000000017": "0x3e7878505d2f5b0548009687f85e3e0491e8a193703cbffd103e9060de532e0d",
"0x0000000000000000000000000000000000000000000000000000000000000018": "0x615a70fc83ca07e7b6fb4a9da05b734479fff08ddef45bf3dd0bbeae10410b36",
"0x0000000000000000000000000000000000000000000000000000000000000025": "0x29030d8519c14cc30a1d3613e13a26354214da5cb8e2c750c95d2884cb17d86d",
"0x0000000000000000000000000000000000000000000000000000000000000038": "0x15cef137d4c827121f1fbca673176fc376cad8582b90e695642b3fb913ae5e5f",
"0x000000000000000000000000000000000000000000000000000000000000000e": "0xd9952f05760fda1a4ca998fecf94b6a11c7a1e9ad5c10636e52b58f238948638",
"0x0000000000000000000000000000000000000000000000000000000000000006": "0x1a4d3e4c00a8711d4b79df383d348de72fafd510cde2998cca273bb5e945634e",
"0x0000000000000000000000000000000000000000000000000000000000000021": "0xfe1a914f738a66729c97f9a987f003733572a7032aacc5237ea73e5d1791be15",
"0x0000000000000000000000000000000000000000000000000000000000000040": "0x872e3b28751def5dd02c04d2e37334aecd63ccdf73b529c5002608f179d81726",
"0x0000000000000000000000000000000000000000000000000000000000000014": "0x1bebfec7364d7b14f77a125c75e06f6cb54998cc2344bcb5838e8f4ac34a799d",
"0x0000000000000000000000000000000000000000000000000000000000000041": "0x282828ce280e5c594f5009f451d6b953dd91b234e9a371f2f5dec7d00661baf7",
"0x000000000000000000000000000000000000000000000000000000000000000d": "0x1c1b8f0803eeb1e1c9447df7b8c9e88817463c785e5462357fcebc7f61cc1a0c",
"0x000000000000000000000000000000000000000000000000000000000000001f": "0xdf915f928c9abcae4533730be221820ff4fe7f6d15364411eefc3b4cf5938d3c",
"0x0000000000000000000000000000000000000000000000000000000000000036": "0x5237502c06660666a59cb0f6f943122ef30db0b39702d0e9b18cf75a67df705e",
"0x0000000000000000000000000000000000000000000000000000000000000029": "0x62d466ab11e99482d3b48cb05959ca8068f8894abd45dce90b13c6a95105669f",
"0x000000000000000000000000000000000000000000000000000000000000002b": "0xcbb14f647e27741b02ef0b47727affdd37883853eaf0a80960ed9fe2417d0155",
"0x0000000000000000000000000000000000000000000000000000000000000011": "0xc206586970ef9cceb3ae4113133b749725d48af653dc3e32e9af6d51f1eb2a8c",
"0x000000000000000000000000000000000000000000000000000000000000001c": "0x247e36fad5af4cccc7207545c64b2298a49af78c7c5a01df85143a32b7be3f08",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x7ad4f2b98894e6ba818e2d230abc7d7b8cbf85d936245a24b2a374f6a81b286f",
"0x000000000000000000000000000000000000000000000000000000000000003d": "0x3da9512589d1256bc831a5beb801a7cc63c26b3870aaf0c191e488644d00eaf6",
"0x0000000000000000000000000000000000000000000000000000000000000005": "0xe6bf887ab883f3817f530198a3738495cf7d121a8f2f62ee38c80fc783963b4d",
"0x0000000000000000000000000000000000000000000000000000000000000015": "0xd4a299c088a928b0d78615b35e8b8d464fe3cd0924e1725a2549512915413888",
"0x0000000000000000000000000000000000000000000000000000000000000022": "0xee5607c31047cd8a768e51e8ed47f2d4e00bbec79087a19fcce4122774bad68a",
"0x000000000000000000000000000000000000000000000000000000000000003c": "0x34e05358e6d64f940d16692aae278df9fb79cd5b31b7ca6ed535c97b61c3f169",
"0x0000000000000000000000000000000000000000000000000000000000000016": "0x459aa0106e3ca4cba1215c6e8683b5a567bdf5c99ec02e4452044c8a115e7a00",
"0x000000000000000000000000000000000000000000000000000000000000002f": "0x07e19ac1142916f7b63663fdeb9401d54ab18eb8e7fb3204149b2a20a091b71d",
"0x000000000000000000000000000000000000000000000000000000000000003f": "0x36a957fcb4cfb170e2e9cfce0c40bd287ea53e70b533319b1d086008df464717",
"0x000000000000000000000000000000000000000000000000000000000000000f": "0x1259338c2e8df334b092b9881f8ea7882b3a7c475d1979af0249c8c69ea28114",
"0x000000000000000000000000000000000000000000000000000000000000000c": "0x177dfa3cdf65903c0235fb12887725bcc4148ed51225be84db90e30ff36d7aaf",
"0x000000000000000000000000000000000000000000000000000000000000000b": "0x8e1841b9f4c6c6ea52f11ec7783a38eab6993840412f1e63773c3b168c8ee2a4",
"0x0000000000000000000000000000000000000000000000000000000000000044": "0x41c10fdeffe6c9d73e9a769d02b02e2687efd05b4ed27ee30379437589fc7739",
"0x000000000000000000000000000000000000000000000000000000000000002e": "0xe7365b9dcb1a93128cc1671627b2b8fb038bf002a5037066a55ce27c444cf0e4",
"0x000000000000000000000000000000000000000000000000000000000000001b": "0xfcd358887d6cead17a31275c7817f4be8ec2399670152736d8afab9f29857a01",
"0x0000000000000000000000000000000000000000000000000000000000000042": "0x6a8b913bac58f095f9b55cdb2ae9e635686313b60c1a43b187aae0a2d07e0aaa",
"0x0000000000000000000000000000000000000000000000000000000000000008": "0x890b339bb81e6d15de4e50b8abb87abd937eee6d83913a577c5e8eb73a185254",
"0x0000000000000000000000000000000000000000000000000000000000000045": "0xc36a0aa304696f05f336fbc39393d93a6d0cc1cd0431ec9a3b09b2ace2fe4e1d",
"0x0000000000000000000000000000000000000000000000000000000000000027": "0xa0c3168f121ede472d57a4e81a1a8e73c9199affdaaa8ec83797b0ca9e65a84a",
"0x0000000000000000000000000000000000000000000000000000000000000019": "0x01e3a46edccdf8e4fa7ba377876c2caa4e7f20e357a7cd69802c90b0f64cd81c",
"0x000000000000000000000000000000000000000000000000000000000000003b": "0xd98147582c214dceef19d46c0658b3b05d326254c0ef38aa875594495756b8ea",
"0x0000000000000000000000000000000000000000000000000000000000000035": "0xb7b970a400b2c4c7f3322a9573369b865c272b6da5348cb0e032e434b33c06bd",
"0x0000000000000000000000000000000000000000000000000000000000000010": "0x2e461dcac54d9f4f52ba077f666a5ddd431341514db0e9f369dbf5a9ae700546",
"0x000000000000000000000000000000000000000000000000000000000000003e": "0x57530920cd762202e8ee8e2016744727f97449998791effbe34ca75314899fb7",
"0x0000000000000000000000000000000000000000000000000000000000000007": "0xa64333f38cf6f05bf76e867e663294e79156582d738eff8997eaa7b092edead1",
"0x0000000000000000000000000000000000000000000000000000000000000013": "0xc08e55cd55f98b08478d00b19d0fdb5aa012f2ef0bb37db6bace5143a65a4b2e",
"0x0000000000000000000000000000000000000000000000000000000000000033": "0xbf2bc3d6b0df3ed1f839eb7050814edbbc865f4ff3543dda811bf71ea59e41ec",
"0x0000000000000000000000000000000000000000000000000000000000000039": "0xf306e8539937696cdc87c607ed45127cba87fb213a4b0c620506d16908a03e0d",
"0x000000000000000000000000000000000000000000000000000000000000001a": "0x30bc181b20c968c2ea5c4b97b241f0035b237c019218eb8ca93486a439c483ba",
"0x0000000000000000000000000000000000000000000000000000000000000009": "0xa94e1c9553391106e061daab33fcb441afa04f603106d943475777270ccfa64e",
"0x000000000000000000000000000000000000000000000000000000000000001e": "0xa0fc11bb768bcb3b45c699aee78a664e69b3857627b3b1a342ea80f14efb57ab",
"0x000000000000000000000000000000000000000000000000000000000000002d": "0xa7aaf5a2b8a2feab05e51df7035f2eb5d8e32ec6f16c0086a35854e25df98670",
"0x0000000000000000000000000000000000000000000000000000000000000047": "0xd20fca41a076819db29bd1ab62bb5489070d0656896cca9069ba181962219a87",
"0x0000000000000000000000000000000000000000000000000000000000000049": "0x1df27bb7e07a1aad2084ccb75255169ca7d1a3e6737d0308412cb860f538192b",
"0x0000000000000000000000000000000000000000000000000000000000000032": "0x672b80852a0a8f09cc2c2d3c9f40c1c48b88b897fff3f63bd2adc934502a92cf",
"0x000000000000000000000000000000000000000000000000000000000000002c": "0xcc56a05b1bc445067c57c06caea96b020b02d035a9702dbfcd6a0a078be87e92"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"37": {
"address": "0xac06641381166cf085281c45292147f833C622d7",
"code": "0x608060405260043610610036575f3560e01c8063338c5371146100415780639bb66b2814610091578063e905182a146100be575f5ffd5b3661003d57005b5f5ffd5b34801561004c575f5ffd5b506100747f0000000000000000000000009d4454b023096f34b160d6b654540c56a1f8168881565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561009c575f5ffd5b506100b06100ab3660046101ae565b6100ff565b604051610088929190610239565b3480156100c9575f5ffd5b506100f17f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610088565b5f6060336001600160a01b037f0000000000000000000000009d4454b023096f34b160d6b654540c56a1f81688161461014a576040516282b42960e81b815260040160405180910390fd5b846001600160a01b03168484604051610164929190610277565b5f60405180830381855af49150503d805f811461019c576040519150601f19603f3d011682016040523d82523d5f602084013e6101a1565b606091505b5091509150935093915050565b5f5f5f604084860312156101c0575f5ffd5b83356001600160a01b03811681146101d6575f5ffd5b9250602084013567ffffffffffffffff8111156101f1575f5ffd5b8401601f81018613610201575f5ffd5b803567ffffffffffffffff811115610217575f5ffd5b866020828401011115610228575f5ffd5b939660209190910195509293505050565b8215158152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f8301168401019150509392505050565b818382375f910190815291905056fea26469706673582212208fe760f358faedf4a90fd4b23c39c8397def11c5b035ea1406af976ecc426bbf64736f6c634300081c00330000000000",
"storage": {}
},
"47": {
"address": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e",
"code": "0x608060405234801561000f575f5ffd5b506004361061004a575f3560e01c806346fbf68e1461004e5780638568520614610085578063ce5484281461009a578063eab66d7a146100ad575b5f5ffd5b61007061005c36600461027a565b5f6020819052908152604090205460ff1681565b60405190151581526020015b60405180910390f35b61009861009336600461029a565b6100d8565b005b6100986100a836600461027a565b610111565b6001546100c0906001600160a01b031681565b6040516001600160a01b03909116815260200161007c565b6001546001600160a01b031633146101035760405163794821ff60e01b815260040160405180910390fd5b61010d8282610148565b5050565b6001546001600160a01b0316331461013c5760405163794821ff60e01b815260040160405180910390fd5b610145816101cf565b50565b6001600160a01b03821661016f576040516339b190bb60e11b815260040160405180910390fd5b6001600160a01b0382165f8181526020818152604091829020805460ff19168515159081179091558251938452908301527f65d3a1fd4c13f05cba164f80d03ce90fb4b5e21946bfc3ab7dbd434c2d0b9152910160405180910390a15050565b6001600160a01b0381166101f6576040516339b190bb60e11b815260040160405180910390fd5b600154604080516001600160a01b03928316815291831660208301527f06b4167a2528887a1e97a366eefe8549bfbf1ea3e6ac81cb2564a934d20e8892910160405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b80356001600160a01b0381168114610275575f5ffd5b919050565b5f6020828403121561028a575f5ffd5b6102938261025f565b9392505050565b5f5f604083850312156102ab575f5ffd5b6102b48361025f565b9150602083013580151581146102c8575f5ffd5b80915050925092905056fea2646970667358221220d968f6e7b0fa23955f1f9580db081bbf816d7e99d0b3ab6d1bf5c644ea927f8d64736f6c634300081c003300",
"storage": {
"0x723077b8a1b173adc35e5f0e7e3662fd1208212cb629f9c128551ea7168da722": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc",
"0x14e04a66bf74771820a7400ff6cf065175b3d7eb25805a5bd1633b161af5d101": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
},
"6": {
"address": "0x0165878A594ca255338adfa4d48449f69242Eb8F",
"code": "0x730165878a594ca255338adfa4d48449f69242eb8f3014608060405260043610610034575f3560e01c8063439fab9114610038575b5f5ffd5b818015610043575f5ffd5b50610057610052366004610683565b610059565b005b5f6100827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b0316036100a8576040516282b42960e81b815260040160405180910390fd5b7e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ab5f6100d584840185610760565b8051835491925090839060ff1916600183818111156100f6576100f6610802565b02179055505f7f03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c1113145f1b60405161012b90610676565b908152602001604051809103905ff08015801561014a573d5f5f3e3d5ffd5b507f03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c1113145f908152600285016020908152604080832080546001600160a01b0319166001600160a01b0386169081179091558151608081018352848152808401859052808301859052606081019190915260018085528089019093529220825181549495509293909291839160ff19169083818111156101ea576101ea610802565b02179055506020828101518254604080860151610100600160881b031990921661010067ffffffffffffffff9485160267ffffffffffffffff60481b191617600160481b9390921692909202178355606093840151600193840180546001600160a01b0319166001600160a01b0392831617905581516080810183525f808252818501819052818401819052918716958101959095526002815287840190925290208251815491929091839160ff199091169083818111156102ae576102ae610802565b021790555060208201518154604080850151610100600160881b031990921661010067ffffffffffffffff9485160267ffffffffffffffff60481b191617600160481b9390921692909202178255606090920151600190910180546001600160a01b0319166001600160a01b03909216919091179055515f907f81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b799061035290610676565b908152602001604051809103905ff080158015610371573d5f5f3e3d5ffd5b507f81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b795f908152600286016020908152604080832080546001600160a01b0319166001600160a01b038616908117909155815160808101835284815280840185905280830185905260608101919091528151637061726160e01b81850152607d60e31b6024820152825180820360080181526028909101835280519084012084526001808a019093529220825181549495509293909291839160ff191690838181111561043f5761043f610802565b021790555060208201518154604084015167ffffffffffffffff908116600160481b0267ffffffffffffffff60481b19919093166101000216610100600160881b031990911617178155606090910151600190910180546001600160a01b039092166001600160a01b03199092169190911790555f6104db7f59ef95eb9983b1a4650e1bc666384b8507689fc8aca3edd429d7e07c0ca9d2f690565b60408501518155602080860151600180840180546fffffffffffffffffffffffffffffffff19166001600160801b0393841617905560c08801516002909401939093557f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c22f80546001600160a01b03969096166001600160c01b031990961695909517607d60a31b1790945560a08601517f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c23155606086015160808701518516600160801b02908516177f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c2305560e08601517f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c23380546101009889015190961690970270ffffffffffffffffffffffffffffffffff1990951660ff9091161793909317909455505f80527f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c22e9052507f8510b5c501cdfc97210e26067e7b0bee5b5cd43d52d902454bc5e2b62167df1d805460ff19169091179055505050565b61032e8061081783390190565b5f5f60208385031215610694575f5ffd5b823567ffffffffffffffff8111156106aa575f5ffd5b8301601f810185136106ba575f5ffd5b803567ffffffffffffffff8111156106d0575f5ffd5b8560208284010111156106e1575f5ffd5b6020919091019590945092505050565b604051610120810167ffffffffffffffff8111828210171561072157634e487b7160e01b5f52604160045260245ffd5b60405290565b803560028110610735575f5ffd5b919050565b80356001600160801b0381168114610735575f5ffd5b803560ff81168114610735575f5ffd5b5f610120828403128015610772575f5ffd5b5061077b6106f1565b61078483610727565b81526107926020840161073a565b6020820152604083810135908201526107ad6060840161073a565b60608201526107be6080840161073a565b608082015260a0838101359082015260c080840135908201526107e360e08401610750565b60e08201526107f5610100840161073a565b6101
"storage": {}
},
"20": {
"address": "0x00000000219ab540356cBB839Cbe05303d7705Fa",
"code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb",
"0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784",
"0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c",
"0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0",
"0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4",
"0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4",
"0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c",
"0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71",
"0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167",
"0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30",
"0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193",
"0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f",
"0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f",
"0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e",
"0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa",
"0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c",
"0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c",
"0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1",
"0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab",
"0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636",
"0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7",
"0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544",
"0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b",
"0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c",
"0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b",
"0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb",
"0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1",
"0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765",
"0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7",
"0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220",
"0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1"
}
},
"44": {
"address": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf",
"code": "0x60806040526004361061021d575f3560e01c8063805ce31d1161011e578063b39053c5116100a8578063d58a8be41161006d578063d58a8be4146106cb578063df4ed829146106de578063f2e500b2146106fd578063f906d30914610710578063fe61cc491461072f575f5ffd5b8063b39053c5146105f9578063be8d42c014610618578063c536218f1461066e578063c66414c51461068d578063c9bd1e5b146106ac575f5ffd5b806390ffc4f9116100ee57806390ffc4f914610561578063928bc49d14610594578063988062ea146105b357806398ea5fca146105d2578063b0a23d44146105da575f5ffd5b8063805ce31d146104d55780638450a97c146104f7578063860929ee146105165780638ce2e33914610542575f5ffd5b80633ae65d7e116101aa57806346cd27511161016f57806346cd27511461045157806352054834146104705780635c60da1b146104835780635e6dae26146104975780636a64d9fb146104b6575f5ffd5b80633ae65d7e1461038a5780633f8bb4d9146103a9578063423e69b6146103c857806342e3ccfa14610413578063439fab9114610432575f5ffd5b806327c1d325116101f057806327c1d325146102cb5780632a6c3229146102ea5780632dd677b1146103295780632fb8ac581461034857806338004f6914610367575f5ffd5b80630705f4651461022157806309824a80146102565780630b6176461461026b57806326aa101f1461029c575b5f5ffd5b34801561022c575f5ffd5b5061024061023b3660046129ee565b61074e565b60405161024d9190612a19565b60405180910390f35b610269610264366004612a47565b6107c8565b005b348015610276575f5ffd5b5061027f610843565b604080519283526001600160801b0390911660208301520161024d565b3480156102a7575f5ffd5b506102bb6102b6366004612a47565b6108b7565b604051901515815260200161024d565b3480156102d6575f5ffd5b506102696102e5366004612aa6565b610933565b3480156102f5575f5ffd5b506103096103043660046129ee565b6109bb565b604080516001600160401b0393841681529290911660208301520161024d565b348015610334575f5ffd5b50610269610343366004612aa6565b610a39565b348015610353575f5ffd5b50610269610362366004612ae4565b610a91565b348015610372575f5ffd5b505f516020613ae35f395f51905f525460ff16610240565b348015610395575f5ffd5b506102696103a4366004612aa6565b610b3e565b3480156103b4575f5ffd5b506102696103c3366004612aa6565b610bb8565b3480156103d3575f5ffd5b506103fb7f0000000000000000000000000e801d84fa97b50751dbf25036d067dcf18858bf81565b6040516001600160a01b03909116815260200161024d565b34801561041e575f5ffd5b5061026961042d366004612aa6565b610c10565b34801561043d575f5ffd5b5061026961044c366004612aa6565b610c68565b34801561045c575f5ffd5b5061026961046b366004612aa6565b610ca1565b61026961047e366004612b50565b610d1b565b34801561048e575f5ffd5b506103fb610da1565b3480156104a2575f5ffd5b506103fb6104b13660046129ee565b610dcf565b3480156104c1575f5ffd5b506102696104d0366004612ae4565b610dd9565b3480156104e0575f5ffd5b506104e9610e33565b60405190815260200161024d565b348015610502575f5ffd5b50610269610511366004612aa6565b610e9f565b348015610521575f5ffd5b5061052a610f19565b6040516001600160401b03909116815260200161024d565b34801561054d575f5ffd5b5061026961055c366004612c2f565b610f85565b34801561056c575f5ffd5b506103fb7f00000000000000000000000099bba657f2bbc93c02d617f8ba121cb8fc104acf81565b34801561059f575f5ffd5b506104e96105ae366004612ccb565b6110fd565b3480156105be575f5ffd5b506102696105cd366004612aa6565b61119c565b6102696111f4565b3480156105e5575f5ffd5b506102696105f4366004612aa6565b61122e565b348015610604575f5ffd5b506102696106133660046129ee565b611286565b348015610623575f5ffd5b506104e9610632366004612a47565b6001600160a01b03165f9081527f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c22e602052604090206001015490565b348015610679575f5ffd5b50610269610688366004612aa6565b6112e8565b348015610698575f5ffd5b506102bb6106a7366004612d32565b611340565b3480156106b7575f5ffd5b506102696106c6366004612aa6565b611389565b6102696106d9366004612d5b565b6113e1565b3480156106e9575f5ffd5b506102696106f8366004612db4565b611438565b61026961070b366004612e3f565b61191f565b34801561071b575f5ffd5b5061026961072a366004612aa6565b6119ac565b34801561073a575f5ffd5b506103fb6107493660046129ee565b611a04565b604051630705f46560e01b8152600481018290525f9073e7f1725e7734ce288f8367e1bb143e90bb3f051290630705f46590602401602060405180830381865af415801561079e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107c29190612f00565b92915050565b5f5c156107d3575f5ffd5b60015f5d6040516213049560e71b81526001600160a01b038216600482015273e7f1725e
"storage": {}
},
"11": {
"address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
"code": "0x739fe46736679d2d9a65f0992f2272de9f3c7fa6e03014608060405260043610610055575f3560e01c80634a283cd91461005957806376b1d08f1461007a578063fd10ebe514610099578063fe65a388146100d2575b5f5ffd5b818015610064575f5ffd5b50610078610073366004610aed565b6100f1565b005b610082600881565b60405160ff90911681526020015b60405180910390f35b7e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96b0546040516001600160401b039091168152602001610090565b8180156100dd575f5ffd5b506100786100ec366004610b67565b610202565b5f8181527e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ad60205260409020547e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ab906001600160a01b0316806101e4578260405161015990610ae0565b908152602001604051809103905ff080158015610178573d5f5f3e3d5ffd5b505f84815260028401602090815260409182902080546001600160a01b0319166001600160a01b0385169081179091558251878152918201529192507f7c96960a1ebd8cc753b10836ea25bd7c9c4f8cd43590db1e8b3648cb0ec4cc89910160405180910390a1505050565b604051630d82532d60e21b815260040160405180910390fd5b505050565b61028d336102448a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061029792505050565b61024e888a610c98565b87878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508992508891506102bf9050565b5050505050505050565b6040805180820182525f80825260606020928301528251808401909352825281019190915290565b6102c761056c565b6001600160801b033411156102ef576040516330e972ad60e01b815260040160405180910390fd5b6102f98183610d8e565b6001600160801b03163410156103225760405163044044a560e21b815260040160405180910390fd5b5f61034c7f81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b796105c5565b90506103616001600160a01b0382163461061d565b8451600810156103845760405163df8153c760e01b815260040160405180910390fd5b5f85516001600160401b0381111561039e5761039e610c54565b6040519080825280602002602001820160405280156103e357816020015b604080518082019091525f8152606060208201528152602001906001900390816103bc5790505b5090505f5b86518110156104385761041387828151811061040657610406610dad565b6020026020010151610646565b82828151811061042557610425610dad565b60209081029190910101526001016103e8565b507e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96b0547e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ab9061048f906001600160401b03166001610dc1565b816005015f6101000a8154816001600160401b0302191690836001600160401b031602179055505f6040518060e001604052808b6001600160a01b031681526020018481526020018a81526020018881526020018688346104f09190610de0565b6104fa9190610de0565b6001600160801b03908116825288811660208301528716604091820152600584015490519192507f550e2067494b1736ea5573f2d19cdc0ac95b410fff161bf16f11c6229655ec9c91610558916001600160401b0316908490610e56565b60405180910390a150505050505050505050565b7e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ab80545f9060ff1660018111156105a4576105a4610f6b565b146105c257604051633ac4266d60e11b815260040160405180910390fd5b50565b5f8181527e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ad60205260409020546001600160a01b0316806106185760405163d3227c9b60e01b815260040160405180910390fd5b919050565b5f5f5f5f5f85875af19050806101fd57604051633d2cec6f60e21b815260040160405180910390fd5b604080518082019091525f815260606020820152602082015160ff165f819003610698575f5f848060200190518101906106809190610f7f565b925092505061068f82826106b1565b95945050505050565b604051636448d6e960e11b815260040160405180910390fd5b604080518082019091525f8152606060208201525f7f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c22e6001600160a01b0385165f90815260208290526040902080549192509060ff166107245760405163259ba1ad60e01b815260040160405180910390fd5b5f846001600160801b03161161074d5760405163162908e360e11b815260040160405180910390fd5b6001810154610783576001820154610770906001600160a01b0316863387610821565b61077a858561089d565b9250505061081b565b61078c81610919565b1561080257604051632770a7eb60e21b81523360048201526001600160801b03851660248201526001600160a01b03861690639dc29fac906044015f604051808303815f87803b1580156107de575f5ffd5b505af11580156107f0573d5f5f3e3d5ffd5b5050505061077a
"storage": {}
},
"30": {
"address": "0x809d550fca64d94Bd9F66E60752A544199cfAC3D",
"code": "0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f5ffd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f5f375f5f365f845af43d5f5f3e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f5f856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f5f85851115610676575f5ffd5b83861115610682575f5ffd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f5ffd5b919050565b5f602082840312156106ba575f5ffd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e8575f5ffd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f5ffd5b8301601f8101851361071c575f5ffd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c657665
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000067": "0x0000000000000000000000009d4454b023096f34b160d6b654540c56a1f81688",
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788",
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x00000000000000000000000036c02da8a0983159322a80ffe9f24b1acff8b570",
"0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000976ea74026e726554db657fa54763abd0c3a0aa9",
"0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000014dc79964da2c08b23698b3d3cc7ca32193d9955",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
},
"23": {
"address": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
"code": "0x6080604052600436106101f1575f3560e01c8063886f119511610108578063a6a509be1161009d578063f2fde38b1161006d578063f2fde38b1461062e578063f5d4fed31461064d578063f6848d2414610662578063fabc1cbc1461069b578063fe243a17146106ba575f5ffd5b8063a6a509be1461059c578063cd6dc687146105b1578063d48e8894146105d0578063ea4d3c9b146105fb575f5ffd5b80639ba06275116100d85780639ba062751461050b578063a1ca780b1461053f578063a38406a31461055e578063a3d75e091461057d575f5ffd5b8063886f1195146104815780638da5cb5b146104b45780639104c319146104d15780639b4e4634146104f8575f5ffd5b8063595c6a67116101895780635c975abb116101595780635c975abb146103e9578063715018a614610407578063724af4231461041b57806374cdd7981461043a57806384d810621461046d575f5ffd5b8063595c6a6714610358578063595edbcb1461036c5780635a26fbf41461038b5780635ac86ab7146103aa575f5ffd5b80632eae418c116101c45780632eae418c146102c55780633fb99ca5146102e457806350ff72251461030357806354fd4d5014610337575f5ffd5b80630d1e9de1146101f5578063136439dd146102165780632704351a14610235578063292b7b2b1461027a575b5f5ffd5b348015610200575f5ffd5b5061021461020f366004611d7e565b6106d9565b005b348015610221575f5ffd5b50610214610230366004611d99565b610736565b348015610240575f5ffd5b50609f5461025c90600160a01b900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020015b60405180910390f35b348015610285575f5ffd5b506102ad7f0000000000000000000000004ed7c70f96b99c776995fb64377f0d4ab3b0e1c181565b6040516001600160a01b039091168152602001610271565b3480156102d0575f5ffd5b506102146102df366004611db0565b610770565b3480156102ef575f5ffd5b506102146102fe366004611dfe565b6109c9565b34801561030e575f5ffd5b5061032261031d366004611e48565b610a6d565b60408051928352602083019190915201610271565b348015610342575f5ffd5b5061034b610b1d565b6040516102719190611e86565b348015610363575f5ffd5b50610214610b4d565b348015610377575f5ffd5b50609f546102ad906001600160a01b031681565b348015610396575f5ffd5b506102146103a5366004611ebb565b610b61565b3480156103b5575f5ffd5b506103d96103c4366004611ee2565b606654600160ff9092169190911b9081161490565b6040519015158152602001610271565b3480156103f4575f5ffd5b506066545b604051908152602001610271565b348015610412575f5ffd5b50610214610be8565b348015610426575f5ffd5b506103f9610435366004611e48565b610bf9565b348015610445575f5ffd5b506102ad7f000000000000000000000000c7f2cf4845c6db0e1a1e91ed41bcd0fcc1b0e14181565b348015610478575f5ffd5b506102ad610d3e565b34801561048c575f5ffd5b506102ad7f000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e81565b3480156104bf575f5ffd5b506033546001600160a01b03166102ad565b3480156104dc575f5ffd5b506102ad73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b610214610506366004611f40565b610da1565b348015610516575f5ffd5b506102ad610525366004611d7e565b60986020525f90815260409020546001600160a01b031681565b34801561054a575f5ffd5b50610214610559366004611fb3565b610e52565b348015610569575f5ffd5b506102ad610578366004611d7e565b611073565b348015610588575f5ffd5b5061025c610597366004611d7e565b611144565b3480156105a7575f5ffd5b506103f960995481565b3480156105bc575f5ffd5b506102146105cb366004611fe5565b6111a4565b3480156105db575f5ffd5b506103f96105ea366004611d7e565b609b6020525f908152604090205481565b348015610606575f5ffd5b506102ad7f0000000000000000000000000dcd1bf9a1b36ce34237eeafef220932846bcd8281565b348015610639575f5ffd5b50610214610648366004611d7e565b6112c0565b348015610658575f5ffd5b506103f9609e5481565b34801561066d575f5ffd5b506103d961067c366004611d7e565b6001600160a01b039081165f9081526098602052604090205416151590565b3480156106a6575f5ffd5b506102146106b5366004611d99565b611339565b3480156106c5575f5ffd5b506103f96106d436600461200f565b6113a6565b6106e1611426565b609f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f7025c71a9fe60d709e71b377dc5f7c72c3e1d8539f8022574254e736ceca01e5906020015b60405180910390a150565b61073e611480565b60665481811681146107635760405163c61dca5d60e01b815260040160405180910390fd5b61076c82611523565b5050565b336001600160a01b037f0000000000000000000000000dcd1bf9a1b36ce34237eeafef220932846bcd8216146107b95760405163f739589b60e01b815260040160405180910390fd5b6107c1611560565b6001600160a01b03831673beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0146107fe57604051632711b74d60e11b81526004016040
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
}
},
"35": {
refactor(contracts): Harden DataHavenServiceManager with input validation and code cleanup (#395) ## Summary - Add zero address validation across all functions that accept address parameters to prevent misconfiguration - Fix race condition in `buildNewValidatorSetMessage()` that could cause reverts during validator deregistration - Refactor contract for improved readability and reduced code duplication - Update AVS metadata URL to point to the correct hosted JSON file ## Changes ### Security & Validation - Add `ZeroAddress` error and validate all address inputs in `initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`, `addValidatorToAllowlist`, `registerOperator`, and `updateSolochainAddressForValidator` - Fix race condition: filter out zero solochain addresses in `buildNewValidatorSetMessage()` to prevent reverts when a validator is mid-deregistration ### Refactoring - Replace verbose `if/revert` patterns with `require` statements for consistency - Inline single-use internal functions (`_createDataHavenOperatorSets`, `_setRewardsInitiator`) - Consolidate duplicate error types into single `ZeroAddress` error - Rename `initialise` → `initialize` to maintain consistency with the transparent upgradability pattern - Optimize validator set message encoding by removing redundant wrapper function ### Observability - Add `SolochainAddressUpdated` event for tracking validator address changes ### Cleanup - Remove unused remappings from `foundry.toml` - Fix typo in metadata description --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
2026-01-20 10:32:32 +00:00
"address": "0x9d4454B023096f34B160D6B654540c56A1F81688",
"code": "0x608060405260043610610021575f3560e01c8063439fab911461008a5761003f565b3661003f5760405163858d70bd60e01b815260040160405180910390fd5b5f6100687f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b9050365f5f375f5f365f845af43d5f5f3e808015610084573d5ff35b3d5ffd5b005b348015610095575f5ffd5b506100886100a43660046100bc565b6040516282b42960e81b815260040160405180910390fd5b5f5f602083850312156100cd575f5ffd5b823567ffffffffffffffff8111156100e3575f5ffd5b8301601f810185136100f3575f5ffd5b803567ffffffffffffffff811115610109575f5ffd5b85602082840101111561011a575f5ffd5b602091909101959094509250505056fea264697066735822122042eb79be1c5c1bf83d453ef1bcf09a68daefc0a952ec517c315a6e1a8ca586e264736f6c634300081c003300",
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x24c230e7f96dea56c14d16c737ac85f999d444fd74b5f3f00170ca4640c77b8f": "0x000000000000000000000000beaafda2e17fc95e69dc06878039d274e0d2b21a",
"0x8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c22f": "0x0000000000000000000003e8df077f5f72071df6e8b0a78071e496ba17b5ee0c",
refactor(contracts): Harden DataHavenServiceManager with input validation and code cleanup (#395) ## Summary - Add zero address validation across all functions that accept address parameters to prevent misconfiguration - Fix race condition in `buildNewValidatorSetMessage()` that could cause reverts during validator deregistration - Refactor contract for improved readability and reduced code duplication - Update AVS metadata URL to point to the correct hosted JSON file ## Changes ### Security & Validation - Add `ZeroAddress` error and validate all address inputs in `initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`, `addValidatorToAllowlist`, `registerOperator`, and `updateSolochainAddressForValidator` - Fix race condition: filter out zero solochain addresses in `buildNewValidatorSetMessage()` to prevent reverts when a validator is mid-deregistration ### Refactoring - Replace verbose `if/revert` patterns with `require` statements for consistency - Inline single-use internal functions (`_createDataHavenOperatorSets`, `_setRewardsInitiator`) - Consolidate duplicate error types into single `ZeroAddress` error - Rename `initialise` → `initialize` to maintain consistency with the transparent upgradability pattern - Optimize validator set message encoding by removing redundant wrapper function ### Observability - Add `SolochainAddressUpdated` event for tracking validator address changes ### Cleanup - Remove unused remappings from `foundry.toml` - Fix typo in metadata description --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
2026-01-20 10:32:32 +00:00
"0x626b8e6b0a06114fed7a662a5b224ce123b32b155eef2616324caf5d9adeb4fa": "0x000000000000000000000000beaafda2e17fc95e69dc06878039d274e0d2b21a",
"0x8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c233": "0x0000000000000000000000000000000000000000000000000000000000000112",
refactor(contracts): Harden DataHavenServiceManager with input validation and code cleanup (#395) ## Summary - Add zero address validation across all functions that accept address parameters to prevent misconfiguration - Fix race condition in `buildNewValidatorSetMessage()` that could cause reverts during validator deregistration - Refactor contract for improved readability and reduced code duplication - Update AVS metadata URL to point to the correct hosted JSON file ## Changes ### Security & Validation - Add `ZeroAddress` error and validate all address inputs in `initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`, `addValidatorToAllowlist`, `registerOperator`, and `updateSolochainAddressForValidator` - Fix race condition: filter out zero solochain addresses in `buildNewValidatorSetMessage()` to prevent reverts when a validator is mid-deregistration ### Refactoring - Replace verbose `if/revert` patterns with `require` statements for consistency - Inline single-use internal functions (`_createDataHavenOperatorSets`, `_setRewardsInitiator`) - Consolidate duplicate error types into single `ZeroAddress` error - Rename `initialise` → `initialize` to maintain consistency with the transparent upgradability pattern - Optimize validator set message encoding by removing redundant wrapper function ### Observability - Add `SolochainAddressUpdated` event for tracking validator address changes ### Cleanup - Remove unused remappings from `foundry.toml` - Fix typo in metadata description --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
2026-01-20 10:32:32 +00:00
"0x91839d9989408fbab863f2059ae80fee5216f58ec04fa3bffb021275bf7d4f24": "0x000000000000000000000000df077f5f72071df6e8b0a78071e496ba17b5ee0c",
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x173ec3ea915b0ecad49b752ec145e745446de67d464520dc696504b3980fccda": "0x000000000000000000000000ac06641381166cf085281c45292147f833c622d7",
"0x59ef95eb9983b1a4650e1bc666384b8507689fc8aca3edd429d7e07c0ca9d2f7": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x8510b5c501cdfc97210e26067e7b0bee5b5cd43d52d902454bc5e2b62167df1d": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000000000000000000000008f86403a4de0bb5791fa46b8e795c547942fe4cf",
"0x8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c231": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c230": "0x0000000000000000000000000000000100000000000000000000000000000001",
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x59ef95eb9983b1a4650e1bc666384b8507689fc8aca3edd429d7e07c0ca9d2f8": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x59ef95eb9983b1a4650e1bc666384b8507689fc8aca3edd429d7e07c0ca9d2f6": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x6bd2118f0148c813209325d23233ce0b7f1042ab160c97a1c605fdedff377204": "0x000000000000000000000000df077f5f72071df6e8b0a78071e496ba17b5ee0c",
"0xdf92d0c198eb2c08351629e12172b863967bc505b5d2fa9fdf58f7b97e45495f": "0x000000000000000000000000beaafda2e17fc95e69dc06878039d274e0d2b21a"
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0": {
"address": "0x00000961Ef480Eb55e80D19ad83579A64c007002",
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd00",
2026-01-12 15:55:46 +00:00
"storage": {}
},
refactor(contracts): Harden DataHavenServiceManager with input validation and code cleanup (#395) ## Summary - Add zero address validation across all functions that accept address parameters to prevent misconfiguration - Fix race condition in `buildNewValidatorSetMessage()` that could cause reverts during validator deregistration - Refactor contract for improved readability and reduced code duplication - Update AVS metadata URL to point to the correct hosted JSON file ## Changes ### Security & Validation - Add `ZeroAddress` error and validate all address inputs in `initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`, `addValidatorToAllowlist`, `registerOperator`, and `updateSolochainAddressForValidator` - Fix race condition: filter out zero solochain addresses in `buildNewValidatorSetMessage()` to prevent reverts when a validator is mid-deregistration ### Refactoring - Replace verbose `if/revert` patterns with `require` statements for consistency - Inline single-use internal functions (`_createDataHavenOperatorSets`, `_setRewardsInitiator`) - Consolidate duplicate error types into single `ZeroAddress` error - Rename `initialise` → `initialize` to maintain consistency with the transparent upgradability pattern - Optimize validator set message encoding by removing redundant wrapper function ### Observability - Add `SolochainAddressUpdated` event for tracking validator address changes ### Cleanup - Remove unused remappings from `foundry.toml` - Fix typo in metadata description --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
2026-01-20 10:32:32 +00:00
"42": {
"address": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d",
"code": "0x608060405234801561000f575f5ffd5b5060043610610148575f3560e01c80637a8b2637116100bf578063ce7c2ac211610079578063ce7c2ac2146102d7578063d9caed12146102ea578063e3dae51c146102fd578063f3e7387514610310578063fabc1cbc14610323578063fdc371ce14610336575f5ffd5b80637a8b26371461025c578063886f11951461026f5780638c871019146102965780638f6a6240146102a9578063ab5921e1146102bc578063c4d66de8146102c4575f5ffd5b8063485cc95511610110578063485cc955146101e257806354fd4d50146101f5578063553ca5f81461020a578063595c6a671461021d5780635ac86ab7146102255780635c975abb14610254575f5ffd5b8063136439dd1461014c5780632495a5991461016157806339b70e38146101915780633a98ef39146101b857806347e7ef24146101cf575b5f5ffd5b61015f61015a3660046111cb565b610349565b005b603254610174906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101747f0000000000000000000000009a676e781a523b5d0c0e43731313a708cb60750881565b6101c160335481565b604051908152602001610188565b6101c16101dd3660046111f6565b610383565b61015f6101f0366004611220565b6104b2565b6101fd61059d565b6040516101889190611257565b6101c161021836600461128c565b6105cd565b61015f6105e0565b6102446102333660046112bc565b6001805460ff9092161b9081161490565b6040519015158152602001610188565b6001546101c1565b6101c161026a3660046111cb565b6105f4565b6101747f000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e81565b6101c16102a43660046111cb565b61063d565b6101c16102b736600461128c565b610647565b6101fd610654565b61015f6102d236600461128c565b610674565b6101c16102e536600461128c565b61073a565b6101c16102f83660046112d7565b6107cc565b6101c161030b3660046111cb565b6108ce565b6101c161031e3660046111cb565b610905565b61015f6103313660046111cb565b61090f565b606454610174906001600160a01b031681565b61035161097c565b60015481811681146103765760405163c61dca5d60e01b815260040160405180910390fd5b61037f82610a1f565b5050565b5f5f61038e81610a5c565b336001600160a01b037f0000000000000000000000009a676e781a523b5d0c0e43731313a708cb60750816146103d7576040516348da714f60e01b815260040160405180910390fd5b6103e18484610a92565b6033545f6103f16103e883611329565b90505f6103e86103ff610b4b565b6104099190611329565b90505f610416878361133c565b905080610423848961134f565b61042d9190611366565b9550855f0361044f57604051630c392ed360e11b815260040160405180910390fd5b6104598685611329565b60338190556f4b3b4ca85a86c47a098a223fffffffff101561048e57604051632f14e8a360e11b815260040160405180910390fd5b6104a7826103e86033546104a29190611329565b610bb5565b505050505092915050565b5f54610100900460ff16158080156104d057505f54600160ff909116105b806104e95750303b1580156104e957505f5460ff166001145b61050e5760405162461bcd60e51b815260040161050590611385565b60405180910390fd5b5f805460ff19166001179055801561052f575f805461ff0019166101001790555b606480546001600160a01b0319166001600160a01b03851617905561055382610c01565b8015610598575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b60606105c87f76312e302e300000000000000000000000000000000000000000000000000006610d4c565b905090565b5f6105da61026a8361073a565b92915050565b6105e861097c565b6105f25f19610a1f565b565b5f5f6103e86033546106069190611329565b90505f6103e8610614610b4b565b61061e9190611329565b90508161062b858361134f565b6106359190611366565b949350505050565b5f6105da826108ce565b5f6105da61031e8361073a565b60606040518060800160405280604d8152602001611456604d9139905090565b5f54610100900460ff161580801561069257505f54600160ff909116105b806106ab5750303b1580156106ab57505f5460ff166001145b6106c75760405162461bcd60e51b815260040161050590611385565b5f805460ff1916600117905580156106e8575f805461ff0019166101001790555b6106f182610c01565b801561037f575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b60405163fe243a1760e01b81526001600160a01b0382811660048301523060248301525f917f0000000000000000000000009a676e781a523b5d0c0e43731313a708cb6075089091169063fe243a1790604401602060405180830381865afa1580156107a8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105da91906113d3565b5f60016107d881610a5c565b336001600160a01b037f0000000000000000000000009a676e781a523b5d0c
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
}
feat: Implement EigenLayer Rewards V2 distribution (#351) ### Summary This PR implements the EigenLayer Rewards Distribution V2 model for DataHaven, replacing the previous merkle-root-based rewards registry approach with EigenLayer's native `OperatorDirectedRewardsSubmission` API. This enables direct integration with EigenLayer's RewardsCoordinator for validator rewards distribution. ### Motivation EigenLayer's V2 rewards model provides several advantages: - **Direct integration**: Uses EigenLayer's native `createOperatorDirectedOperatorSetRewardsSubmission` API - **Per-operator rewards**: Distributes rewards proportionally to individual operators based on their earned points - **Simplified architecture**: Removes the need for a separate RewardsRegistry contract - **Better UX**: Operators receive rewards directly through EigenLayer's established claiming mechanism ### Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ DataHaven Substrate │ ├─────────────────────────────────────────────────────────────────┤ │ Era End │ │ │ │ │ ▼ │ │ external-validators-rewards pallet │ │ │ generate_era_rewards_utils() │ │ │ • Calculate individual points per validator │ │ │ • Compute total inflation amount │ │ │ │ │ ▼ │ │ RewardsSubmissionAdapter (runtime_common) │ │ │ build() → points_to_rewards() → encode_rewards_calldata() │ │ │ │ │ ▼ │ │ Snowbridge Outbound Queue │ │ │ CallContract(ServiceManager.submitRewards(...)) │ └────│────────────────────────────────────────────────────────────┘ │ ▼ Cross-chain message via Snowbridge ┌─────────────────────────────────────────────────────────────────┐ │ Ethereum │ ├─────────────────────────────────────────────────────────────────┤ │ DataHavenServiceManager │ │ │ submitRewards(OperatorDirectedRewardsSubmission) │ │ │ • Approve wHAVE tokens to RewardsCoordinator │ │ │ │ │ ▼ │ │ EigenLayer RewardsCoordinator │ │ │ createOperatorDirectedOperatorSetRewardsSubmission() │ │ │ │ │ ▼ │ │ Operators claim rewards via EigenLayer │ └─────────────────────────────────────────────────────────────────┘ ``` ### Changes Overview #### Smart Contracts (`contracts/`) **DataHavenServiceManager.sol** - Added `submitRewards(OperatorDirectedRewardsSubmission)` function to submit rewards to EigenLayer's RewardsCoordinator - Implements `SafeERC20` for secure token approvals - Uses `onlyRewardsInitiator` modifier for access control (Snowbridge Agent) - Emits `RewardsSubmitted` and `RewardsInitiatorSet` events for tracking **IDataHavenServiceManager.sol** - Added `submitRewards()` interface for EigenLayer rewards submission - Added `setRewardsInitiator()` interface for configuring the authorized caller - Added new events: `RewardsSubmitted`, `RewardsInitiatorSet` **New Test: RewardsSubmitter.t.sol** - Comprehensive test suite covering: - Access control (only rewards initiator can submit) - Single and multiple operator rewards - Multiple consecutive submissions - Custom descriptions and different tokens #### Substrate Runtime (`operator/`) **New: `runtime/common/src/rewards_adapter.rs` (934 lines)** A generic, configurable adapter for building EigenLayer rewards messages: - **`RewardsSubmissionConfig` trait**: Runtime-agnostic configuration interface - `OutboundQueue`: Snowbridge outbound queue type - `rewards_duration()`: Reward period duration (typically 86400s) - `whave_token_address()`: wHAVE ERC20 token on Ethereum - `service_manager_address()`: ServiceManager contract address - `rewards_agent_origin()`: Snowbridge agent origin - **`RewardsSubmissionAdapter<C>`**: Generic implementation of `SendMessage` trait - **`points_to_rewards()`**: Converts validator points to token amounts - Proportional distribution based on total points - Returns remainder (dust) from integer division - Arithmetic overflow/underflow protection - **`encode_rewards_calldata()`**: ABI-encodes the `submitRewards` call - Uses `alloy-core` for type-safe Solidity ABI encoding - Validates `uint96` multiplier bounds - **Comprehensive test suite** covering: - Basic and edge-case reward calculations - Remainder/dust handling - Overflow/underflow protection - ABI encoding round-trip verification - Message building with various configurations **Modified: `pallets/external-validators-rewards/`** - **`types.rs`**: Extended `EraRewardsUtils` struct: ```rust pub struct EraRewardsUtils { pub era_index: u32, // NEW pub rewards_merkle_root: H256, pub leaves: Vec<H256>, pub leaf_index: Option<u64>, pub total_points: u128, pub individual_points: Vec<(H160, u32)>, // NEW pub inflation_amount: u128, // NEW pub era_start_timestamp: u32 // NEW } ``` - **`lib.rs`**: Updated `generate_era_rewards_utils()`: - Now accepts `inflation_amount` parameter - Extracts `individual_points` as `(H160, u32)` tuples for EigenLayer - Returns `None` when `total_points` is zero (prevents inflation with no distribution) - **`mock.rs`**: Updated test mock to use `H160` as `AccountId` (matching DataHaven's EVM-compatible account model) **Modified: Runtime Configurations** All three runtimes (mainnet, stagenet, testnet) updated: 1. **New runtime parameters** (`runtime_params.rs`): - `ServiceManagerAddress`: DataHaven ServiceManager contract on Ethereum - `WHAVETokenAddress`: wHAVE ERC20 token address - `RewardsGenesisTimestamp`: EigenLayer-aligned genesis timestamp - `RewardsDuration`: Rewards period (default: 86400 = 1 day) 2. **Refactored `RewardsSendAdapter`**: - Replaced inline implementation with `RewardsSubmissionAdapter<Config>` - Each runtime implements `RewardsSubmissionConfig` trait - Cleaner, DRY configuration ## ⚠️ Breaking Changes ⚠️ - **Runtime Parameters**: New parameters must be configured via governance before rewards submission will work: - `ServiceManagerAddress` (replaces `RewardsRegistryAddress`) - `WHAVETokenAddress` - `RewardsGenesisTimestamp` - **Contract Interface**: `submitRewards()` now accepts a full `OperatorDirectedRewardsSubmission` struct instead of a merkle root --------- Co-authored-by: Gonza Montiel <gonzamontiel@users.noreply.github.com>
2026-01-06 23:53:03 +00:00
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"46": {
"address": "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02",
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500",
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x000000000000000000000000000000000000000000000000000000000000047d": "0x00000000000000000000000000000000000000000000000000000000697238d1",
"0x0000000000000000000000000000000000000000000000000000000000002478": "0x33f4b7a22c274a253f8f047e28aa095a56cd6a25fc20519286f01d7152f92cac",
"0x0000000000000000000000000000000000000000000000000000000000002479": "0x541fa6279d8389cb5710c10254e6d1161fa1764cf808266ae9760c247b1de184",
"0x0000000000000000000000000000000000000000000000000000000000000461": "0x00000000000000000000000000000000000000000000000000000000697238b5",
"0x000000000000000000000000000000000000000000000000000000000000046f": "0x00000000000000000000000000000000000000000000000000000000697238c3",
"0x0000000000000000000000000000000000000000000000000000000000000452": "0x00000000000000000000000000000000000000000000000000000000697238a6",
"0x0000000000000000000000000000000000000000000000000000000000000488": "0x00000000000000000000000000000000000000000000000000000000697238dc",
"0x0000000000000000000000000000000000000000000000000000000000002455": "0x78bb46a7cb61e6bdb34415590d3bec9407a926362a32f794b020948af31eec4b",
"0x0000000000000000000000000000000000000000000000000000000000002487": "0xf98717faec1f38dc071ea8afde5cac7be731a7bbbfb5610c3d306105b58f7492",
"0x0000000000000000000000000000000000000000000000000000000000002482": "0x37388147728cccc62f6c585fd5bd722e8d5579937f466782b716a335f2a04b5a",
"0x0000000000000000000000000000000000000000000000000000000000000472": "0x00000000000000000000000000000000000000000000000000000000697238c6",
"0x0000000000000000000000000000000000000000000000000000000000000464": "0x00000000000000000000000000000000000000000000000000000000697238b8",
"0x0000000000000000000000000000000000000000000000000000000000000445": "0x0000000000000000000000000000000000000000000000000000000069723899",
"0x000000000000000000000000000000000000000000000000000000000000045a": "0x00000000000000000000000000000000000000000000000000000000697238ae",
"0x000000000000000000000000000000000000000000000000000000000000047b": "0x00000000000000000000000000000000000000000000000000000000697238cf",
"0x0000000000000000000000000000000000000000000000000000000000002448": "0xbc6d08fab0741414058297acbf125161f2fdc3e5cb4b0e89d22a188e0c62d2bc",
"0x0000000000000000000000000000000000000000000000000000000000002459": "0x928833d6bb105e2c08853e1399cada4682e4d311c5fa59df0217d934caab7022",
"0x0000000000000000000000000000000000000000000000000000000000002469": "0x5cfddd9a87e0e4ec7bc6e94d00e5c5be95e656a711801aaf3c064e2a56a9fa11",
"0x0000000000000000000000000000000000000000000000000000000000000486": "0x00000000000000000000000000000000000000000000000000000000697238da",
"0x000000000000000000000000000000000000000000000000000000000000244f": "0x180c3597be125112738bcedf70245e215065ef429e8050833554ed7cd2a38804",
"0x000000000000000000000000000000000000000000000000000000000000048c": "0x00000000000000000000000000000000000000000000000000000000697238e0",
"0x0000000000000000000000000000000000000000000000000000000000000477": "0x00000000000000000000000000000000000000000000000000000000697238cb",
"0x0000000000000000000000000000000000000000000000000000000000000456": "0x00000000000000000000000000000000000000000000000000000000697238aa",
"0x000000000000000000000000000000000000000000000000000000000000046c": "0x00000000000000000000000000000000000000000000000000000000697238c0",
"0x0000000000000000000000000000000000000000000000000000000000002453": "0x66d4ea81c801cbd7fce5e6bdf29badadbae8960b164700a48974ca984f6fca28",
"0x000000000000000000000000000000000000000000000000000000000000246c": "0x0bfd9de6fab35b9664efe10d59fcea1a4b19f005627243935f6a52005759b3c1",
"0x0000000000000000000000000000000000000000000000000000000000002474": "0x3a6c344872b8b6a315149265e28ab9b0ada9ea14b9c213ad25f43788a073760f",
"0x0000000000000000000000000000000000000000000000000000000000002476": "0x6bf71b631c30d9491721b446104222470add3e9ecd9f6a761e0cc6f74ae697e3",
"0x0000000000000000000000000000000000000000000000000000000000002481": "0x7781d8ec936c1d1c871b0552c5e39493bda7c6aec04c2ea85276a0075a2c1c23",
"0x0000000000000000000000000000000000000000000000000000000000002472": "0x4fab78dc66e82a775d0f1e00e5730eb22c197abfb86fa74fac0c17a6ec884a10",
"0x0000000000000000000000000000000000000000000000000000000000002471": "0x89fe746e22fbfc3e6e0fd28a16fdd025ec0a55e541c6cfb9ca4cf2e267ad36d2",
"0x0000000000000000000000000000000000000000000000000000000000000449": "0x000000000000000000000000000000000000000000000000000000006972389d",
"0x0000000000000000000000000000000000000000000000000000000000000467": "0x00000000000000000000000000000000000000000000000000000000697238bb",
"0x000000000000000000000000000000000000000000000000000000000000046d": "0x00000000000000000000000000000000000000000000000000000000697238c1",
"0x0000000000000000000000000000000000000000000000000000000000000459": "0x00000000000000000000000000000000000000000000000000000000697238ad",
"0x0000000000000000000000000000000000000000000000000000000000000480": "0x00000000000000000000000000000000000000000000000000000000697238d4",
"0x000000000000000000000000000000000000000000000000000000000000046a": "0x00000000000000000000000000000000000000000000000000000000697238be",
"0x000000000000000000000000000000000000000000000000000000000000246e": "0x37437855c2f7350a40a8d13cdd6997e2bc2fb5531b2ad11e3d878022bc6cc2ef",
"0x000000000000000000000000000000000000000000000000000000000000044b": "0x000000000000000000000000000000000000000000000000000000006972389f",
"0x000000000000000000000000000000000000000000000000000000000000247b": "0x62387a38188a4177d2d7954ff7dd6fa53bae25356db42cc561edb84eb2c87233",
"0x0000000000000000000000000000000000000000000000000000000000002484": "0x964204cbfafddd69550dc66ffd8369d85247dd43ec77f913f5d941bfb1aef5a6",
"0x0000000000000000000000000000000000000000000000000000000000000446": "0x000000000000000000000000000000000000000000000000000000006972389a",
"0x000000000000000000000000000000000000000000000000000000000000244d": "0x6b69c7e11c386d97a901d74d15173221785099d618a3bd905c4798591e2472a6",
"0x000000000000000000000000000000000000000000000000000000000000047e": "0x00000000000000000000000000000000000000000000000000000000697238d2",
"0x000000000000000000000000000000000000000000000000000000000000247e": "0x74eb6ef676ae8fc7c7fd21f7fc2308b496eb153a834e72c3f0890fb6bdf1027a",
"0x0000000000000000000000000000000000000000000000000000000000002475": "0x4e0767b9e97c8b49bdd1cedeff3bacb70b9a1b0d5c008e746d8f6ca2bfe0b610",
"0x0000000000000000000000000000000000000000000000000000000000002454": "0x6af7ccdca6c7c98a9279047724315c2a48be0f17f1c20c49296479f5d14aefbe",
"0x000000000000000000000000000000000000000000000000000000000000044f": "0x00000000000000000000000000000000000000000000000000000000697238a3",
"0x0000000000000000000000000000000000000000000000000000000000000485": "0x00000000000000000000000000000000000000000000000000000000697238d9",
"0x000000000000000000000000000000000000000000000000000000000000045d": "0x00000000000000000000000000000000000000000000000000000000697238b1",
"0x000000000000000000000000000000000000000000000000000000000000046e": "0x00000000000000000000000000000000000000000000000000000000697238c2",
"0x0000000000000000000000000000000000000000000000000000000000002449": "0x84d0222891c9e06c993a99d85ded6218fcdbc1c13c55a45e8d95851d119e4234",
"0x0000000000000000000000000000000000000000000000000000000000000458": "0x00000000000000000000000000000000000000000000000000000000697238ac",
"0x0000000000000000000000000000000000000000000000000000000000002457": "0x50eac8ce69fb0f0b0250d5e1690d50e928970394120694718f4bef7a5ea7ef71",
"0x000000000000000000000000000000000000000000000000000000000000248a": "0xd89df4ecf0e95207a664d1bec16a2e9277073f6f91a14ad8078de424e7bd8592",
"0x000000000000000000000000000000000000000000000000000000000000044c": "0x00000000000000000000000000000000000000000000000000000000697238a0",
"0x0000000000000000000000000000000000000000000000000000000000000473": "0x00000000000000000000000000000000000000000000000000000000697238c7",
"0x0000000000000000000000000000000000000000000000000000000000000455": "0x00000000000000000000000000000000000000000000000000000000697238a9",
"0x0000000000000000000000000000000000000000000000000000000000002467": "0xbc4f7e3a7d645c90b7a096e84809e183195081de63d5d502d6bf6cc32d4eeb98",
"0x0000000000000000000000000000000000000000000000000000000000000453": "0x00000000000000000000000000000000000000000000000000000000697238a7",
"0x000000000000000000000000000000000000000000000000000000000000245f": "0x361f87740b2f1b0ed2365dffa2c4f3f0eb12f5f66221cfd9aa3a568cd9abceb4",
"0x0000000000000000000000000000000000000000000000000000000000002461": "0xf6a83841edf8fcb1e66e37743a2f869d60fe6c79f9787f0c84f68a225d0b11d4",
"0x0000000000000000000000000000000000000000000000000000000000002444": "0x7c6c245445dbdff3e71cf089d2db408405f961c7e4d361e6570ca432cf6d55d7",
"0x0000000000000000000000000000000000000000000000000000000000002486": "0xa201b506d37d418fdcd45dfd467c5476cdd5f96c09a1399511d48b3d4658474f",
"0x0000000000000000000000000000000000000000000000000000000000000470": "0x00000000000000000000000000000000000000000000000000000000697238c4",
"0x000000000000000000000000000000000000000000000000000000000000248b": "0x2d890eaeeb3c19a7baeb9658df1db21f185a8fe4984771df4d4dd149ce6b64f9",
"0x000000000000000000000000000000000000000000000000000000000000045e": "0x00000000000000000000000000000000000000000000000000000000697238b2",
"0x000000000000000000000000000000000000000000000000000000000000247d": "0x975e0c76ac8bb18586d96588faf09997ef0a4bad33b7cf7d2a07615cbcb036d2",
"0x000000000000000000000000000000000000000000000000000000000000245c": "0xb24731b36d9fb45d3fd28f64bb879f2bdd27dcee352e35af2f59c2aecdfaea20",
"0x000000000000000000000000000000000000000000000000000000000000047f": "0x00000000000000000000000000000000000000000000000000000000697238d3",
"0x000000000000000000000000000000000000000000000000000000000000048a": "0x00000000000000000000000000000000000000000000000000000000697238de",
"0x0000000000000000000000000000000000000000000000000000000000002447": "0x5fcdf63ed9ee4714d8d3b3370b4a5bd51ba0cddb4ceaad028008cc68a5c3bfe0",
"0x0000000000000000000000000000000000000000000000000000000000000483": "0x00000000000000000000000000000000000000000000000000000000697238d7",
"0x000000000000000000000000000000000000000000000000000000000000044d": "0x00000000000000000000000000000000000000000000000000000000697238a1",
"0x000000000000000000000000000000000000000000000000000000000000245a": "0xccc53e889e3c202cf57575e55088445204e2ceebeab3987d768f831489a8e493",
"0x000000000000000000000000000000000000000000000000000000000000045f": "0x00000000000000000000000000000000000000000000000000000000697238b3",
"0x0000000000000000000000000000000000000000000000000000000000000469": "0x00000000000000000000000000000000000000000000000000000000697238bd",
"0x000000000000000000000000000000000000000000000000000000000000244a": "0x23527ac268bd603cea37ad3ec137101dd9723dfb020e552ed86221773c947137",
"0x000000000000000000000000000000000000000000000000000000000000048f": "0x00000000000000000000000000000000000000000000000000000000697238e3",
"0x0000000000000000000000000000000000000000000000000000000000002465": "0xd1c1d44101783386ccb22f699b186a5654be2f1c972688c03c8b0304a5442f42",
"0x000000000000000000000000000000000000000000000000000000000000247a": "0x9220ecb05dbc583364c680ac30fd504cd953b2cada6899b750b4430a5bcc6512",
"0x000000000000000000000000000000000000000000000000000000000000247c": "0x7d37f7705914d62e2de5f5c4ca5bbf599dbb885c225c6672466f05ee99c1fe12",
"0x0000000000000000000000000000000000000000000000000000000000000451": "0x00000000000000000000000000000000000000000000000000000000697238a5",
"0x0000000000000000000000000000000000000000000000000000000000000465": "0x00000000000000000000000000000000000000000000000000000000697238b9",
"0x000000000000000000000000000000000000000000000000000000000000244b": "0x8dc2ff3299d70c7408b8ba2bd6d72f18fba95038594bae40d704faeca438b76d",
"0x0000000000000000000000000000000000000000000000000000000000002480": "0x78123ad8ce4dc49e0b9e5c1b998efed203276d16301231b1defe29d1c4f31409",
"0x0000000000000000000000000000000000000000000000000000000000000487": "0x00000000000000000000000000000000000000000000000000000000697238db",
"0x000000000000000000000000000000000000000000000000000000000000245b": "0xf5fd7f142382a8b3036a73581409a1a81f4253976a2f45a262a4aef542b25682",
"0x0000000000000000000000000000000000000000000000000000000000000463": "0x00000000000000000000000000000000000000000000000000000000697238b7",
"0x000000000000000000000000000000000000000000000000000000000000248c": "0x796c897719d317d104b3fe0e3dd718a16ccaac62a03fe792f06ab1860b020bcd",
"0x0000000000000000000000000000000000000000000000000000000000000479": "0x00000000000000000000000000000000000000000000000000000000697238cd",
"0x0000000000000000000000000000000000000000000000000000000000000482": "0x00000000000000000000000000000000000000000000000000000000697238d6",
"0x0000000000000000000000000000000000000000000000000000000000002456": "0xf2329f0610d54dd62dad2ff6b2ce7e044c563f0330486248487b5649a8e57f32",
"0x0000000000000000000000000000000000000000000000000000000000002450": "0x629f40464f808b00779cce29a20b44678ad27fbab164b52b3ce65f91c6991892",
"0x0000000000000000000000000000000000000000000000000000000000002458": "0xe039f05481865865b1ed65b8afb07a1878e3e39841cd102fd7adc7b2d10f66a2",
"0x000000000000000000000000000000000000000000000000000000000000248d": "0x06a8c2d710b8466d9610c5390735fcd8cda2db8346ec894711ed34c2a44e3370",
"0x0000000000000000000000000000000000000000000000000000000000000476": "0x00000000000000000000000000000000000000000000000000000000697238ca",
"0x000000000000000000000000000000000000000000000000000000000000048e": "0x00000000000000000000000000000000000000000000000000000000697238e2",
"0x000000000000000000000000000000000000000000000000000000000000248e": "0xe80b58c8fb6c38cee7e89906f5bc67db0c3d795ce038e20fa772838e0dfda9d9",
"0x0000000000000000000000000000000000000000000000000000000000002452": "0x5ce6c063ba5a96a2bf7dc17a7e440256a030a76d31512d281f72f2e5fc12d212",
"0x000000000000000000000000000000000000000000000000000000000000245e": "0x8da6e81a5056bf532fc1b9359030ce3d92460ae7597a082499a857b25733d1c1",
"0x0000000000000000000000000000000000000000000000000000000000000481": "0x00000000000000000000000000000000000000000000000000000000697238d5",
"0x0000000000000000000000000000000000000000000000000000000000000474": "0x00000000000000000000000000000000000000000000000000000000697238c8",
"0x0000000000000000000000000000000000000000000000000000000000002466": "0x5d9f43d718821f409ab035232280df2095ee3993eb0cd732051129a3a411e357",
"0x0000000000000000000000000000000000000000000000000000000000002473": "0x1f0a9590c08c416f865a99aa629f215e81a309a9c9aba561417ad52e75cee459",
"0x0000000000000000000000000000000000000000000000000000000000000447": "0x000000000000000000000000000000000000000000000000000000006972389b",
"0x000000000000000000000000000000000000000000000000000000000000246b": "0xe52553027455ae41c0df271964e3ed9620cab07cf058f391c42ad253128d9408",
"0x000000000000000000000000000000000000000000000000000000000000047c": "0x00000000000000000000000000000000000000000000000000000000697238d0",
"0x000000000000000000000000000000000000000000000000000000000000047a": "0x00000000000000000000000000000000000000000000000000000000697238ce",
"0x000000000000000000000000000000000000000000000000000000000000246a": "0xa4a069f58ddcd2f73c87dbfef895ba67c96701708c32924f4a6d567abc54ec19",
"0x0000000000000000000000000000000000000000000000000000000000000460": "0x00000000000000000000000000000000000000000000000000000000697238b4",
"0x0000000000000000000000000000000000000000000000000000000000000454": "0x00000000000000000000000000000000000000000000000000000000697238a8",
"0x000000000000000000000000000000000000000000000000000000000000247f": "0x4cc2003f4ae9925d2a0f1f58f9fbc34d75ee9d1b7e6271be78e4245e8405efa7",
"0x0000000000000000000000000000000000000000000000000000000000002451": "0x5154642f458e86b9582eb0fd4aca5288cc0ea430a2e308314371da24755dd95f",
"0x0000000000000000000000000000000000000000000000000000000000002489": "0x604959dff65a1deba1c3991c69ad92d426b51611b8ae98dc8b982968a598c82d",
"0x0000000000000000000000000000000000000000000000000000000000000466": "0x00000000000000000000000000000000000000000000000000000000697238ba",
"0x000000000000000000000000000000000000000000000000000000000000045c": "0x00000000000000000000000000000000000000000000000000000000697238b0",
"0x0000000000000000000000000000000000000000000000000000000000000468": "0x00000000000000000000000000000000000000000000000000000000697238bc",
"0x0000000000000000000000000000000000000000000000000000000000000484": "0x00000000000000000000000000000000000000000000000000000000697238d8",
"0x0000000000000000000000000000000000000000000000000000000000000462": "0x00000000000000000000000000000000000000000000000000000000697238b6",
"0x000000000000000000000000000000000000000000000000000000000000245d": "0x2a3a6a49c7046f8e971535952dd1b34f0cc33f367abfd57436a9ace6f750eba1",
"0x0000000000000000000000000000000000000000000000000000000000002460": "0x06d272c823662455995135fa2bf92acd5ccc1f7b80373c4778d36b160e887d33",
"0x0000000000000000000000000000000000000000000000000000000000002445": "0xfdab1d1c2672259525cd5a4526712c6c4cff3d874cbac051aee655524edda829",
"0x000000000000000000000000000000000000000000000000000000000000244e": "0xf8fd49a0aaf9939561aa4e3c7689c80f15c4106fd61eb3168f8ef2018b49a3e2",
"0x0000000000000000000000000000000000000000000000000000000000002488": "0x7247670d4d2a5f80683ab9552c4d780b0dc746bda5d9a70206635391d24dd59e",
"0x000000000000000000000000000000000000000000000000000000000000044e": "0x00000000000000000000000000000000000000000000000000000000697238a2",
"0x000000000000000000000000000000000000000000000000000000000000244c": "0x89c81eba17ac01f4397bf7c932b0a1db58b2dcc4356f1c8e3bbf8a5b6e823104",
"0x000000000000000000000000000000000000000000000000000000000000044a": "0x000000000000000000000000000000000000000000000000000000006972389e",
"0x0000000000000000000000000000000000000000000000000000000000002464": "0xefdbcaca82d4ad681a074d716113b0ea592ae0520b0d2cfdd0e819c4361d713f",
"0x0000000000000000000000000000000000000000000000000000000000002485": "0x29c9375906d6d8f690b8bda099e31fc9428e27a290ba4dc471b9d271c8b7adbe",
"0x0000000000000000000000000000000000000000000000000000000000000457": "0x00000000000000000000000000000000000000000000000000000000697238ab",
"0x0000000000000000000000000000000000000000000000000000000000000475": "0x00000000000000000000000000000000000000000000000000000000697238c9",
"0x000000000000000000000000000000000000000000000000000000000000246f": "0xd9602aeb69c13b3752172f77bf144ca6d71bb21476bd90286d37c90a86239ae9",
"0x0000000000000000000000000000000000000000000000000000000000000450": "0x00000000000000000000000000000000000000000000000000000000697238a4",
"0x0000000000000000000000000000000000000000000000000000000000000471": "0x00000000000000000000000000000000000000000000000000000000697238c5",
"0x0000000000000000000000000000000000000000000000000000000000002468": "0x39e3e27cf9df76ec404ce6929a4d49369c8e6e06e53d59d46697dca84b9723ba",
"0x0000000000000000000000000000000000000000000000000000000000002477": "0x5ba2e6d3afa130be24ccb2ab8b259358c9f7cc6bb1ded34f30c2df041baa94a1",
"0x000000000000000000000000000000000000000000000000000000000000046b": "0x00000000000000000000000000000000000000000000000000000000697238bf",
"0x0000000000000000000000000000000000000000000000000000000000002483": "0x695736708364ed76c3d8113c6d71e6db0ef9739a00187c59bb1c85bebf82e3fb",
"0x000000000000000000000000000000000000000000000000000000000000246d": "0x43d28cffdc7c4e712a02531e9a82788db2db25ae097eeb508eea647fbd66b8ac",
"0x0000000000000000000000000000000000000000000000000000000000002463": "0x2a9e87d5c512b4eb9ab9b31b49e9ed2a138411c65f5b4332eb1f8218c338511b",
"0x0000000000000000000000000000000000000000000000000000000000000489": "0x00000000000000000000000000000000000000000000000000000000697238dd",
"0x000000000000000000000000000000000000000000000000000000000000048d": "0x00000000000000000000000000000000000000000000000000000000697238e1",
"0x0000000000000000000000000000000000000000000000000000000000002446": "0x1b0fb1d8777656036988eae201185a7e3bdd9e1d1ff66a83a28a1d3305e5d898",
"0x0000000000000000000000000000000000000000000000000000000000002470": "0x7c1c09193652ccb5b8f78cddf7a93adfde3f1460f8a225e8e35b93f9db7fe624",
"0x000000000000000000000000000000000000000000000000000000000000045b": "0x00000000000000000000000000000000000000000000000000000000697238af",
"0x0000000000000000000000000000000000000000000000000000000000002462": "0x5cd583c165373a7f2989274fb0e2a067dc174c983406a7a81ff287ea7aaff99a",
"0x0000000000000000000000000000000000000000000000000000000000000448": "0x000000000000000000000000000000000000000000000000000000006972389c",
"0x000000000000000000000000000000000000000000000000000000000000048b": "0x00000000000000000000000000000000000000000000000000000000697238df",
"0x0000000000000000000000000000000000000000000000000000000000000478": "0x00000000000000000000000000000000000000000000000000000000697238cc"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"13": {
"address": "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1",
"code": "0x608060405234801561000f575f5ffd5b5060043610610055575f3560e01c80633659cfe6146100595780635c60da1b1461006e578063715018a6146100975780638da5cb5b1461009f578063f2fde38b146100af575b5f5ffd5b61006c6100673660046102d7565b6100c2565b005b6001546001600160a01b03165b6040516001600160a01b03909116815260200160405180910390f35b61006c610109565b5f546001600160a01b031661007b565b61006c6100bd3660046102d7565b61011c565b6100ca61019a565b6100d3816101f3565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b61011161019a565b61011a5f610288565b565b61012461019a565b6001600160a01b03811661018e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61019781610288565b50565b5f546001600160a01b0316331461011a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610185565b6001600160a01b0381163b6102665760405162461bcd60e51b815260206004820152603360248201527f5570677261646561626c65426561636f6e3a20696d706c656d656e746174696f6044820152721b881a5cc81b9bdd08184818dbdb9d1c9858dd606a1b6064820152608401610185565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f602082840312156102e7575f5ffd5b81356001600160a01b03811681146102fd575f5ffd5b939250505056fea2646970667358221220003d7f443094069cb023dc39fb36d6ba29922db6cd9b714ea95af972fc56405e64736f6c634300081c003300000000000000",
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000059b670e9fa9d0a427751af201d676719a970857b",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000015d34aaf54267db7d7c367839aaf71a00a2c6a65"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"14": {
"address": "0xBeaAFDA2E17fC95E69Dc06878039d274E0d2B21A",
"code": "0x608060405260043610610036575f3560e01c8063338c5371146100415780639bb66b2814610091578063e905182a146100be575f5ffd5b3661003d57005b5f5ffd5b34801561004c575f5ffd5b506100747f0000000000000000000000009d4454b023096f34b160d6b654540c56a1f8168881565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561009c575f5ffd5b506100b06100ab3660046101ae565b6100ff565b604051610088929190610239565b3480156100c9575f5ffd5b506100f17f03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131481565b604051908152602001610088565b5f6060336001600160a01b037f0000000000000000000000009d4454b023096f34b160d6b654540c56a1f81688161461014a576040516282b42960e81b815260040160405180910390fd5b846001600160a01b03168484604051610164929190610277565b5f60405180830381855af49150503d805f811461019c576040519150601f19603f3d011682016040523d82523d5f602084013e6101a1565b606091505b5091509150935093915050565b5f5f5f604084860312156101c0575f5ffd5b83356001600160a01b03811681146101d6575f5ffd5b9250602084013567ffffffffffffffff8111156101f1575f5ffd5b8401601f81018613610201575f5ffd5b803567ffffffffffffffff811115610217575f5ffd5b866020828401011115610228575f5ffd5b939660209190910195509293505050565b8215158152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f8301168401019150509392505050565b818382375f910190815291905056fea26469706673582212208fe760f358faedf4a90fd4b23c39c8397def11c5b035ea1406af976ecc426bbf64736f6c634300081c00330000000000",
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
"storage": {}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"12": {
"address": "0x5FbDB2315678afecb367f032d93F642f64180aa3",
"code": "0x735fbdb2315678afecb367f032d93f642f64180aa33014608060405260043610610034575f3560e01c8063e5bad8da14610038575b5f5ffd5b61004b610046366004610256565b61005f565b604051901515815260200160405180910390f35b5f80610079610073368590038501856102fc565b85610104565b90506001600160a01b03851663a401662b8261009860c087018761039b565b8760e001356040518563ffffffff1660e01b81526004016100bc94939291906103e8565b602060405180830381865afa1580156100d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100fb919061042c565b95945050505050565b81515f90819060f81b61013c8560200151600881811c62ff00ff1663ff00ff009290911b9190911617601081811c91901b1760e01b90565b85604001516101b287606001515f65ff000000ff00600883811b91821664ff000000ff9185901c91821617601090811b67ff000000ff0000009390931666ff000000ff00009290921691909117901c17602081811b6bffffffffffffffff000000001691901c63ffffffff161760c01b92915050565b6080880151600881811b63ff00ff001662ff00ff9290911c9190911617601081811b91901c1760e01b60a08901516040516001600160f81b031990961660208701526001600160e01b0319948516602187015260258601939093526001600160c01b0319909116604585015291909116604d83015260518201526071810184905260910160408051808303601f190181529190528051602090910120949350505050565b5f5f5f60608486031215610268575f5ffd5b83356001600160a01b038116811461027e575f5ffd5b925060208401359150604084013567ffffffffffffffff8111156102a0575f5ffd5b840161010081870312156102b2575f5ffd5b809150509250925092565b803560ff811681146102cd575f5ffd5b919050565b803563ffffffff811681146102cd575f5ffd5b803567ffffffffffffffff811681146102cd575f5ffd5b5f60c082840312801561030d575f5ffd5b5060405160c0810167ffffffffffffffff8111828210171561033d57634e487b7160e01b5f52604160045260245ffd5b604052610349836102bd565b8152610357602084016102d2565b602082015260408381013590820152610372606084016102e5565b6060820152610383608084016102d2565b608082015260a0928301359281019290925250919050565b5f5f8335601e198436030181126103b0575f5ffd5b83018035915067ffffffffffffffff8211156103ca575f5ffd5b6020019150600581901b36038213156103e1575f5ffd5b9250929050565b84815260606020820181905281018390525f6001600160fb1b0384111561040d575f5ffd5b8360051b80866080850137604083019390935250016080019392505050565b5f6020828403121561043c575f5ffd5b8151801515811461044b575f5ffd5b939250505056fea2646970667358221220202aa32fed9b1043addbc14e73c73106e521b4a0cbd4090b88a279664688a3ca64736f6c634300081c0033000000000000000000000000",
refactor(contracts): Harden DataHavenServiceManager with input validation and code cleanup (#395) ## Summary - Add zero address validation across all functions that accept address parameters to prevent misconfiguration - Fix race condition in `buildNewValidatorSetMessage()` that could cause reverts during validator deregistration - Refactor contract for improved readability and reduced code duplication - Update AVS metadata URL to point to the correct hosted JSON file ## Changes ### Security & Validation - Add `ZeroAddress` error and validate all address inputs in `initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`, `addValidatorToAllowlist`, `registerOperator`, and `updateSolochainAddressForValidator` - Fix race condition: filter out zero solochain addresses in `buildNewValidatorSetMessage()` to prevent reverts when a validator is mid-deregistration ### Refactoring - Replace verbose `if/revert` patterns with `require` statements for consistency - Inline single-use internal functions (`_createDataHavenOperatorSets`, `_setRewardsInitiator`) - Consolidate duplicate error types into single `ZeroAddress` error - Rename `initialise` → `initialize` to maintain consistency with the transparent upgradability pattern - Optimize validator set message encoding by removing redundant wrapper function ### Observability - Add `SolochainAddressUpdated` event for tracking validator address changes ### Cleanup - Remove unused remappings from `foundry.toml` - Fix typo in metadata description --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
2026-01-20 10:32:32 +00:00
"storage": {}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"29": {
"address": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed",
"code": "0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f5ffd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f5f375f5f365f845af43d5f5f3e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f5f856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f5f85851115610676575f5ffd5b83861115610682575f5ffd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f5ffd5b919050565b5f602082840312156106ba575f5ffd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e8575f5ffd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f5ffd5b8301601f8101851361071c575f5ffd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c657665
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x38de7073e27519f272741044a68ab5a51022aa002af20801e32867226a9bb4bd": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x9254291d7d424716ad6728e8cf28d7329070cafa88280734e18f0a5f711cc416": "0x000000000000000000000000998abeb3e57409262ae5b751f60747921b33613e",
"0x288c6faa56b91953378099dc2014a331affa988ca357fe83ca55e72915585282": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x4bad58e84dc127f47e7265bd5e504be070126f63f93af282fe2a4f1acbb07707": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x165183f4d7a8ecead93a30c1491a78d70b212627d72d451cc2b61e9844bb6182": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000c5a5c42992decbae36851359345fe25997f5c42d",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x54ab5bc83c0127df10d352dbba9557880cef93f87419916bd513c73a26e9de39": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"1": {
"address": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
"code": "0x732279b7a0a67db372996a5fab50d91eaa73d2ebe63014608060405260043610610034575f3560e01c8063a3499c7314610038575b5f5ffd5b818015610043575f5ffd5b50610057610052366004610230565b610059565b005b61006b836001600160a01b03166101b3565b610088576040516303777f6960e51b815260040160405180910390fd5b81836001600160a01b03163f146100b2576040516323e13ec960e21b815260040160405180910390fd5b6100da837f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b5f5f846001600160a01b0316836040516024016100f79190610309565b60408051601f198184030181529181526020820180516001600160e01b031663439fab9160e01b1790525161012c919061033e565b5f60405180830381855af49150503d805f8114610164576040519150601f19603f3d011682016040523d82523d5f602084013e610169565b606091505b509150915061017882826101fd565b506040516001600160a01b038616907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a25050505050565b5f6001600160a01b0382163f158015906101f757507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4706001600160a01b0383163f14155b92915050565b6060821561020c5750806101f7565b8151156100345781518083602001fd5b634e487b7160e01b5f52604160045260245ffd5b5f5f5f60608486031215610242575f5ffd5b83356001600160a01b0381168114610258575f5ffd5b925060208401359150604084013567ffffffffffffffff81111561027a575f5ffd5b8401601f8101861361028a575f5ffd5b803567ffffffffffffffff8111156102a4576102a461021c565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156102d3576102d361021c565b6040528181528282016020018810156102ea575f5ffd5b816020840160208301375f602083830101528093505050509250925092565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f82518060208501845e5f92019182525091905056fea26469706673582212204f9eff25a489952d6ace57dae13f4311e26f51d13db35754950e1446aa6c4c3264736f6c634300081c003300",
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
"storage": {}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"2": {
"address": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933",
"code": "0x608060405234801561000f575f5ffd5b50600436106100e5575f3560e01c80639100674511610088578063ad8aca7711610063578063ad8aca77146101df578063df595cb8146101f2578063eb5a4e8714610205578063fddbdefd14610218575f5ffd5b80639100674514610196578063950d806e146101b9578063ad5f2210146101cc575f5ffd5b806354fd4d50116100c357806354fd4d5014610124578063628806ef146101425780636bddfa1f14610155578063882a3b3814610175575f5ffd5b806306641201146100e9578063268959e5146100fe5780634f906cf914610111575b5f5ffd5b6100fc6100f7366004610dbd565b61022b565b005b6100fc61010c366004610e0e565b61034c565b6100fc61011f366004610e0e565b610427565b61012c6104ca565b6040516101399190610e3f565b60405180910390f35b6100fc610150366004610e74565b6104fa565b610168610163366004610e74565b610588565b6040516101399190610ed0565b610188610183366004610e0e565b6105b1565b604051610139929190610ee2565b6101a96101a4366004610e0e565b610712565b6040519015158152602001610139565b6100fc6101c7366004610dbd565b610782565b6101686101da366004610e74565b610893565b6101a96101ed366004610e0e565b610939565b6101a9610200366004610dbd565b61095a565b6100fc610213366004610e0e565b6109af565b610168610226366004610f44565b610a7d565b836102368133610712565b61025357604051637bfa4b9f60e01b815260040160405180910390fd5b6001600160a01b0385165f908152600160205260408120906102758585610abb565b6001600160a01b0387165f908152600484016020526040902090915061029b9082610ae8565b6102b85760405163262118cd60e01b815260040160405180910390fd5b6001600160a01b0386165f90815260048301602052604090206102db9082610aff565b505f81815260058301602052604090206102f59087610b0a565b50856001600160a01b0316876001600160a01b03167f18242326b6b862126970679759169f01f646bd55ec5bfcab85ba9f337a74e0c6878760405161033b929190610f84565b60405180910390a350505050505050565b816103578133610712565b61037457604051637bfa4b9f60e01b815260040160405180910390fd5b6001600160a01b0383165f9081526001602081905260409091206002019061039b82610b1e565b116103b9576040516310ce892b60e31b815260040160405180910390fd5b6103c38184610b0a565b6103e057604051630716d81b60e51b815260040160405180910390fd5b6040516001600160a01b0384811682528516907fdb9d5d31320daf5bc7181d565b6da4d12e30f0f4d5aa324a992426c14a1d19ce906020015b60405180910390a250505050565b816104328133610712565b61044f57604051637bfa4b9f60e01b815260040160405180910390fd5b6001600160a01b0383165f9081526001602052604090206104708184610b0a565b61048d5760405163bed8295f60e01b815260040160405180910390fd5b6040516001600160a01b0384811682528516907fd706ed7ae044d795b49e54c9f519f663053951011985f663a862cd9ee72a9ac790602001610419565b60606104f57f76312e302e300000000000000000000000000000000000000000000000000006610b27565b905090565b6001600160a01b0381165f90815260016020526040902061051b8133610b0a565b6105385760405163bed8295f60e01b815260040160405180910390fd5b6105456002820133610b64565b506040513381526001600160a01b038316907fbf265e8326285a2747e33e54d5945f7111f2b5edb826eb8c08d4677779b3ff979060200160405180910390a25050565b6001600160a01b0381165f9081526001602052604090206060906105ab90610b78565b92915050565b6001600160a01b038083165f9081526001602090815260408083209385168352600490930190529081206060918291906105ea82610b1e565b90505f8167ffffffffffffffff81111561060657610606610fa7565b60405190808252806020026020018201604052801561062f578160200160208202803683370190505b5090505f8267ffffffffffffffff81111561064c5761064c610fa7565b604051908082528060200260200182016040528015610675578160200160208202803683370190505b5090505f5b83811015610704576106a861068f8683610b84565b606081901c9160a09190911b6001600160e01b03191690565b8483815181106106ba576106ba610fbb565b602002602001018484815181106106d3576106d3610fbb565b6001600160e01b0319909316602093840291909101909201919091526001600160a01b03909116905260010161067a565b509097909650945050505050565b6001600160a01b0382165f90815260016020526040812061073590600201610b1e565b5f0361075757816001600160a01b0316836001600160a01b03161490506105ab565b6001600160a01b0383165f90815260016020526040902061077b9060020183610b8f565b9392505050565b8361078d8133610712565b6107aa57604051637bfa4b9f60e01b815260040160405180910390fd5b6001600160a01b0385165f908152600160205260408120906107cc8585610abb565b6001600160a01b0387165f90815260048401602052604090209091506107f29082610ae8565b1561081057
feat : Slashing integration in EigenLayer and Datahaven AVS (#345) ## 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
2026-01-16 19:49:45 +00:00
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
}
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"22": {
"address": "0x95401dc811bb5740090279Ba06cfA8fcF6113778",
"code": "0x608060405234801561000f575f5ffd5b50600436106100cb575f3560e01c806342966c681161008857806395d89b411161006357806395d89b41146101a7578063a457c2d7146101af578063a9059cbb146101c2578063dd62ed3e146101d5575f5ffd5b806342966c681461015757806370a082311461016c57806379cc679014610194575f5ffd5b806306fdde03146100cf578063095ea7b3146100ed57806318160ddd1461011057806323b872dd14610122578063313ce567146101355780633950935114610144575b5f5ffd5b6100d76101e8565b6040516100e49190610826565b60405180910390f35b6101006100fb366004610876565b610278565b60405190151581526020016100e4565b6002545b6040519081526020016100e4565b61010061013036600461089e565b610291565b604051601281526020016100e4565b610100610152366004610876565b6102b4565b61016a6101653660046108d8565b6102d5565b005b61011461017a3660046108ef565b6001600160a01b03165f9081526020819052604090205490565b61016a6101a2366004610876565b6102e2565b6100d76102fb565b6101006101bd366004610876565b61030a565b6101006101d0366004610876565b610389565b6101146101e336600461090f565b610396565b6060600380546101f790610940565b80601f016020809104026020016040519081016040528092919081815260200182805461022390610940565b801561026e5780601f106102455761010080835404028352916020019161026e565b820191905f5260205f20905b81548152906001019060200180831161025157829003601f168201915b5050505050905090565b5f336102858185856103c0565b60019150505b92915050565b5f3361029e8582856104e4565b6102a985858561055c565b506001949350505050565b5f336102858185856102c68383610396565b6102d09190610978565b6103c0565b6102df33826106fe565b50565b6102ed8233836104e4565b6102f782826106fe565b5050565b6060600480546101f790610940565b5f33816103178286610396565b90508381101561037c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102a982868684036103c0565b5f3361028581858561055c565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166104225760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610373565b6001600160a01b0382166104835760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610373565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b5f6104ef8484610396565b90505f19811461055657818110156105495760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610373565b61055684848484036103c0565b50505050565b6001600160a01b0383166105c05760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610373565b6001600160a01b0382166106225760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610373565b6001600160a01b0383165f90815260208190526040902054818110156106995760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610373565b6001600160a01b038481165f81815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610556565b6001600160a01b03821661075e5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610373565b6001600160a01b0382165f90815260208190526040902054818110156107d15760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610373565b6001600160a01b0383165f818152602081815260408083208686039055600280548790039055
refactor: cleanup old rewards model (#383) ## Summary This PR removes the old merkle root-based rewards model and completes the migration to EigenLayer Rewards V2 distribution. The old model required operators to claim rewards by providing merkle proofs, while the new model uses `submitRewards` to send rewards directly to EigenLayer's `RewardsCoordinator`. ### Key Changes - **Smart Contracts**: Removed `RewardsRegistry`, `RewardsRegistryStorage`, `IRewardsRegistry`, and `SortedMerkleProof` contracts along with all merkle claim functions from `ServiceManagerBase` - **Substrate Pallets**: Removed merkle proof generation from `external-validators-rewards` pallet and deleted the entire `runtime-api` crate (no longer needed) - **Test Framework**: Removed all RewardsRegistry-related code from deployment scripts, CLI handlers, and TypeScript bindings - **Runtimes**: Cleaned up all three runtimes (testnet, stagenet, mainnet) to remove runtime API implementations and unused imports ### Files Removed **Contracts:** - `contracts/src/middleware/RewardsRegistry.sol` - `contracts/src/middleware/RewardsRegistryStorage.sol` - `contracts/src/interfaces/IRewardsRegistry.sol` - `contracts/src/libraries/SortedMerkleProof.sol` - `contracts/test/RewardsRegistry.t.sol` - `contracts/test/ServiceManagerRewardsRegistry.t.sol` **Substrate:** - `operator/pallets/external-validators-rewards/runtime-api/` (entire crate) **Test Framework:** - `test/suites/rewards-message.test.ts` ### Files Modified **Contracts:** - `ServiceManagerBase.sol` - Removed merkle claim functions - `ServiceManagerBaseStorage.sol` - Removed `operatorSetToRewardsRegistry` mapping - `IServiceManager.sol` - Removed interface members **Substrate:** - `external-validators-rewards` pallet - Removed merkle proof generation, simplified `EraRewardsUtils` struct - All runtime configs - Removed `ExternalValidatorsRewardsApi` implementations **Test Framework:** - Updated deployment scripts, CLI handlers, relayer configs, and TypeScript bindings ### Stats ``` 50 files changed, 966 insertions(+), 4453 deletions(-) ``` ## Test plan - [x] All Rust tests pass (`cargo test`) - [x] All contract tests pass (`forge test`) - [x] TypeScript type checking passes (`bun typecheck`) - [x] Contracts build successfully (`forge build`) - [x] Operator builds successfully (`cargo build --release --features fast-runtime`) - [ ] E2E tests pass (`bun test:e2e`)
2026-01-09 14:25:49 +00:00
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000d3c21bcecceda1000000",
"0xd19bcde47e0ffe1c643525c3cff070e266ec404a07f499b41fcbc480ff16fff7": "0x0000000000000000000000000000000000000000000069e10de76676d0800000",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x54657374546f6b656e0000000000000000000000000000000000000000000012",
"0x14e04a66bf74771820a7400ff6cf065175b3d7eb25805a5bd1633b161af5d101": "0x0000000000000000000000000000000000000000000069e10de76676d0800000",
"0x0000000000000000000000000000000000000000000000000000000000000004": "0x5445535400000000000000000000000000000000000000000000000000000008"
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"7": {
"address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853",
"code": "0x73a513e6e4b8f2a923d98304ec87f64353c4d5c853301460806040526004361061009b575f3560e01c806338412ce51161006e57806338412ce514610150578063480ff0651461016f5780636f378c061461018e578063957cae98146101ad578063c7f62387146101c0575f5ffd5b806319a79b481461009f5780631b8d43b0146100c057806320606b70146100f457806330adf81f14610129575b5f5ffd5b8180156100aa575f5ffd5b506100be6100b9366004610a4d565b6101df565b005b8180156100cb575f5ffd5b506100df6100da366004610acf565b610346565b60405190151581526020015b60405180910390f35b61011b7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b6040519081526020016100eb565b61011b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b81801561015b575f5ffd5b506100df61016a366004610b10565b61036b565b81801561017a575f5ffd5b506100be610189366004610b10565b610384565b818015610199575f5ffd5b506100df6101a8366004610b10565b6103cf565b61011b6101bb366004610b43565b6103dc565b8180156101cb575f5ffd5b506100be6101da366004610b10565b6103ec565b834211156102005760405163068568f360e21b815260040160405180910390fd5b5f61020a8961042d565b6001600160a01b0389165f90815260028c016020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928c928c928c9290919061025983610b6e565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810187905260e001604051602081830303815290604052805190602001206040516020016102d292919061190160f01b81526002810192909252602282015260420190565b6040516020818303038152906040528051906020012090505f6102f7828686866104dc565b9050886001600160a01b0316816001600160a01b03161461032b57604051638baa579f60e01b815260040160405180910390fd5b6103398b8a8a8a6001610502565b5050505050505050505050565b5f610353858533856105f0565b506103608585858561067c565b506001949350505050565b5f61037a843385856001610502565b5060019392505050565b5f6001600160a01b0383166103bd57604051639cfea58360e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b506103ca835f84846106f8565b505050565b5f61037a8433858561067c565b5f6103e68261042d565b92915050565b5f6001600160a01b038316610420576040516313053d9360e21b81526001600160a01b0390911660048201526024016103b4565b506103ca83835f846106f8565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8260405161045d9190610b86565b60408051918290038220828201825260018352603160f81b6020938401528151928301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c001604051602081830303815290604052805190602001209050919050565b5f5f5f6104eb87878787610829565b915091506104f8816108e6565b5095945050505050565b5f6001600160a01b038516610536576040516322f051b160e21b81526001600160a01b0390911660048201526024016103b4565b505f6001600160a01b03841661056b5760405163270af7ed60e11b81526001600160a01b0390911660048201526024016103b4565b506001600160a01b038085165f908152600187016020908152604080832093871683529290522082905580156105e957826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516105e091815260200190565b60405180910390a35b5050505050565b6001600160a01b038084165f90815260018601602090815260408083209386168352929052908120545f198114610670578381848082101561065e57604051630c95cf2760e11b81526001600160a01b039093166004840152602483019190915260448201526064016103b4565b5050506106708686868685035f610502565b50600195945050505050565b5f6001600160a01b0384166106b0576040516313053d9360e21b81526001600160a01b0390911660048201526024016103b4565b505f6001600160a01b0383166106e557604051639cfea58360e01b81526001600160a01b0390911660048201526024016103b4565b506106f2848484846106f8565b50505050565b6001600160a01b0383166107245780846003015f8282546107199190610c22565b9091555061079a9050565b6001600160a01b0383165f90815260208590526040902054838183808210156107795760405163db42144d60e01b81526001600160a01b039093166004840152602483019190915260448201526064016103b4565b5050506001600160a01b0384165f9081526020869052604090209082900390555b6001600160a01b0382166107b85760038401805482900390556107d6565b6001600160a01b0382165f9081526020859052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068
feat : Slashing integration in EigenLayer and Datahaven AVS (#345) ## 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
2026-01-16 19:49:45 +00:00
"storage": {}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"15": {
"address": "0x610178dA211FEF7D417bC0e6FeD39F05609AD788",
"code": "0x608060405260043610610079575f3560e01c80639623609d1161004c5780639623609d1461010957806399a88ec41461011c578063f2fde38b1461013b578063f3b7dead1461015a575f5ffd5b8063204e1c7a1461007d578063715018a6146100b85780637eff275e146100ce5780638da5cb5b146100ed575b5f5ffd5b348015610088575f5ffd5b5061009c610097366004610479565b610179565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c3575f5ffd5b506100cc610204565b005b3480156100d9575f5ffd5b506100cc6100e836600461049b565b610217565b3480156100f8575f5ffd5b505f546001600160a01b031661009c565b6100cc6101173660046104e6565b61027a565b348015610127575f5ffd5b506100cc61013636600461049b565b6102e5565b348015610146575f5ffd5b506100cc610155366004610479565b61031b565b348015610165575f5ffd5b5061009c610174366004610479565b610399565b5f5f5f836001600160a01b031660405161019d90635c60da1b60e01b815260040190565b5f60405180830381855afa9150503d805f81146101d5576040519150601f19603f3d011682016040523d82523d5f602084013e6101da565b606091505b5091509150816101e8575f5ffd5b808060200190518101906101fc91906105bd565b949350505050565b61020c6103bd565b6102155f610416565b565b61021f6103bd565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b5f604051808303815f87803b158015610260575f5ffd5b505af1158015610272573d5f5f3e3d5ffd5b505050505050565b6102826103bd565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906102b290869086906004016105d8565b5f604051808303818588803b1580156102c9575f5ffd5b505af11580156102db573d5f5f3e3d5ffd5b5050505050505050565b6102ed6103bd565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe690602401610249565b6103236103bd565b6001600160a01b03811661038d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61039681610416565b50565b5f5f5f836001600160a01b031660405161019d906303e1469160e61b815260040190565b5f546001600160a01b031633146102155760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610384565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381168114610396575f5ffd5b5f60208284031215610489575f5ffd5b813561049481610465565b9392505050565b5f5f604083850312156104ac575f5ffd5b82356104b781610465565b915060208301356104c781610465565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b5f5f5f606084860312156104f8575f5ffd5b833561050381610465565b9250602084013561051381610465565b9150604084013567ffffffffffffffff81111561052e575f5ffd5b8401601f8101861361053e575f5ffd5b803567ffffffffffffffff811115610558576105586104d2565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610587576105876104d2565b60405281815282820160200188101561059e575f5ffd5b816020840160208301375f602083830101528093505050509250925092565b5f602082840312156105cd575f5ffd5b815161049481610465565b60018060a01b0383168152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f830116840101915050939250505056fea2646970667358221220d1857c1d79adf09a4456300c200565d4db0d5bcc151c34d3d6a7ed403fb9defd64736f6c634300081c003300",
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000015d34aaf54267db7d7c367839aaf71a00a2c6a65"
}
},
"16": {
"address": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
"code": "0x73e7f1725e7734ce288f8367e1bb143e90bb3f0512301460806040526004361061009b575f3560e01c80632a6c32291161006e5780632a6c322914610191578063805ce31d146101c5578063928bc49d146101db57806399056fcc146101ee578063fe61cc491461020d575f5ffd5b80630705f4651461009f57806309824a80146100c85780630b617646146100e957806326aa101f1461014a575b5f5ffd5b6100b26100ad366004611fdf565b61026c565b6040516100bf919061200a565b60405180910390f35b8180156100d3575f5ffd5b506100e76100e236600461203a565b610282565b005b7f59ef95eb9983b1a4650e1bc666384b8507689fc8aca3edd429d7e07c0ca9d2f6547f59ef95eb9983b1a4650e1bc666384b8507689fc8aca3edd429d7e07c0ca9d2f754604080519283526001600160801b039091166020830152016100bf565b61018161015836600461203a565b6001600160a01b03165f9081525f5160206125e85f395f51905f52602052604090205460ff1690565b60405190151581526020016100bf565b6101a461019f366004611fdf565b61033b565b6040805167ffffffffffffffff9384168152929091166020830152016100bf565b6101cd61036a565b6040519081526020016100bf565b6101cd6101e936600461207c565b610380565b8180156101f9575f5ffd5b506100e76102083660046120bc565b6103e0565b61025461021b366004611fdf565b5f9081527f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c23260205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020016100bf565b5f5f61027783610494565b5460ff169392505050565b5f5160206125e85f395f51905f52610299826104ef565b60408051608081019091526001820154600160a01b900463ffffffff1681525f90602081016102c6610586565b815260028401546020909101906102e79086906001600160801b03166105e7565b81525f6020918201526040516001600160a01b03861681529192507ff78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7e910160405180910390a161033681610632565b505050565b5f5f5f61034784610494565b5467ffffffffffffffff6101008204811696600160481b90920416945092505050565b5f61037b610376610586565b610836565b905090565b6001600160a01b0383165f9081525f5160206125e85f395f51905f52602081905260408220805460ff166103c75760405163259ba1ad60e01b815260040160405180910390fd5b6103d461037686866108c7565b925050505b9392505050565b5f5160206125e85f395f51905f526001600160801b0382165f036104175760405163162908e360e11b815260040160405180910390fd5b6001600160a01b0387165f908152602082905260409020805460ff166104505760405163259ba1ad60e01b815260040160405180910390fd5b60018101546104745761046f61046a8989898989896109ae565b610632565b61048a565b61048a61046a82600101548a8a8a8a8a8a610b97565b5050505050505050565b5f8181527e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ac6020526040902060018101546001600160a01b03166104ea57604051636ddd9da960e01b815260040160405180910390fd5b919050565b610501816001600160a01b0316610cf9565b61051e5760405163c1ab6dc160e01b815260040160405180910390fd5b6001600160a01b0381165f9081525f5160206125e85f395f51905f5260208190526040909120805460ff168015610559575061055981610d3f565b1561057757604051633ea7ffd960e11b815260040160405180910390fd5b805460ff191660011790555050565b604080518082019091527f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c230546001600160801b031681527f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c23154602082015290565b60605f6105f346610d53565b5f6105fd86610dbc565b61060686610ded565b60405160200161061a959493929190612161565b60405160208183030381529060405290505b92915050565b805160408051637061726160e01b60208083019190915260e09390931b6001600160e01b031916602482015281516008818303018152602890910190915280519101205f61067f82610494565b905061068a81610e8c565b5f6106988460200151610836565b90505f84606001516001600160801b0316826106b491906121c4565b9050803410156106d757604051631c0b171360e31b815260040160405180910390fd5b60608501516001600160801b0316156107225761072285606001516001600160801b031661070f5f5160206125e85f395f51905f5290565b600101546001600160a01b031690610f08565b825461074090600160481b900467ffffffffffffffff1660016121d7565b835467ffffffffffffffff91909116600160481b0270ffffffffffffffff000000000000000000199091161783555f61077982346121f7565b9050610783610f31565b811115610794576107943382610f08565b83546040805160208101889052600160481b90920460c01b6001600160c01b031916908201525f9060480160405160208183030381529060405280519060200120905080867f7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b057
"storage": {}
},
"25": {
"address": "0x36C02dA8a0983159322a80FFE9F24b1acfF8B570",
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"code": "0x608060405260043610610195575f3560e01c8063a98fb355116100e7578063ceb29d6111610087578063e2148f5a11610062578063e2148f5a14610492578063f2fde38b146104b1578063fc299dee146104d0578063fe776c2a146104ef575f5ffd5b8063ceb29d611461042b578063d156b9111461044a578063d4c250081461045e575f5ffd5b8063be6ab6ef116100c2578063be6ab6ef146103ad578063c1a8e2c5146103ce578063c63fd502146103ed578063c968095b1461040c575f5ffd5b8063a98fb35514610337578063a9a899cd14610356578063b526578714610375575f5ffd5b8063715018a6116101525780638da5cb5b1161012d5780638da5cb5b146102c05780638f661996146102dd5780638f8ee552146102f0578063a831570514610318575f5ffd5b8063715018a61461026e57806373fe4ad81461028257806383821e8e146102a1575f5ffd5b80631500cd8d146101995780632fb31ef1146101ba578063303ca956146101f05780633bc28c8c1461020f57806357e443551461022e57806359b005341461024f575b5f5ffd5b3480156101a4575f5ffd5b506101b86101b3366004611eb6565b61051d565b005b3480156101c5575f5ffd5b506067546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101fb575f5ffd5b506101b861020a366004611f18565b610595565b34801561021a575f5ffd5b506101b8610229366004611eb6565b6106be565b348015610239575f5ffd5b5061024261073e565b6040516101e79190611fa6565b34801561025a575f5ffd5b506101b8610269366004611eb6565b61094b565b348015610279575f5ffd5b506101b86109d0565b34801561028d575f5ffd5b506101b861029c366004612068565b6109e3565b3480156102ac575f5ffd5b506101b86102bb36600461213c565b610d73565b3480156102cb575f5ffd5b506033546001600160a01b03166101d3565b6101b86102eb366004612188565b610f9a565b3480156102fb575f5ffd5b506103035f81565b60405163ffffffff90911681526020016101e7565b348015610323575f5ffd5b506101b86103323660046121b9565b61105a565b348015610342575f5ffd5b506101b861035136600461226a565b6110e5565b348015610361575f5ffd5b506101b8610370366004611eb6565b611164565b348015610380575f5ffd5b5061039d61038f366004611eb6565b6001600160a01b0316301490565b60405190151581526020016101e7565b3480156103b8575f5ffd5b506103c16111b4565b6040516101e7919061229b565b3480156103d9575f5ffd5b506101b86103e83660046122e6565b61125c565b3480156103f8575f5ffd5b506101b8610407366004612336565b611328565b348015610417575f5ffd5b506101b86104263660046121b9565b6114d2565b348015610436575f5ffd5b506101b86104453660046121b9565b61152c565b348015610455575f5ffd5b50610242611792565b348015610469575f5ffd5b506101d3610478366004611eb6565b60686020525f90815260409020546001600160a01b031681565b34801561049d575f5ffd5b506101b86104ac366004611eb6565b6117ae565b3480156104bc575f5ffd5b506101b86104cb366004611eb6565b611828565b3480156104db575f5ffd5b506065546101d3906001600160a01b031681565b3480156104fa575f5ffd5b5061039d610509366004611eb6565b60666020525f908152604090205460ff1681565b6105256118a1565b6001600160a01b03811661054c5760405163d92e233d60e01b815260040160405180910390fd5b606780546001600160a01b0319166001600160a01b0383169081179091556040517f6a8a174b559440c4e231f06fda7f0eb644f79306c33292fbb95f7602bef9aaf9905f90a250565b61059d6118fb565b6001600160a01b03831630146105c657604051631280731d60e21b815260040160405180910390fd5b600181146105e75760405163f37f411760e01b815260040160405180910390fd5b5f828282816105f8576105f86123f5565b905060200201602081019061060d919061241c565b63ffffffff16146106315760405163c106a33360e01b815260040160405180910390fd5b6001600160a01b0384165f90815260686020526040812080546001600160a01b03191690558290829081610667576106676123f5565b905060200201602081019061067c919061241c565b63ffffffff16846001600160a01b03167f2638d53da645bac898f1b50bd1d6d2a4d389e3141e209c988488abced5c3c54c60405160405180910390a350505050565b6106c66118a1565b6001600160a01b0381166106ed5760405163d92e233d60e01b815260040160405180910390fd5b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907fa499ec18d14a183a8ce150f6d1a61fe68e989121c8aa695bafde5305f1eee81c905f90a35050565b6040805180820182523081525f602082018190529151633743aedd60e11b8152606092907f00000000000000000000000068b1d87f95878fe05b998f19b66f4baba5de1aed6001600160a01b031690636e875dba906107a1908590600401612435565b5f60405180830381865afa1580156107bb573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526107e2919081019061245d565b90505f81516001600160401b038111156107fe5761
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
2026-01-12 15:55:46 +00:00
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"32": {
"address": "0x998abeb3E57409262aE5b751f60747921B33613E",
"code": "0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f5ffd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f5f375f5f365f845af43d5f5f3e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f5f856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f5f85851115610676575f5ffd5b83861115610682575f5ffd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f5ffd5b919050565b5f602082840312156106ba575f5ffd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e8575f5ffd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f5ffd5b8301601f8101851361071c575f5ffd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c657665
2026-01-12 15:55:46 +00:00
"storage": {
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788",
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000032": "0x00000000000000000000000095401dc811bb5740090279ba06cfa8fcf6113778",
"0x0000000000000000000000000000000000000000000000000000000000000064": "0x00000000000000000000000000000000000000000000d3c21bcecceda1000000",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001",
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000065": "0x000000000000000000000000000000000000000000084595161401484a000000",
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000f5059a5d33d5853360d16c683c16e67980206f36"
2026-01-12 15:55:46 +00:00
}
refactor: cleanup old rewards model (#383) ## Summary This PR removes the old merkle root-based rewards model and completes the migration to EigenLayer Rewards V2 distribution. The old model required operators to claim rewards by providing merkle proofs, while the new model uses `submitRewards` to send rewards directly to EigenLayer's `RewardsCoordinator`. ### Key Changes - **Smart Contracts**: Removed `RewardsRegistry`, `RewardsRegistryStorage`, `IRewardsRegistry`, and `SortedMerkleProof` contracts along with all merkle claim functions from `ServiceManagerBase` - **Substrate Pallets**: Removed merkle proof generation from `external-validators-rewards` pallet and deleted the entire `runtime-api` crate (no longer needed) - **Test Framework**: Removed all RewardsRegistry-related code from deployment scripts, CLI handlers, and TypeScript bindings - **Runtimes**: Cleaned up all three runtimes (testnet, stagenet, mainnet) to remove runtime API implementations and unused imports ### Files Removed **Contracts:** - `contracts/src/middleware/RewardsRegistry.sol` - `contracts/src/middleware/RewardsRegistryStorage.sol` - `contracts/src/interfaces/IRewardsRegistry.sol` - `contracts/src/libraries/SortedMerkleProof.sol` - `contracts/test/RewardsRegistry.t.sol` - `contracts/test/ServiceManagerRewardsRegistry.t.sol` **Substrate:** - `operator/pallets/external-validators-rewards/runtime-api/` (entire crate) **Test Framework:** - `test/suites/rewards-message.test.ts` ### Files Modified **Contracts:** - `ServiceManagerBase.sol` - Removed merkle claim functions - `ServiceManagerBaseStorage.sol` - Removed `operatorSetToRewardsRegistry` mapping - `IServiceManager.sol` - Removed interface members **Substrate:** - `external-validators-rewards` pallet - Removed merkle proof generation, simplified `EraRewardsUtils` struct - All runtime configs - Removed `ExternalValidatorsRewardsApi` implementations **Test Framework:** - Updated deployment scripts, CLI handlers, relayer configs, and TypeScript bindings ### Stats ``` 50 files changed, 966 insertions(+), 4453 deletions(-) ``` ## Test plan - [x] All Rust tests pass (`cargo test`) - [x] All contract tests pass (`forge test`) - [x] TypeScript type checking passes (`bun typecheck`) - [x] Contracts build successfully (`forge build`) - [x] Operator builds successfully (`cargo build --release --features fast-runtime`) - [ ] E2E tests pass (`bun test:e2e`)
2026-01-09 14:25:49 +00:00
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"10": {
"address": "0xf5059a5D33d5853360D16C683c16e67980206f36",
"code": "0x608060405234801561000f575f5ffd5b5060043610610187575f3560e01c80637a8b2637116100d9578063c4d66de811610093578063df6fadc11161006e578063df6fadc114610361578063e3dae51c1461037c578063f3e738751461038f578063fabc1cbc146103a2575f5ffd5b8063c4d66de814610328578063ce7c2ac21461033b578063d9caed121461034e575f5ffd5b80637a8b2637146102ad578063886f1195146102c05780638c871019146102e75780638f6a6240146102fa578063a6ab36f21461030d578063ab5921e114610320575f5ffd5b806347e7ef2411610144578063595c6a671161011f578063595c6a67146102655780635ac86ab71461026d5780635c975abb1461029c57806361b01b5d146102a4575f5ffd5b806347e7ef241461022a57806354fd4d501461023d578063553ca5f814610252575f5ffd5b806311c70c9d1461018b578063136439dd146101a05780632495a599146101b357806339b70e38146101e35780633a98ef391461020a57806343fe08b014610221575b5f5ffd5b61019e6101993660046111b1565b6103b5565b005b61019e6101ae3660046111d1565b6103cb565b6032546101c6906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101c67f0000000000000000000000009a676e781a523b5d0c0e43731313a708cb60750881565b61021360335481565b6040519081526020016101da565b61021360645481565b6102136102383660046111fc565b610401565b610245610530565b6040516101da9190611226565b61021361026036600461125b565b610560565b61019e610573565b61028c61027b36600461128b565b6001805460ff9092161b9081161490565b60405190151581526020016101da565b600154610213565b61021360655481565b6102136102bb3660046111d1565b610587565b6101c67f000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e81565b6102136102f53660046111d1565b6105d0565b61021361030836600461125b565b6105da565b61019e61031b3660046112a6565b6105e7565b6102456106c2565b61019e61033636600461125b565b6106e2565b61021361034936600461125b565b6107a8565b61021361035c3660046112dc565b61083a565b606454606554604080519283526020830191909152016101da565b61021361038a3660046111d1565b61093c565b61021361039d3660046111d1565b610973565b61019e6103b03660046111d1565b61097d565b6103bd6109ea565b6103c78282610a9b565b5050565b6103d3610b3f565b60015481811681146103f85760405163c61dca5d60e01b815260040160405180910390fd5b6103c782610be2565b5f5f61040c81610c1f565b336001600160a01b037f0000000000000000000000009a676e781a523b5d0c0e43731313a708cb6075081614610455576040516348da714f60e01b815260040160405180910390fd5b61045f8484610c55565b6033545f61046f6103e88361132e565b90505f6103e861047d610cac565b610487919061132e565b90505f6104948783611341565b9050806104a18489611354565b6104ab919061136b565b9550855f036104cd57604051630c392ed360e11b815260040160405180910390fd5b6104d7868561132e565b60338190556f4b3b4ca85a86c47a098a223fffffffff101561050c57604051632f14e8a360e11b815260040160405180910390fd5b610525826103e8603354610520919061132e565b610d16565b505050505092915050565b606061055b7f76312e302e300000000000000000000000000000000000000000000000000006610d62565b905090565b5f61056d6102bb836107a8565b92915050565b61057b610b3f565b6105855f19610be2565b565b5f5f6103e8603354610599919061132e565b90505f6103e86105a7610cac565b6105b1919061132e565b9050816105be8583611354565b6105c8919061136b565b949350505050565b5f61056d8261093c565b5f61056d61039d836107a8565b5f54610100900460ff161580801561060557505f54600160ff909116105b8061061e5750303b15801561061e57505f5460ff166001145b6106435760405162461bcd60e51b815260040161063a9061138a565b60405180910390fd5b5f805460ff191660011790558015610664575f805461ff0019166101001790555b61066e8484610a9b565b61067782610d9f565b80156106bc575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b60606040518060800160405280604d815260200161145b604d9139905090565b5f54610100900460ff161580801561070057505f54600160ff909116105b806107195750303b15801561071957505f5460ff166001145b6107355760405162461bcd60e51b815260040161063a9061138a565b5f805460ff191660011790558015610756575f805461ff0019166101001790555b61075f82610d9f565b80156103c7575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b60405163fe243a1760e01b81526001600160a01b0382811660048301523060248301525f917f0000000000000000000000009a676e781a523b5d0c0e43731313a708cb6075089091169063fe243a17
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"40": {
"address": "0xc5a5C42992dECbae36851359345FE25997F5C42d",
"code": "0x608060405234801561000f575f5ffd5b50600436106102ff575f3560e01c8063670d3ba211610195578063b2447af7116100e4578063db4df7611161009e578063f231bd0811610079578063f231bd08146107f7578063f605ce081461080a578063fabc1cbc1461081d578063fe4b84df14610830575f5ffd5b8063db4df76114610796578063dc2af692146107bd578063df5cf723146107d0575f5ffd5b8063b2447af714610708578063b66bd9891461071b578063b9fbaed11461072e578063ba1a84e51461075d578063c221d8ae14610770578063d3d96ff414610783575f5ffd5b8063886f11951161014f578063952899ee1161012a578063952899ee146106bc578063a9333ec8146106cf578063a9821821146106e2578063adc2e3d9146106f5575f5ffd5b8063886f1195146106625780638ce648541461068957806394d7d00c146106a9575f5ffd5b8063670d3ba2146105c45780636cfb4481146105d75780636e3492b5146106025780636e875dba1461061557806379ae50cd146106285780637bc1ef611461063b575f5ffd5b806340120dab1161025157806350feea201161020b57806356c483e6116101e657806356c483e61461057e578063595c6a67146105915780635ac86ab7146105995780635c975abb146105bc575f5ffd5b806350feea2014610543578063547afb871461055657806354fd4d5014610569575f5ffd5b806340120dab146104875780634177a87c146104a85780634657e26a146104c85780634a10ffe5146104ef5780634b5046ef1461050f5780634cfd293914610522575f5ffd5b8063261f84e0116102bc5780632bab2c4a116102975780632bab2c4a1461042d578063304c10cd1461044057806332a879e4146104535780633635205714610466575f5ffd5b8063261f84e0146103be5780632981eb77146103d15780632b453a9a1461040d575f5ffd5b80630f3df50e1461030357806310e1b9b8146103335780631352c3e614610353578063136439dd1461037657806315fe50281461038b578063260dc758146103ab575b5f5ffd5b610316610311366004614bf0565b610843565b6040516001600160a01b0390911681526020015b60405180910390f35b610346610341366004614c0a565b610884565b60405161032a9190614c51565b610366610361366004614c84565b6108bd565b604051901515815260200161032a565b610389610384366004614cb8565b610938565b005b61039e610399366004614ccf565b610972565b60405161032a9190614d4d565b6103666103b9366004614bf0565b610a89565b6103896103cc366004614d9f565b610aba565b6103f87f000000000000000000000000000000000000000000000000000000000000003281565b60405163ffffffff909116815260200161032a565b61042061041b366004614e84565b610b63565b60405161032a9190614f27565b61042061043b366004614f8a565b610b79565b61031661044e366004614ccf565b610c18565b61038961046136600461500e565b610c47565b61047961047436600461508e565b610d8e565b60405161032a9291906150e0565b61049a6104953660046150f8565b610ed1565b60405161032a929190615185565b6104bb6104b6366004614bf0565b61104c565b60405161032a91906151e2565b6103167f0000000000000000000000003aa5ebb10dc797cac828524e59a333d0a371443c81565b6105026104fd3660046151f4565b611070565b60405161032a9190615237565b61038961051d36600461500e565b611118565b610535610530366004614bf0565b6111ab565b60405190815260200161032a565b610389610551366004615282565b6111cd565b6105026105643660046152e0565b6112be565b610571611366565b60405161032a9190615322565b61038961058c366004615357565b611396565b61038961149b565b6103666105a7366004615381565b606654600160ff9092169190911b9081161490565b606654610535565b6103666105d2366004614c84565b6114af565b6105ea6105e53660046150f8565b6114db565b6040516001600160401b03909116815260200161032a565b6103896106103660046153b7565b6114f0565b6104bb610623366004614bf0565b6118b3565b61039e610636366004614ccf565b6118c4565b6103f87f000000000000000000000000000000000000000000000000000000000000004b81565b6103167f000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e81565b61069c6106973660046153e8565b61199e565b60405161032a919061542b565b6105026106b736600461543d565b611a5a565b6103896106ca366004615498565b611b46565b6105ea6106dd3660046150f8565b611fe7565b6103896106f0366004615641565b612016565b6103896107033660046156bf565b6120c8565b610535610716366004614bf0565b612411565b610389610729366004615282565b612433565b61074161073c366004614ccf565b61258d565b60408051921515835263ffffffff90911660208301520161032a565b61053561076b366004614ccf565b612627565b6104bb61077e366004614c84565b612647565b6103896107913660046150f8565b612670565b6103167f000000000000000000000000c6e7df5e7b4f2a278906862b61205850344d4e7d81565b6103666107cb366004614ccf565b61279d565b6103167f0000000000000000000000000dcd1bf9a1b36ce34237eeafef220932846bcd8281565b
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
refactor: Remove eigenlayer-middleware and flatten ServiceManagerBase (#389) ## Summary - Flatten `ServiceManagerBase` middleware layer directly into `DataHavenServiceManager` - Remove all unused EigenLayer integration code to keep the contract minimal - Fix access control on `deregisterOperatorFromOperatorSets` (was missing `onlyOwner`) ## Motivation The `ServiceManagerBase` from eigenlayer-middleware was designed for the old `AVSDirectory` model and included many generic functions DataHaven doesn't use. This refactor: - Reduces code complexity and contract size - Removes ~200 lines of unused code - Makes the codebase easier to audit and maintain - Keeps only what DataHaven actually needs ## Changes ### Architecture Before: DataHavenServiceManager → ServiceManagerBase → ServiceManagerBaseStorage → OwnableUpgradeable After: DataHavenServiceManager → OwnableUpgradeable, IAVSRegistrar, IDataHavenServiceManager ### Removed (unused) - `IServiceManager` and `IServiceManagerUI` interfaces (old AVSDirectory model) - `ServiceManagerBase` and `ServiceManagerBaseStorage` middleware - `PermissionController` integration (5 proxy functions) - `createOperatorSets()` - only needed at initialization - `avs()` - never called ### Kept (with fixes) - `deregisterOperatorFromOperatorSets()` - added `onlyOwner` modifier (security fix) - `updateAVSMetadataURI()` - needed for EigenLayer registration ### Files Deleted - `src/interfaces/IServiceManager.sol` - `src/interfaces/IServiceManagerUI.sol` - `src/middleware/ServiceManagerBase.sol` - `src/middleware/ServiceManagerBaseStorage.sol` - `test/mocks/ServiceManagerMock.sol` - `test/ServiceManagerBase.t.sol` ## Test Plan - [x] `forge build` passes - [x] `forge test` - all 10 tests pass - [x] Contract bindings regenerated - [x] State diff regenerated
2026-01-13 14:03:10 +00:00
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"9": {
"address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
"code": "0x735fc8d32690cc91d4c39d9d3abcbd16989f875707301460806040526004361061006b575f3560e01c8063017b73111461006f578063253946451461009057806365529675146100af5780638257f3d5146100ce578063ae8a4d98146100ed578063fe1aa59d1461010c575b5f5ffd5b81801561007a575f5ffd5b5061008e61008936600461080c565b61012b565b005b81801561009b575f5ffd5b5061008e6100aa36600461080c565b610155565b8180156100ba575f5ffd5b5061008e6100c9366004610860565b6101db565b8180156100d9575f5ffd5b5061008e6100e836600461080c565b610267565b8180156100f8575f5ffd5b5061008e61010736600461080c565b6102f8565b818015610117575f5ffd5b5061008e6101263660046108ae565b610328565b5f610138828401846109a7565b9050610150815f0151826020015183604001516103a5565b505050565b5f61016282840184610a68565b80516020820151604080840151905163a3499c7360e01b8152939450732279b7a0a67db372996a5fab50d91eaa73d2ebe69363a3499c73936101aa9390929091600401610b1b565b5f6040518083038186803b1580156101c0575f5ffd5b505af41580156101d2573d5f5f3e3d5ffd5b50505050505050565b5f6101e882840184610b4a565b90505f6102147f81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b79610414565b82519091506001600160a01b0316610248576102438582846020015185604001516001600160801b031661046c565b610260565b6102608582845f0151856020015186604001516104c9565b5050505050565b5f61027482840184610b7b565b80517e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ab805492935091829060ff1916600183818111156102b5576102b5610bc9565b021790555081516040517f4016a1377b8961c4aa6f3a2d3de830a685ddbfe0f228ffc0208eb96304c4cf1a916102ea91610bdd565b60405180910390a150505050565b5f61030582840184610c03565b9050610322815f015182602001518360400151846060015161052e565b50505050565b5f61033582840184610cbd565b90505f61034186610414565b90505f825f01518360200151846040015160405160240161036493929190610d45565b60408051601f198184030181529190526020810180516001600160e01b031663c6b295c160e01b179052905061039b828783610679565b5050505050505050565b5f6103af84610705565b6040516340c10f1960e01b81526001600160a01b0385811660048301526001600160801b0385166024830152919250908216906340c10f19906044015f604051808303815f87803b158015610402575f5ffd5b505af115801561039b573d5f5f3e3d5ffd5b5f8181527e96e2f02350077f4ff1746770dbe5db3c04b7db2c8763c8fc21bf66b35e96ad60205260409020546001600160a01b0316806104675760405163d3227c9b60e01b815260040160405180910390fd5b919050565b6040516001600160a01b0383166024820152604481018290525f9060640160408051601f198184030181529190526020810180516001600160e01b03166305b1137b60e01b17905290506104c1848683610679565b505050505050565b6040516001600160a01b038085166024830152831660448201526001600160801b03821660648201525f9060840160408051601f198184030181529190526020810180516001600160e01b03166309733b7b60e21b17905290506101d2858783610679565b5f8481527f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c23260205260408120547f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c22e906001600160a01b0316156105a457604051633ea7ffd960e11b815260040160405180910390fd5b5f8585856040516105b4906107bb565b6105c093929190610d78565b604051809103905ff0801580156105d9573d5f5f3e3d5ffd5b50604080518082018252600180825260208083018c81525f8d815260048901835285812080546001600160a01b0319166001600160a01b038916908117909155808252898452908690208551815460ff19169015151781559151919093015592519081529293509189917f57f58171b8777633d03aff1e7408b96a3d910c93a7ce433a8cb7fb837dc306a6910160405180910390a2509695505050505050565b60605f5f856001600160a01b0316639bb66b2886866040518363ffffffff1660e01b81526004016106ab929190610db0565b5f604051808303815f875af11580156106c6573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106ed9190810190610ddb565b915091506106fb8282610796565b9695505050505050565b5f8181527f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c23260205260408120547f8d3b47662f045c362f825b520d7ddf7a0e5f6703a828606de6840b3652b8c22e906001600160a01b031661077a5760405163259ba1ad60e01b815260040160405180910390fd5b5f9283526004016020525060409020546001600160a01b031690565b606082156107a55750806107b5565b81511561006b5781518083602001fd5b92915050565b610c3580610e6883390190565b5f5f83601f8401126107d8575f5ffd5b5081356001600160401b038111156107ee575f5ffd5b602083019150836020
"storage": {}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"43": {
"address": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9",
"code": "0x73cf7ed3acca5a467e9e704c703e8d87f634fb0fc93014608060405260043610610034575f3560e01c8063d3b08db814610038575b5f5ffd5b61004b610046366004610370565b610061565b6040516100589190610465565b60405180910390f35b805180516060915f83815b83518163ffffffff1610156101065781848263ffffffff16815181106100945761009461049a565b60200260200101516040516020016100c4919060609190911b6bffffffffffffffffffffffff1916815260140190565b60408051601f19818403018152908290526100e292916020016104c5565b604051602081830303815290604052915080806100fe906104f5565b91505061006c565b50630e02a00760e31b5f8061011a876101ac565b8465ff000000ff00600888811b91821664ff000000ff918a901c91821617601090811b67ff000000ff0000009390931666ff000000ff00009290921691909117901c17602081811b6bffffffffffffffff000000001691901c63ffffffff161760c01b60405160200161019296959493929190610519565b604051602081830303815290604052945050505050919050565b6060603f8263ffffffff16116101e957604051603f60fa1b60fa84901b1660208201526021015b6040516020818303038152906040529050919050565b613fff8263ffffffff1611610248576102256102116403fffffffc600285901b166001610572565b600881811b62ffff001691901c60ff161790565b6040516020016101d3919060f09190911b6001600160f01b031916815260020190565b633fffffff8263ffffffff16116102ba5761029760028363ffffffff16901b60026102739190610572565b600881811c62ff00ff1663ff00ff009290911b9190911617601081811c91901b1790565b6040516020016101d3919060e09190911b6001600160e01b031916815260040190565b604051600360f81b60208201526001600160e01b0319600884811c62ff00ff1663ff00ff009186901b9190911617601081811c91901b1760e01b1660218201526025016101d3565b634e487b7160e01b5f52604160045260245ffd5b6040516020810167ffffffffffffffff8111828210171561033957610339610302565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561036857610368610302565b604052919050565b5f60208284031215610380575f5ffd5b813567ffffffffffffffff811115610396575f5ffd5b8201602081850312156103a7575f5ffd5b6103af610316565b813567ffffffffffffffff8111156103c5575f5ffd5b80830192505084601f8301126103d9575f5ffd5b813567ffffffffffffffff8111156103f3576103f3610302565b8060051b6104036020820161033f565b9182526020818501810192908101908884111561041e575f5ffd5b6020860195505b8386101561045757853592506001600160a01b0383168314610445575f5ffd5b82825260209586019590910190610425565b845250919695505050505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52603260045260245ffd5b5f81518060208401855e5f93019283525090919050565b5f6104d96104d383866104ae565b846104ae565b949350505050565b634e487b7160e01b5f52601160045260245ffd5b5f63ffffffff821663ffffffff8103610510576105106104e1565b60010192915050565b6001600160e01b0319871681526001600160f81b03198681166004830152851660058201525f61055561054f60068401876104ae565b856104ae565b6001600160c01b0319939093168352505060080195945050505050565b63ffffffff818116838216019081111561058e5761058e6104e1565b9291505056fea2646970667358221220ec754a565932b22e059c17b06dbd28b7721de4df0054b69f4983510c827d2c9364736f6c634300081c0033000000000000000000000000000000000000",
"storage": {}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"34": {
"address": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE",
"code": "0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f5ffd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f5f375f5f365f845af43d5f5f3e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f5f856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f5f85851115610676575f5ffd5b83861115610682575f5ffd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f5ffd5b919050565b5f602082840312156106ba575f5ffd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e8575f5ffd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f5ffd5b8301601f8101851361071c575f5ffd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c657665
refactor(contracts): Harden DataHavenServiceManager with input validation and code cleanup (#395) ## Summary - Add zero address validation across all functions that accept address parameters to prevent misconfiguration - Fix race condition in `buildNewValidatorSetMessage()` that could cause reverts during validator deregistration - Refactor contract for improved readability and reduced code duplication - Update AVS metadata URL to point to the correct hosted JSON file ## Changes ### Security & Validation - Add `ZeroAddress` error and validate all address inputs in `initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`, `addValidatorToAllowlist`, `registerOperator`, and `updateSolochainAddressForValidator` - Fix race condition: filter out zero solochain addresses in `buildNewValidatorSetMessage()` to prevent reverts when a validator is mid-deregistration ### Refactoring - Replace verbose `if/revert` patterns with `require` statements for consistency - Inline single-use internal functions (`_createDataHavenOperatorSets`, `_setRewardsInitiator`) - Consolidate duplicate error types into single `ZeroAddress` error - Rename `initialise` → `initialize` to maintain consistency with the transparent upgradability pattern - Optimize validator set message encoding by removing redundant wrapper function ### Observability - Add `SolochainAddressUpdated` event for tracking validator address changes ### Cleanup - Remove unused remappings from `foundry.toml` - Fix typo in metadata description --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
2026-01-20 10:32:32 +00:00
"storage": {
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x00000000000000000000000009635f643e140090a9a8dcd712ed6285858cebef",
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788",
"0x00000000000000000000000000000000000000000000000000000000000000cb": "0x000003e80000000000001c2090f79bf6eb2c4f870365e785982e1f101e93b906",
"0x0000000000000000000000000000000000000000000000000000000000000033": "0x00000000000000000000000015d34aaf54267db7d7c367839aaf71a00a2c6a65"
refactor(contracts): Harden DataHavenServiceManager with input validation and code cleanup (#395) ## Summary - Add zero address validation across all functions that accept address parameters to prevent misconfiguration - Fix race condition in `buildNewValidatorSetMessage()` that could cause reverts during validator deregistration - Refactor contract for improved readability and reduced code duplication - Update AVS metadata URL to point to the correct hosted JSON file ## Changes ### Security & Validation - Add `ZeroAddress` error and validate all address inputs in `initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`, `addValidatorToAllowlist`, `registerOperator`, and `updateSolochainAddressForValidator` - Fix race condition: filter out zero solochain addresses in `buildNewValidatorSetMessage()` to prevent reverts when a validator is mid-deregistration ### Refactoring - Replace verbose `if/revert` patterns with `require` statements for consistency - Inline single-use internal functions (`_createDataHavenOperatorSets`, `_setRewardsInitiator`) - Consolidate duplicate error types into single `ZeroAddress` error - Rename `initialise` → `initialize` to maintain consistency with the transparent upgradability pattern - Optimize validator set message encoding by removing redundant wrapper function ### Observability - Add `SolochainAddressUpdated` event for tracking validator address changes ### Cleanup - Remove unused remappings from `foundry.toml` - Fix typo in metadata description --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
2026-01-20 10:32:32 +00:00
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"5": {
"address": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318",
"code": "0x738a791620dd6260079bf849dc5567adc3f2fdc3183014608060405260043610610090575f3560e01c8063ab55562e11610063578063ab55562e146100fd578063af18d14214610105578063c82b5f451461010d578063ded905d514610115575f5ffd5b80632db726161461009457806379d0e91c146100bc5780637cb1a954146100e05780639ce504ff146100f6575b5f5ffd5b6100a76100a23660046109da565b61011c565b60405190151581526020015b60405180910390f35b6100c7600160f81b81565b6040516001600160f81b031990911681526020016100b3565b6100e8600581565b6040519081526020016100b3565b6100c75f81565b6100e8600681565b6100e8600481565b6100e8600881565b6100e85f81565b5f6101318461012b8580610a64565b84610278565b61013c57505f61026f565b6101496020840184610a82565b6020013583806020019061015d9190610a82565b351061016a57505f61026f565b5f61017e866101798680610a64565b610419565b90505f6101c7826101926020880188610a82565b356101a06020890189610a82565b602001358880602001906101b49190610a82565b6101c2906040810190610a96565b610434565b90505f6101e56101df36889003880160408901610b1d565b836104da565b90506001600160a01b03891663a401662b826102056101008a018a610a96565b8a61012001356040518563ffffffff1660e01b815260040161022a9493929190610bbc565b602060405180830381865afa158015610245573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102699190610c00565b93505050505b95945050505050565b5f5f82610285575f61028b565b600160f81b5b90505f5b61029c6080860186610a96565b905081101561040c575f6102b36080870187610a96565b838181106102c3576102c3610c1b565b90506020028101906102d59190610a82565b3514801561032157506102eb6080860186610a96565b828181106102fb576102fb610c1b565b905060200281019061030d9190610a82565b61031b906040810190610c2f565b90506021145b801561039657506001600160f81b031982166103406080870187610a96565b8381811061035057610350610c1b565b90506020028101906103629190610a82565b610370906040810190610c2f565b5f81811061038057610380610c1b565b9050013560f81c60f81b6001600160f81b031916145b80156103f457506103aa6080860186610a96565b828181106103ba576103ba610c1b565b90506020028101906103cc9190610a82565b6103da906040810190610c2f565b6103e8916001908290610c72565b6103f191610c99565b86145b1561040457600192505050610412565b60010161028f565b505f9150505b9392505050565b5f610424838361062c565b8051906020012090505b92915050565b5f85815b838110156104cf57866001166001148061045457508587600101145b1561048b5761048485858381811061046e5761046e610c1b565b90506020020135835f9182526020526040902090565b91506104b9565b6104b6828686848181106104a1576104a1610c1b565b905060200201355f9182526020526040902090565b91505b600196871c965f19909601861c86019501610438565b509695505050505050565b81515f90819060f81b6105128560200151600881811c62ff00ff1663ff00ff009290911b9190911617601081811c91901b1760e01b90565b856040015161058887606001515f65ff000000ff00600883811b91821664ff000000ff9185901c91821617601090811b67ff000000ff0000009390931666ff000000ff00009290921691909117901c17602081811b6bffffffffffffffff000000001691901c63ffffffff161760c01b92915050565b6080880151600881811b63ff00ff001662ff00ff9290911c9190911617601081811b91901c1760e01b60a08901516040516001600160f81b031990961660208701526001600160e01b0319948516602187015260258601939093526001600160c01b0319909116604585015291909116604d83015260518201526071810184905260910160408051808303601f190181529190528051602090910120949350505050565b60605f823561063e60208501356106b8565b6040850135606086013561065d6106586080890189610a96565b6106e8565b604051602001610671959493929190610ccd565b60405160208183030381529060405290508361068d82516106b8565b826040516020016106a093929190610d00565b60405160208183030381529060405291505092915050565b606063ffffffff8211156106df57604051637404cccd60e11b815260040160405180910390fd5b61042e82610778565b60408051602081019091525f808252606091905b8381101561075c578161073186868481811061071a5761071a610c1b565b905060200281019061072c9190610a82565b6108d3565b604051602001610742929190610d24565b60408051601f1981840301815291905291506001016106fc565b50610766836106b8565b816040516020016106a0929190610d24565b6060603f8263ffffffff16116107b557604051603f60fa1b60fa84901b1660208201526021015b6040516020818303038152906040529050919050565b613fff8263ffffffff1611610814576107f16107dd6403fffffffc600285901b166001610d3a565b600881811b62ffff001691901c60ff161790565b604051602001
2026-01-12 15:55:46 +00:00
"storage": {}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"31": {
"address": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1",
refactor(contracts): Harden DataHavenServiceManager with input validation and code cleanup (#395) ## Summary - Add zero address validation across all functions that accept address parameters to prevent misconfiguration - Fix race condition in `buildNewValidatorSetMessage()` that could cause reverts during validator deregistration - Refactor contract for improved readability and reduced code duplication - Update AVS metadata URL to point to the correct hosted JSON file ## Changes ### Security & Validation - Add `ZeroAddress` error and validate all address inputs in `initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`, `addValidatorToAllowlist`, `registerOperator`, and `updateSolochainAddressForValidator` - Fix race condition: filter out zero solochain addresses in `buildNewValidatorSetMessage()` to prevent reverts when a validator is mid-deregistration ### Refactoring - Replace verbose `if/revert` patterns with `require` statements for consistency - Inline single-use internal functions (`_createDataHavenOperatorSets`, `_setRewardsInitiator`) - Consolidate duplicate error types into single `ZeroAddress` error - Rename `initialise` → `initialize` to maintain consistency with the transparent upgradability pattern - Optimize validator set message encoding by removing redundant wrapper function ### Observability - Add `SolochainAddressUpdated` event for tracking validator address changes ### Cleanup - Remove unused remappings from `foundry.toml` - Fix typo in metadata description --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
2026-01-20 10:32:32 +00:00
"code": "0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f5ffd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f5f375f5f365f845af43d5f5f3e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f5f856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f5f85851115610676575f5ffd5b83861115610682575f5ffd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f5ffd5b919050565b5f602082840312156106ba575f5ffd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e8575f5ffd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f5ffd5b8301601f8101851361071c575f5ffd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c657665
feat : Slashing integration in EigenLayer and Datahaven AVS (#345) ## 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
2026-01-16 19:49:45 +00:00
"storage": {
refactor(contracts): Harden DataHavenServiceManager with input validation and code cleanup (#395) ## Summary - Add zero address validation across all functions that accept address parameters to prevent misconfiguration - Fix race condition in `buildNewValidatorSetMessage()` that could cause reverts during validator deregistration - Refactor contract for improved readability and reduced code duplication - Update AVS metadata URL to point to the correct hosted JSON file ## Changes ### Security & Validation - Add `ZeroAddress` error and validate all address inputs in `initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`, `addValidatorToAllowlist`, `registerOperator`, and `updateSolochainAddressForValidator` - Fix race condition: filter out zero solochain addresses in `buildNewValidatorSetMessage()` to prevent reverts when a validator is mid-deregistration ### Refactoring - Replace verbose `if/revert` patterns with `require` statements for consistency - Inline single-use internal functions (`_createDataHavenOperatorSets`, `_setRewardsInitiator`) - Consolidate duplicate error types into single `ZeroAddress` error - Rename `initialise` → `initialize` to maintain consistency with the transparent upgradability pattern - Optimize validator set message encoding by removing redundant wrapper function ### Observability - Add `SolochainAddressUpdated` event for tracking validator address changes ### Cleanup - Remove unused remappings from `foundry.toml` - Fix typo in metadata description --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
2026-01-20 10:32:32 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001",
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788",
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"0x0000000000000000000000000000000000000000000000000000000000000033": "0x00000000000000000000000015d34aaf54267db7d7c367839aaf71a00a2c6a65",
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000000000000000000000007a2088a1bfc9d81c55368ae168c2c02570cb814f"
feat : Slashing integration in EigenLayer and Datahaven AVS (#345) ## 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
2026-01-16 19:49:45 +00:00
}
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"3": {
"address": "0x09635F643e140090A9A8Dcd712eD6285858ceBef",
"code": "0x608060405234801561000f575f5ffd5b50600436106103b3575f3560e01c8063886f1195116101f5578063de02e50311610114578063f6efbb59116100a9578063fabc1cbc11610079578063fabc1cbc14610a33578063fbf1e2c114610a46578063fce36c7d14610a59578063ff9f6cce14610a6c575f5ffd5b8063f6efbb59146109e7578063f74e8eac146109fa578063f8cd844814610a0d578063f96abf2e14610a20575f5ffd5b8063ed71e6a2116100e4578063ed71e6a214610967578063f22cef8514610994578063f2f07ab4146109a7578063f2fde38b146109d4575f5ffd5b8063de02e50314610907578063e063f81f1461091a578063e810ce211461092d578063ea4d3c9b14610940575f5ffd5b8063a50a1d9c1161018a578063bf21a8aa1161015a578063bf21a8aa14610879578063c46db606146108a0578063ca8aa7c7146108cd578063dcbb03b3146108f4575f5ffd5b8063a50a1d9c14610807578063aebd8bae1461081a578063b3dbb0e014610847578063bb7e451f1461085a575f5ffd5b80639cb9a5fa116101c55780639cb9a5fa146107a75780639d45c281146107ba5780639de4b35f146107e1578063a0169ddd146107f4575f5ffd5b8063886f11951461074c5780638da5cb5b146107735780639104c319146107845780639be3d4e41461079f575f5ffd5b80634596021c116102e15780635c975abb11610276578063715018a611610246578063715018a6146106ff5780637b8f8b0514610707578063863cb9a91461070f578063865c695314610722575f5ffd5b80635c975abb146106a25780635e9d8348146106aa57806363f6a798146106bd5780636d21117e146106d2575f5ffd5b806354fd4d50116102b157806354fd4d501461064f57806358baaa3e14610664578063595c6a67146106775780635ac86ab71461067f575f5ffd5b80634596021c146105d85780634657e26a146105eb5780634b943960146106125780634d18cc3514610638575f5ffd5b8063149bc8721161035757806339b70e381161032757806339b70e38146105745780633a8c07861461059b5780633ccc861d146105b25780633efe1db6146105c5575f5ffd5b8063149bc872146104d95780632b9f64a4146104fa57806336af41fa1461053a57806337838ed01461054d575f5ffd5b80630e9a53cf116103925780630e9a53cf1461043f5780630eb383451461048c578063131433b41461049f578063136439dd146104c6575f5ffd5b806218572c146103b757806304a0c502146103ee5780630ca298991461042a575b5f5ffd5b6103d96103c5366004613a33565b60d16020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6104157f0000000000000000000000000000000000000000000000000000000000278d0081565b60405163ffffffff90911681526020016103e5565b61043d610438366004613aab565b610a7f565b005b610447610d25565b6040516103e591905f6080820190508251825263ffffffff602084015116602083015263ffffffff604084015116604083015260608301511515606083015292915050565b61043d61049a366004613b07565b610e25565b6104157f0000000000000000000000000000000000000000000000000000000065fb788081565b61043d6104d4366004613b3e565b610ea5565b6104ec6104e7366004613b55565b610edf565b6040519081526020016103e5565b610522610508366004613a33565b60cc6020525f90815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103e5565b61043d610548366004613b6f565b610f54565b6104157f000000000000000000000000000000000000000000000000000000000076a70081565b6105227f0000000000000000000000009a676e781a523b5d0c0e43731313a708cb60750881565b60cb5461041590600160a01b900463ffffffff1681565b61043d6105c0366004613bbe565b6110c5565b61043d6105d3366004613c14565b6110ec565b61043d6105e6366004613c3e565b6112c2565b6105227f0000000000000000000000003aa5ebb10dc797cac828524e59a333d0a371443c81565b610625610620366004613a33565b611325565b60405161ffff90911681526020016103e5565b60cb5461041590600160c01b900463ffffffff1681565b610657611380565b6040516103e59190613c90565b61043d610672366004613cc5565b6113b0565b61043d6113c4565b6103d961068d366004613cde565b606654600160ff9092169190911b9081161490565b6066546104ec565b6103d96106b8366004613cfe565b6113d8565b60cb5461062590600160e01b900461ffff1681565b6103d96106e0366004613d2f565b60cf60209081525f928352604080842090915290825290205460ff1681565b61043d611463565b60ca546104ec565b61043d61071d366004613a33565b611474565b6104ec610730366004613d59565b60cd60209081525f928352604080842090915290825290205481565b6105227f000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e81565b6033546001600160a01b0316610522565b61052273beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b610447611485565b61043d6107b5366004613d85565b611521565b6104157f000000000000000000000000000000000000000000000000000000000001518081565b6106256107ef366004613dbc565b61169c565b61043d
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000000000000000000000000000000000000000000ff"
}
feat : Slashing integration in EigenLayer and Datahaven AVS (#345) ## 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
2026-01-16 19:49:45 +00:00
},
refactor(rewards): Optimize reward calculation (#408) ### Summary Optimizes `award_session_performance_points` by batching all validator rewards into a single storage mutation instead of performing individual mutations inside the loop. ### Problem The `award_session_performance_points` function, called during session rotation via `SessionManager::end_session`, was calling `reward_by_ids` inside the validator loop for each validator individually: ```rust for validator in validators.iter() { // ... calculate points ... Self::reward_by_ids([(validator.clone(), points)].into_iter()); } ``` Each call to `reward_by_ids` performs a `StorageMap::mutate` on `RewardPointsForEra`, which reads and writes the entire `EraRewardPoints` structure (a `BTreeMap` containing up to N validator entries). With N validators, this results in N separate read-modify-write cycles of an O(N)-sized structure, leading to O(N²) total storage I/O. ### Solution Collect all reward points first, then perform a single batched call to `reward_by_ids`: ```rust let mut rewards = Vec::new(); for validator in validators.iter() { // ... calculate points ... rewards.push((validator.clone(), points)); } if !rewards.is_empty() { Self::reward_by_ids(rewards.into_iter()); } ``` This reduces the complexity from O(N²) to O(N) by performing only one storage mutation that processes all validators at once. ### Why This Matters Session rotation hooks are mandatory—they execute regardless of block weight limits. While `pallet_session::on_initialize` returns `max_block` weight during rotation (preventing user transactions), the actual execution time still matters. With a large validator set, O(N²) storage operations could exceed the block time target, potentially causing block production delays. ### Test Plan - [x] Existing unit tests pass (`cargo test -p pallet-external-validators-rewards`)
2026-01-22 21:40:12 +00:00
"8": {
"address": "0x0E801D84Fa97b50751Dbf25036d067dCf18858bF",
"code": "0x60806040526004361061003e575f3560e01c806305b1137b1461004257806325ccedec14610063578063c6b295c114610082578063d0e30db014610061575b5f5ffd5b34801561004d575f5ffd5b5061006161005c36600461025e565b6100a1565b005b34801561006e575f5ffd5b5061006161007d366004610288565b6100b8565b34801561008d575f5ffd5b5061006161009c3660046102ef565b6100da565b6100b46001600160a01b038316826100f7565b5050565b6100d56001600160a01b038416836001600160801b038416610120565b505050565b5f6100e6848484610171565b9050806100f1575f5ffd5b50505050565b5f5f5f5f5f85875af19050806100d557604051633d2cec6f60e21b815260040160405180910390fd5b6040516001600160a01b0383166024820152604481018290526100d590849060640160408051601f198184030181529190526020810180516001600160e01b031663a9059cbb60e01b179052610188565b5f5f5f5f85516020870186895af195945050505050565b5f5f836001600160a01b0316836040516101a291906103be565b5f604051808303815f865af19150503d805f81146101db576040519150601f19603f3d011682016040523d82523d5f602084013e6101e0565b606091505b50915091505f82801561020b57508151158061020b57508180602001905181019061020b91906103d4565b905080158061022257506001600160a01b0385163b155b156102405760405163022e258160e11b815260040160405180910390fd5b5050505050565b6001600160a01b038116811461025b575f5ffd5b50565b5f5f6040838503121561026f575f5ffd5b823561027a81610247565b946020939093013593505050565b5f5f5f6060848603121561029a575f5ffd5b83356102a581610247565b925060208401356102b581610247565b915060408401356001600160801b03811681146102d0575f5ffd5b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f5f5f60608486031215610301575f5ffd5b833561030c81610247565b9250602084013567ffffffffffffffff811115610327575f5ffd5b8401601f81018613610337575f5ffd5b803567ffffffffffffffff811115610351576103516102db565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610380576103806102db565b604052818152828201602001881015610397575f5ffd5b816020840160208301375f9181016020019190915293969395505050506040919091013590565b5f82518060208501845e5f920191825250919050565b5f602082840312156103e4575f5ffd5b815180151581146103f3575f5ffd5b939250505056fea2646970667358221220590055fea5441ad6e827390b16005643886d2dc4ffe2b97b43ed3ab207076ab664736f6c634300081c003300",
"storage": {}
}
}