Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions contract/p/gnoswap/uinttree/doc.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Package uinttree provides a shared uint64-keyed AVL wrapper for GnoSwap realms.
//
// Keys are encoded as zero-padded decimal strings so natural AVL ordering matches
// uint64 ordering, which makes the package suitable for timestamp-indexed history.
package uinttree
2 changes: 2 additions & 0 deletions contract/p/gnoswap/uinttree/gnomod.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module = "gno.land/p/gnoswap/uinttree"
gno = "0.9"
118 changes: 118 additions & 0 deletions contract/p/gnoswap/uinttree/tree.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package uinttree

import (
"strconv"
"strings"

avl "gno.land/p/nt/avl/v0"
)

type UintTree struct {
tree *avl.Tree
}

func NewUintTree() *UintTree {
return &UintTree{tree: avl.NewTree()}
}

func (self *UintTree) Get(key uint64) (any, bool) {
v, ok := self.tree.Get(EncodeUint(key))
if !ok {
return nil, false
}
return v, true
}

func (self *UintTree) GetByInt64(key int64) (any, bool) {
return self.Get(SafeConvertInt64ToUint64(key))
}

func (self *UintTree) Set(key uint64, value any) {
self.tree.Set(EncodeUint(key), value)
}

func (self *UintTree) SetByInt64(key int64, value any) {
self.Set(SafeConvertInt64ToUint64(key), value)
}

func (self *UintTree) Has(key uint64) bool {
return self.tree.Has(EncodeUint(key))
}

func (self *UintTree) HasByInt64(key int64) bool {
return self.Has(SafeConvertInt64ToUint64(key))
}

func (self *UintTree) Remove(key uint64) {
self.tree.Remove(EncodeUint(key))
}

func (self *UintTree) RemoveByInt64(key int64) {
self.Remove(SafeConvertInt64ToUint64(key))
}

func (self *UintTree) Iterate(start, end uint64, fn func(key uint64, value any) bool) {
self.tree.Iterate(EncodeUint(start), EncodeUint(end), func(key string, value any) bool {
return fn(DecodeUint(key), value)
})
}

func (self *UintTree) IterateByInt64(start, end int64, fn func(key uint64, value any) bool) {
self.Iterate(SafeConvertInt64ToUint64(start), SafeConvertInt64ToUint64(end), fn)
}

func (self *UintTree) ReverseIterate(start, end uint64, fn func(key uint64, value any) bool) {
self.tree.ReverseIterate(EncodeUint(start), EncodeUint(end), func(key string, value any) bool {
return fn(DecodeUint(key), value)
})
}

func (self *UintTree) ReverseIterateByInt64(start, end int64, fn func(key uint64, value any) bool) {
self.ReverseIterate(SafeConvertInt64ToUint64(start), SafeConvertInt64ToUint64(end), fn)
}

func (self *UintTree) Size() int {
return self.tree.Size()
}

func (self *UintTree) IterateByOffset(offset, count int, fn func(key uint64, value any) bool) {
self.tree.IterateByOffset(offset, count, func(key string, value any) bool {
return fn(DecodeUint(key), value)
})
}

func (self *UintTree) Clone() *UintTree {
if self == nil {
return nil
}

cloned := NewUintTree()
self.tree.Iterate("", "", func(key string, value any) bool {
cloned.tree.Set(key, value)
return false
})

return cloned
}

func SafeConvertInt64ToUint64(value int64) uint64 {
if value < 0 {
panic("value must be non-negative")
}

return uint64(value)
}

func EncodeUint(num uint64) string {
s := strconv.FormatUint(num, 10)
zerosNeeded := 20 - len(s)
return strings.Repeat("0", zerosNeeded) + s
}

func DecodeUint(s string) uint64 {
num, err := strconv.ParseUint(s, 10, 64)
if err != nil {
panic(err)
}
return num
}
50 changes: 50 additions & 0 deletions contract/p/gnoswap/uinttree/tree_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package uinttree

import (
"testing"
)

func TestUintTreeSetAndGetByInt64(t *testing.T) {
tree := NewUintTree()
tree.SetByInt64(7, "value")

value, ok := tree.GetByInt64(7)
if !ok {
t.Fatal("expected key to exist")
}
if value != "value" {
t.Fatalf("expected value, got %v", value)
}
}

func TestUintTreeReverseIterateByInt64(t *testing.T) {
tree := NewUintTree()
tree.SetByInt64(5, "five")
tree.SetByInt64(10, "ten")

var latest string
tree.ReverseIterateByInt64(0, 10, func(_ uint64, value any) bool {
latest = value.(string)
return true
})

if latest != "ten" {
t.Fatalf("expected ten, got %s", latest)
}
}

func TestUintTreeSetByInt64PanicsOnNegativeKey(t *testing.T) {
tree := NewUintTree()

defer func() {
r := recover()
if r == nil {
t.Fatal("expected panic")
}
if r != "value must be non-negative" {
t.Fatalf("unexpected panic: %v", r)
}
}()

tree.SetByInt64(-1, "value")
}
9 changes: 5 additions & 4 deletions contract/r/gnoswap/gov/staker/store.gno
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"strconv"

"gno.land/p/gnoswap/store"
utree "gno.land/p/gnoswap/uinttree"
avl "gno.land/p/nt/avl/v0"
ufmt "gno.land/p/nt/ufmt/v0"
)
Expand Down Expand Up @@ -220,21 +221,21 @@ func (s *govStakerStore) HasTotalDelegationHistoryStoreKey() bool {
return s.kvStore.Has(StoreKeyTotalDelegationHistory)
}

func (s *govStakerStore) GetTotalDelegationHistory() *UintTree {
func (s *govStakerStore) GetTotalDelegationHistory() *utree.UintTree {
result, err := s.kvStore.Get(StoreKeyTotalDelegationHistory)
if err != nil {
panic(err)
}

history, ok := result.(*UintTree)
history, ok := result.(*utree.UintTree)
if !ok {
panic(ufmt.Sprintf("failed to cast result to *UintTree: %T", result))
panic(ufmt.Sprintf("failed to cast result to *utree.UintTree: %T", result))
}

return history
}

func (s *govStakerStore) SetTotalDelegationHistory(history *UintTree) error {
func (s *govStakerStore) SetTotalDelegationHistory(history *utree.UintTree) error {
return s.kvStore.Set(StoreKeyTotalDelegationHistory, history)
}

Expand Down
5 changes: 3 additions & 2 deletions contract/r/gnoswap/gov/staker/store_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"chain/runtime"
"testing"

utree "gno.land/p/gnoswap/uinttree"
avl "gno.land/p/nt/avl/v0"
testutils "gno.land/p/nt/testutils/v0"
uassert "gno.land/p/nt/uassert/v0"
Expand Down Expand Up @@ -572,7 +573,7 @@ func TestStoreSetAndGetTotalDelegationHistory(t *testing.T) {
{
name: "set and get total delegation history successfully",
setupFn: func(gs IGovStakerStore) {
history := NewUintTree()
history := utree.NewUintTree()
gs.SetTotalDelegationHistory(history)
},
testFn: func(t *testing.T, gs IGovStakerStore) {
Expand Down Expand Up @@ -926,7 +927,7 @@ func TestStoreMultipleSetAndGet(t *testing.T) {
}
gs.SetDelegationCounter(counter)

totalHistory := NewUintTree()
totalHistory := utree.NewUintTree()
gs.SetTotalDelegationHistory(totalHistory)

userHistory := avl.NewTree()
Expand Down
124 changes: 0 additions & 124 deletions contract/r/gnoswap/gov/staker/tree.gno

This file was deleted.

Loading
Loading