Skip to content

Commit eedbff0

Browse files
authored
fix(query): add pagination support (#1976)
* Add pagination utility package with encoding/decoding functionality * Implement pagination support in cert, deployment, and market queries * Update validation utilities for address handling * Add comprehensive test coverage for pagination functionality * chore(mod): bump cometbft, refs akash-network/support#291 Signed-off-by: Artur Troian <[email protected]> Co-authored-by: Artur Troian <[email protected]>
1 parent 5841156 commit eedbff0

File tree

11 files changed

+999
-226
lines changed

11 files changed

+999
-226
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ replace (
6868
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
6969
// use cometBFT system fork of tendermint with akash patches
7070

71-
github.com/tendermint/tendermint => github.com/akash-network/cometbft v0.34.27-akash.2
71+
github.com/tendermint/tendermint => github.com/akash-network/cometbft v0.34.27-akash.3
7272

7373
github.com/zondax/hid => github.com/troian/hid v0.13.2
7474
github.com/zondax/ledger-go => github.com/akash-network/ledger-go v0.14.3

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY
7878
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
7979
github.com/akash-network/akash-api v0.0.75 h1:h9RZemWa7JqMGYb3nVRhRgP4xZnACIy0yN7de60JLyg=
8080
github.com/akash-network/akash-api v0.0.75/go.mod h1:pvoHHEQbt63+U+HUSTjssZ1nUJ8sJuWtHCu6ztaXcqo=
81-
github.com/akash-network/cometbft v0.34.27-akash.2 h1:2hKEcX+cIv/OLAJ82gBWdkZlVWn+8JUYs4GrDoPAOhU=
82-
github.com/akash-network/cometbft v0.34.27-akash.2/go.mod h1:BcCbhKv7ieM0KEddnYXvQZR+pZykTKReJJYf7YC7qhw=
81+
github.com/akash-network/cometbft v0.34.27-akash.3 h1:ObmkKrMybIuRLPcwPwUMJ8Pllsr+Gsve443mkJsonMA=
82+
github.com/akash-network/cometbft v0.34.27-akash.3/go.mod h1:BcCbhKv7ieM0KEddnYXvQZR+pZykTKReJJYf7YC7qhw=
8383
github.com/akash-network/cosmos-sdk v0.45.16-akash.3 h1:QiHOQ1ACzCvAEXRlzGNQhp9quWLOowE104D0uESGrEk=
8484
github.com/akash-network/cosmos-sdk v0.45.16-akash.3/go.mod h1:NTnk/GuQdFyfk/iGFxDAgQH9fwcbRW/hREap6qaPg48=
8585
github.com/akash-network/ledger-go v0.14.3 h1:LCEFkTfgGA2xFMN2CtiKvXKE7dh0QSM77PJHCpSkaAo=

tests/upgrade/upgrade_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ type nodeInitParams struct {
254254
grpcPort uint16
255255
grpcWebPort uint16
256256
pprofPort uint16
257+
apiPort uint16
257258
}
258259

259260
var (
@@ -446,6 +447,7 @@ func TestUpgrade(t *testing.T) {
446447
grpcPort: 9090 + uint16(idx*3),
447448
grpcWebPort: 9091 + uint16(idx*3),
448449
pprofPort: 6060 + uint16(idx),
450+
apiPort: 1317 + uint16(idx),
449451
}
450452
}
451453

@@ -488,6 +490,7 @@ func TestUpgrade(t *testing.T) {
488490
fmt.Sprintf("AKASH_RPC_PPROF_LADDR=%s:%d", listenAddr, params.pprofPort),
489491
fmt.Sprintf("AKASH_GRPC_ADDRESS=%s:%d", listenAddr, params.grpcPort),
490492
fmt.Sprintf("AKASH_GRPC_WEB_ADDRESS=%s:%d", listenAddr, params.grpcWebPort),
493+
fmt.Sprintf("AKASH_API_ADDRESS=tcp://%s:%d", listenAddr, params.apiPort),
491494
"DAEMON_NAME=akash",
492495
"DAEMON_RESTART_AFTER_UPGRADE=true",
493496
"DAEMON_ALLOW_DOWNLOAD_BINARIES=true",
@@ -508,6 +511,7 @@ func TestUpgrade(t *testing.T) {
508511
"AKASH_TX_INDEX_INDEXER=null",
509512
"AKASH_GRPC_ENABLE=true",
510513
"AKASH_GRPC_WEB_ENABLE=true",
514+
"AKASH_API_ENABLE=true",
511515
},
512516
}
513517
}

util/query/pagination.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package query
2+
3+
import (
4+
"encoding/binary"
5+
"fmt"
6+
"hash/crc32"
7+
8+
"github.com/akash-network/node/util/validation"
9+
)
10+
11+
var (
12+
ErrInvalidPaginationKey = fmt.Errorf("pagination: invalid key")
13+
)
14+
15+
// DecodePaginationKey parses the pagination key and returns the states, prefix and key to be used by the FilteredPaginate
16+
func DecodePaginationKey(key []byte) ([]byte, []byte, []byte, []byte, error) {
17+
if len(key) < 5 {
18+
return nil, nil, nil, nil, fmt.Errorf("%w: invalid key length", ErrInvalidPaginationKey)
19+
}
20+
21+
expectedChecksum := binary.BigEndian.Uint32(key)
22+
23+
key = key[4:]
24+
25+
checksum := crc32.ChecksumIEEE(key)
26+
27+
if expectedChecksum != checksum {
28+
return nil, nil, nil, nil, fmt.Errorf("%w: invalid checksum, 0x%08x != 0x%08x", ErrInvalidPaginationKey, expectedChecksum, checksum)
29+
}
30+
31+
statesC := int(key[0])
32+
key = key[1:]
33+
34+
if len(key) < statesC {
35+
return nil, nil, nil, nil, fmt.Errorf("%w: invalid state length", ErrInvalidPaginationKey)
36+
}
37+
38+
states := make([]byte, 0, statesC)
39+
for _, state := range key[:statesC] {
40+
states = append(states, state)
41+
}
42+
43+
key = key[len(states):]
44+
45+
if len(key) < 1 {
46+
return nil, nil, nil, nil, fmt.Errorf("%w: invalid state length", ErrInvalidPaginationKey)
47+
}
48+
49+
prefixLength := int(key[0])
50+
51+
key = key[1:]
52+
53+
if len(key) < prefixLength {
54+
return nil, nil, nil, nil, fmt.Errorf("%w: invalid state length", ErrInvalidPaginationKey)
55+
}
56+
57+
prefix := key[:prefixLength]
58+
59+
key = key[prefixLength:]
60+
61+
if len(key) == 0 {
62+
return nil, nil, nil, nil, fmt.Errorf("%w: invalid state length", ErrInvalidPaginationKey)
63+
}
64+
65+
keyLength := int(key[0])
66+
key = key[1:]
67+
68+
if len(key) < keyLength {
69+
return nil, nil, nil, nil, fmt.Errorf("%w: invalid state length", ErrInvalidPaginationKey)
70+
}
71+
72+
pkey := key[:keyLength]
73+
74+
key = key[keyLength:]
75+
var unsolicited []byte
76+
77+
if len(key) > 0 {
78+
keyLength = int(key[0])
79+
key = key[1:]
80+
81+
if len(key) != keyLength {
82+
return nil, nil, nil, nil, fmt.Errorf("%w: invalid state length", ErrInvalidPaginationKey)
83+
}
84+
85+
unsolicited = key
86+
}
87+
88+
return states, prefix, pkey, unsolicited, nil
89+
}
90+
91+
func EncodePaginationKey(states, prefix, key, unsolicited []byte) ([]byte, error) {
92+
if len(states) == 0 {
93+
return nil, fmt.Errorf("%w: states cannot be empty", ErrInvalidPaginationKey)
94+
}
95+
96+
if len(prefix) == 0 {
97+
return nil, fmt.Errorf("%w: prefix cannot be empty", ErrInvalidPaginationKey)
98+
}
99+
100+
if len(key) == 0 {
101+
return nil, fmt.Errorf("%w: key cannot be empty", ErrInvalidPaginationKey)
102+
}
103+
104+
// 4 bytes for checksum
105+
// 1 byte for states count
106+
// len(states) bytes for states
107+
// 1 byte for prefix length
108+
// len(prefix) bytes for prefix
109+
// 1 byte for key length
110+
// len(key) bytes for key
111+
encLen := 4 + 1 + len(states) + 1 + len(prefix) + 1 + len(key)
112+
113+
if len(unsolicited) > 0 {
114+
encLen += 1 + len(unsolicited)
115+
}
116+
117+
buf := make([]byte, encLen)
118+
119+
data := buf[4:]
120+
121+
tmp := validation.MustEncodeWithLengthPrefix(states)
122+
copy(data, tmp)
123+
124+
offset := len(tmp)
125+
tmp = validation.MustEncodeWithLengthPrefix(prefix)
126+
127+
copy(data[offset:], tmp)
128+
offset += len(tmp)
129+
130+
tmp = validation.MustEncodeWithLengthPrefix(key)
131+
copy(data[offset:], tmp)
132+
133+
if len(unsolicited) > 0 {
134+
offset += len(tmp)
135+
tmp = validation.MustEncodeWithLengthPrefix(unsolicited)
136+
copy(data[offset:], tmp)
137+
}
138+
139+
checksum := crc32.ChecksumIEEE(data)
140+
binary.BigEndian.PutUint32(buf, checksum)
141+
142+
return buf, nil
143+
}

0 commit comments

Comments
 (0)