delegation_manager.gno
5.25 Kb · 151 lines
1package staker
2
3import (
4 bptree "gno.land/p/nt/bptree/v0"
5)
6
7// DelegationManager manages the mapping between users and their delegation IDs.
8// It provides efficient lookup and management of user delegations organized by delegator and delegatee addresses.
9type DelegationManager struct {
10 // userDelegations maps delegator address -> *bptree.BPTree (delegatee address -> list of delegation IDs)
11 // Using BPTree instead of map to handle unbounded growth of delegators efficiently
12 userDelegations *bptree.BPTree
13}
14
15// NewDelegationManager creates a new instance of DelegationManager.
16// This factory function initializes the BPTree structure for tracking user delegations.
17//
18// Returns:
19// - *DelegationManager: manager ready to track delegator/delegatee ID lists.
20func NewDelegationManager() *DelegationManager {
21 return &DelegationManager{
22 userDelegations: bptree.NewBPTreeN(16),
23 }
24}
25
26// GetUserDelegations returns the entire user delegations tree.
27//
28// Returns:
29// - *bptree.BPTree: tree keyed by delegator address string.
30func (dm *DelegationManager) GetUserDelegations() *bptree.BPTree {
31 return dm.userDelegations
32}
33
34// SetUserDelegations replaces the root delegator-to-delegations tree.
35//
36// Parameters:
37// - userDelegations: tree keyed by delegator address string and containing delegatee trees.
38func (dm *DelegationManager) SetUserDelegations(userDelegations *bptree.BPTree) {
39 dm.userDelegations = userDelegations
40}
41
42// GetDelegatorDelegations returns the delegatee tree for one delegator.
43//
44// Parameters:
45// - delegator: delegator address string used as the root-tree key.
46//
47// Returns:
48// - *bptree.BPTree: delegatee-to-delegation-ID tree when present and correctly typed.
49// - bool: true when the delegator entry exists with the expected tree type.
50func (dm *DelegationManager) GetDelegatorDelegations(delegator string) (*bptree.BPTree, bool) {
51 delegations := dm.userDelegations.Get(delegator)
52 if delegations == nil {
53 return nil, false
54 }
55 delegationsTree, ok := delegations.(*bptree.BPTree)
56 if !ok {
57 return nil, false
58 }
59 return delegationsTree, true
60}
61
62// GetDelegationIDs returns IDs recorded for one delegator/delegatee pair.
63//
64// Parameters:
65// - delegator: delegator address string used to select the nested tree.
66// - delegatee: delegatee address string used as the nested-tree key.
67//
68// Returns:
69// - []int64: delegation IDs stored for the pair.
70// - bool: true when the pair exists with a valid ID slice.
71func (dm *DelegationManager) GetDelegationIDs(delegator, delegatee string) ([]int64, bool) {
72 delegations, exists := dm.GetDelegatorDelegations(delegator)
73 if !exists {
74 return nil, false
75 }
76 ids := delegations.Get(delegatee)
77 if ids == nil {
78 return nil, false
79 }
80 idsSlice, ok := ids.([]int64)
81 if !ok {
82 return nil, false
83 }
84 return idsSlice, true
85}
86
87// SetDelegationIDs stores the complete ID slice for a delegator/delegatee pair.
88// A missing delegator entry is initialized with a new nested tree.
89//
90// Parameters:
91// - delegator: delegator address string used to select or create the nested tree.
92// - delegatee: delegatee address string used as the nested-tree key.
93// - ids: delegation IDs to store for the pair.
94func (dm *DelegationManager) SetDelegationIDs(delegator, delegatee string, ids []int64) {
95 delegations, exists := dm.GetDelegatorDelegations(delegator)
96 if !exists {
97 delegations = NewDelegationTree()
98 dm.userDelegations.Set(delegator, delegations)
99 }
100 delegations.Set(delegatee, ids)
101}
102
103// AddDelegationID appends a delegation ID to the delegator-delegatee pair,
104// skipping duplicates. The whole get-modify-set runs inside this domain method
105// so the nested BPTree mutation never escapes the owning realm. Performing the
106// lookup in one realm and the write in another (e.g. re-fetching the inner tree
107// across a realm boundary and mutating it) would hit the cross-realm write
108// guard for the persisted leaf slot.
109//
110// Parameters:
111// - delegator: delegator address string used to select the nested tree.
112// - delegatee: delegatee address string used as the nested-tree key.
113// - delegationID: delegation ID to append when it is not already present.
114func (dm *DelegationManager) AddDelegationID(delegator, delegatee string, delegationID int64) {
115 ids, _ := dm.GetDelegationIDs(delegator, delegatee)
116 for _, id := range ids {
117 if id == delegationID {
118 return
119 }
120 }
121 ids = append(ids, delegationID)
122 dm.SetDelegationIDs(delegator, delegatee, ids)
123}
124
125// RemoveDelegationID removes a delegation ID from the delegator-delegatee pair.
126// Like AddDelegationID, the read-modify-write is kept inside this domain method.
127// RemoveDelegationID removes one ID from a delegator/delegatee pair.
128// Missing pairs and IDs are left unchanged.
129//
130// Parameters:
131// - delegator: delegator address string used to select the nested tree.
132// - delegatee: delegatee address string used as the nested-tree key.
133// - delegationID: delegation ID to remove when it is present.
134func (dm *DelegationManager) RemoveDelegationID(delegator, delegatee string, delegationID int64) {
135 ids, exists := dm.GetDelegationIDs(delegator, delegatee)
136 if !exists {
137 return
138 }
139 index := -1
140 for i, id := range ids {
141 if id == delegationID {
142 index = i
143 break
144 }
145 }
146 if index == -1 {
147 return
148 }
149 ids = append(ids[:index], ids[index+1:]...)
150 dm.SetDelegationIDs(delegator, delegatee, ids)
151}