package keeper import ( "context" "mukan/x/poj/types" sdk "github.com/cosmos/cosmos-sdk/types" ) // ProcessBlockReward applies the PoJ logic (Micro/Macro Fren) for a miner. // Returns true if the miner is allowed to receive a reward for this block. func (k Keeper) ProcessBlockReward(ctx context.Context, minerAddr string) bool { sdkCtx := sdk.UnwrapSDKContext(ctx) // 0. Bootstrap check: No automatic proposer rewards in Phase 1 if k.IsBootstrapping(ctx) { return false } state, found := k.GetMinerState(ctx, minerAddr) if !found { state = types.MinerState{ Address: minerAddr, ConsecutiveWins: 0, StreakCount: 0, CooldownUntil: 0, } } currentBlock := sdkCtx.BlockHeight() params, _ := k.Params.Get(ctx) // 1. Cooldown check if state.CooldownUntil >= currentBlock { // Solution rejected - no reward produced. return false } // 2. Consecutive wins increment state.ConsecutiveWins++ if state.ConsecutiveWins < 2 { // No streak yet, award reward k.SetMinerState(ctx, state) return true } // 3. Micro Fren: 2nd consecutive win state.StreakCount++ state.ConsecutiveWins = 0 if state.StreakCount >= params.MacroStreakLimit { // 4. Macro Fren: 5th streak -> Big Break state.CooldownUntil = currentBlock + params.MacroCooldown state.StreakCount = 0 // RESET - penalty served, clean slate } else { // Micro Fren: 1 block wait state.CooldownUntil = currentBlock + params.MicroCooldown } k.SetMinerState(ctx, state) return true // Current block reward is given, cooldown affects the next one }