// Copyright (c) 2026 The Limenka developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef LIMENKA_POW_FORK_H #define LIMENKA_POW_FORK_H #include #include #include class CBlockIndex; struct CBlockHeader; /** Per-block fork DAA state (memory-only on CBlockIndex, not persisted). */ struct ForkDAAState { arith_uint256 nForkTarget{}; int64_t nForkAvgError{}; // EMA accumulator (integral action) int64_t nForkLastBlockTime{}; // nTime of the previous fork block }; /** Compute the next required difficulty target for a fork block. * Pure: does not mutate any state. `out` (if non-null) receives the * DAA state to store on the new block when it is connected. * * Measurement basis: e = pblock->nTime - prev nTime (direct stamp * delta). Controller: PI asymmetric with corrected naming - * P (proportional, kp) acts on the instantaneous error, I (integral, * ki_up/ki_down) acts on the EMA accumulator. Raise slow / lower * fast. The setpoint nForkIntervalTarget is calibrated above 600s to * cancel the asymmetric-integral rectification bias. */ uint32_t CalculateForkTarget(const CBlockIndex* pindexPrev, const CBlockHeader* pblock, const Consensus::Params& params, ForkDAAState* out = nullptr); /** Initialize fork DAA state at activation, seeding from the block's own * difficulty so the fork continues the parent chain's cadence. */ void InitForkDAAState(CBlockIndex* pindex); /** Get the current DAA target. */ arith_uint256 GetForkTarget(const CBlockIndex* pindex); #endif // LIMENKA_POW_FORK_H