delegation_manager.gno
3.57 Kb · 109 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.
17func NewDelegationManager() *DelegationManager {
18 return &DelegationManager{
19 userDelegations: bptree.NewBPTreeN(16),
20 }
21}
22
23// GetUserDelegations returns the entire user delegations tree.
24func (dm *DelegationManager) GetUserDelegations() *bptree.BPTree {
25 return dm.userDelegations
26}
27
28// SetUserDelegations sets the entire user delegations tree.
29func (dm *DelegationManager) SetUserDelegations(userDelegations *bptree.BPTree) {
30 dm.userDelegations = userDelegations
31}
32
33// GetDelegatorDelegations returns all delegations for a specific delegator.
34func (dm *DelegationManager) GetDelegatorDelegations(delegator string) (*bptree.BPTree, bool) {
35 delegations, exists := dm.userDelegations.Get(delegator)
36 if !exists {
37 return nil, false
38 }
39 delegationsTree, ok := delegations.(*bptree.BPTree)
40 if !ok {
41 return nil, false
42 }
43 return delegationsTree, true
44}
45
46// GetDelegationIDs returns all delegation IDs for a specific delegator-delegatee pair.
47func (dm *DelegationManager) GetDelegationIDs(delegator, delegatee string) ([]int64, bool) {
48 delegations, exists := dm.GetDelegatorDelegations(delegator)
49 if !exists {
50 return nil, false
51 }
52 ids, exists := delegations.Get(delegatee)
53 if !exists {
54 return nil, false
55 }
56 idsSlice, ok := ids.([]int64)
57 if !ok {
58 return nil, false
59 }
60 return idsSlice, true
61}
62
63// SetDelegationIDs sets delegation IDs for a specific delegator-delegatee pair.
64func (dm *DelegationManager) SetDelegationIDs(delegator, delegatee string, ids []int64) {
65 delegations, exists := dm.GetDelegatorDelegations(delegator)
66 if !exists {
67 delegations = NewDelegationTree()
68 dm.userDelegations.Set(delegator, delegations)
69 }
70 delegations.Set(delegatee, ids)
71}
72
73// AddDelegationID appends a delegation ID to the delegator-delegatee pair,
74// skipping duplicates. The whole get-modify-set runs inside this domain method
75// so the nested BPTree mutation never escapes the owning realm. Performing the
76// lookup in one realm and the write in another (e.g. re-fetching the inner tree
77// across a realm boundary and mutating it) would hit the cross-realm write
78// guard for the persisted leaf slot.
79func (dm *DelegationManager) AddDelegationID(delegator, delegatee string, delegationID int64) {
80 ids, _ := dm.GetDelegationIDs(delegator, delegatee)
81 for _, id := range ids {
82 if id == delegationID {
83 return
84 }
85 }
86 ids = append(ids, delegationID)
87 dm.SetDelegationIDs(delegator, delegatee, ids)
88}
89
90// RemoveDelegationID removes a delegation ID from the delegator-delegatee pair.
91// Like AddDelegationID, the read-modify-write is kept inside this domain method.
92func (dm *DelegationManager) RemoveDelegationID(delegator, delegatee string, delegationID int64) {
93 ids, exists := dm.GetDelegationIDs(delegator, delegatee)
94 if !exists {
95 return
96 }
97 index := -1
98 for i, id := range ids {
99 if id == delegationID {
100 index = i
101 break
102 }
103 }
104 if index == -1 {
105 return
106 }
107 ids = append(ids[:index], ids[index+1:]...)
108 dm.SetDelegationIDs(delegator, delegatee, ids)
109}