6c34650a0d
v0.5 Bearers Runtime — 7 runtime REQs (REQ-033..039) shipped as feature. 8 modules promoted to runtime (MsgServer + simtest). cosmos-sdk v0.50.8 + ibc-go v8.2.1 added (G-006 controlled exception). G-003 + locked-const firewalls intact. 8 keeper packages ≥80% coverage. 5 GRILL decisions ratified; 8 binding fixes landed; 5 P1+ flagged for v0.6+. ---ci--- project: oy phase: 8 milestone: v0.5 status: complete requirements: covered: [REQ-033, REQ-034, REQ-035, REQ-036, REQ-037, REQ-038, REQ-039] partial: [] ---/ci---
138 lines
4.9 KiB
Go
138 lines
4.9 KiB
Go
package keeper
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
storetypes "cosmossdk.io/store/types"
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
"github.com/oy/openyield/x/partner/types"
|
|
)
|
|
|
|
// keeper.go holds the store-backed Keeper for the partner module's
|
|
// Anchor credential runtime (P3-02-01, REQ-035).
|
|
//
|
|
// The Keeper wraps an sdk.KVStore via a storeKey. It holds the
|
|
// AnchorCredential records (by anchor-id). The v0.3 in-memory registry
|
|
// Keeper stub (types.Keeper, x/partner/types/types.go) is RETAINED for
|
|
// the Partner registry (non-Anchor partners — the v0.3 skeleton); the
|
|
// v0.5 runtime promotes ONLY the Anchor credential lifecycle to a
|
|
// store-backed keeper (D-054 simtest grade). The Partner registry stays
|
|
// on the v0.3 in-memory stub (non-Anchor partner tiers are not promoted
|
|
// in v0.5 — out of scope; only the Anchor credential lifecycle is).
|
|
//
|
|
// The Keeper also holds the two expected-keeper shims (WatcherKeeper for
|
|
// 6-of-9 quorum authz on issue/revoke; HubKeeper for custody-provider-id
|
|
// validity on onboard — the P3→P4 hub dep edge broken by the interface
|
|
// shim per G-003 / ARCHITECTURE.md v0.5). The shims are interfaces
|
|
// (G-003 — no struct import of x/watcher/types or x/hub/types); the
|
|
// concrete keepers satisfy them structurally.
|
|
//
|
|
// State-machine ordering (vision §7, enforced in every handler):
|
|
// ValidateBasic → keeper authz → state mutation → ctx.EventManager().EmitEvent
|
|
|
|
// Keeper is the store-backed partner Anchor-credential keeper.
|
|
type Keeper struct {
|
|
cdc codec.Codec
|
|
storeKey storetypes.StoreKey
|
|
watcherKeeper types.WatcherKeeper
|
|
hubKeeper types.HubKeeper
|
|
}
|
|
|
|
// NewKeeper constructs a new store-backed partner Anchor-credential
|
|
// Keeper. The WatcherKeeper and HubKeeper expected-keeper shims are
|
|
// injected (nil-able for partial tests; the handlers guard nil shims
|
|
// and skip the corresponding authz/validity check, still mutating state
|
|
// — the simtest wiring document this). The HubKeeper shim is the P3→P4
|
|
// hub dep edge: in P3 simtest it is wired to a stub (G-003 test
|
|
// exemption); the real hub keeper is wired in P4.
|
|
func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey, wk types.WatcherKeeper, hk types.HubKeeper) Keeper {
|
|
return Keeper{
|
|
cdc: cdc,
|
|
storeKey: storeKey,
|
|
watcherKeeper: wk,
|
|
hubKeeper: hk,
|
|
}
|
|
}
|
|
|
|
// SetWatcherKeeper sets the WatcherKeeper expected-keeper shim (for
|
|
// post-construction wiring, e.g., app wiring or test setup).
|
|
func (k *Keeper) SetWatcherKeeper(wk types.WatcherKeeper) { k.watcherKeeper = wk }
|
|
|
|
// SetHubKeeper sets the HubKeeper expected-keeper shim (for
|
|
// post-construction wiring, e.g., app wiring or test setup). This is
|
|
// the P3→P4 hub dep edge: P4 wires the real hub keeper via this setter
|
|
// or via NewKeeper.
|
|
func (k *Keeper) SetHubKeeper(hk types.HubKeeper) { k.hubKeeper = hk }
|
|
|
|
// --- Anchor credential store -------------------------------------------------
|
|
|
|
var anchorKeyPrefix = []byte("anchor/")
|
|
|
|
func anchorKey(anchorID string) []byte {
|
|
return append(anchorKeyPrefix, []byte(anchorID)...)
|
|
}
|
|
|
|
// GetAnchorCredential loads an AnchorCredential by anchor-id. Returns the
|
|
// credential and true if found, or zero value + false if not.
|
|
func (k Keeper) GetAnchorCredential(ctx sdk.Context, anchorID string) (types.AnchorCredential, bool) {
|
|
store := ctx.KVStore(k.storeKey)
|
|
bz := store.Get(anchorKey(anchorID))
|
|
if bz == nil {
|
|
return types.AnchorCredential{}, false
|
|
}
|
|
var c types.AnchorCredential
|
|
if err := json.Unmarshal(bz, &c); err != nil {
|
|
return types.AnchorCredential{}, false
|
|
}
|
|
return c, true
|
|
}
|
|
|
|
// SetAnchorCredential persists an AnchorCredential by anchor-id.
|
|
func (k Keeper) SetAnchorCredential(ctx sdk.Context, c types.AnchorCredential) {
|
|
store := ctx.KVStore(k.storeKey)
|
|
bz, err := json.Marshal(c)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("partner: marshal anchor credential %q: %v", c.AnchorID, err))
|
|
}
|
|
store.Set(anchorKey(c.AnchorID), bz)
|
|
}
|
|
|
|
// AllAnchorCredentials returns all persisted AnchorCredential records
|
|
// (iteration helper).
|
|
func (k Keeper) AllAnchorCredentials(ctx sdk.Context) []types.AnchorCredential {
|
|
store := ctx.KVStore(k.storeKey)
|
|
iterator := store.Iterator(anchorKeyPrefix, prefixEnd(anchorKeyPrefix))
|
|
defer iterator.Close()
|
|
out := []types.AnchorCredential{}
|
|
for ; iterator.Valid(); iterator.Next() {
|
|
var c types.AnchorCredential
|
|
if err := json.Unmarshal(iterator.Value(), &c); err == nil {
|
|
out = append(out, c)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// prefixEnd returns the key that sorts immediately after all keys sharing
|
|
// the given prefix (the standard prefix-iteration end key: increment the
|
|
// last byte, drop overflow). Used for store.Iterator(start, prefixEnd(start))
|
|
// prefix scans.
|
|
func prefixEnd(prefix []byte) []byte {
|
|
if len(prefix) == 0 {
|
|
return nil
|
|
}
|
|
end := make([]byte, len(prefix))
|
|
copy(end, prefix)
|
|
for i := len(end) - 1; i >= 0; i-- {
|
|
end[i]++
|
|
if end[i] != 0 {
|
|
return end
|
|
}
|
|
}
|
|
// All bytes were 0xFF; return nil (iterate to end of store).
|
|
return nil
|
|
}
|