proof_test.gno
8.06 Kb · 222 lines
1package ics23_test
2
3import (
4 "encoding/hex"
5 "testing"
6
7 "gno.land/p/aib/ics23"
8 "gno.land/p/nt/uassert/v0"
9)
10
11func TestProofSpecEqual(t *testing.T) {
12 newLeaf := func() *ics23.LeafOp {
13 return &ics23.LeafOp{
14 Prefix: []byte{0},
15 PrehashKey: ics23.HashOp_NO_HASH,
16 Hash: ics23.HashOp_SHA256,
17 PrehashValue: ics23.HashOp_SHA256,
18 Length: ics23.LengthOp_VAR_PROTO,
19 }
20 }
21 newInner := func() *ics23.InnerSpec {
22 return &ics23.InnerSpec{
23 ChildOrder: []int32{0, 1},
24 MinPrefixLength: 4,
25 MaxPrefixLength: 12,
26 ChildSize: 33,
27 EmptyChild: nil,
28 Hash: ics23.HashOp_SHA256,
29 }
30 }
31 newSpec := func() *ics23.ProofSpec {
32 return &ics23.ProofSpec{
33 LeafSpec: newLeaf(),
34 InnerSpec: newInner(),
35 MaxDepth: 0,
36 MinDepth: 0,
37 PrehashKeyBeforeComparison: false,
38 }
39 }
40
41 testCases := []struct {
42 name string
43 malleate func(a, b *ics23.ProofSpec)
44 expEqual bool
45 }{
46 {"equal — same fresh spec", func(a, b *ics23.ProofSpec) {}, true},
47 {"equal — same as well-known IavlSpec", func(a, b *ics23.ProofSpec) {
48 *a = *ics23.IavlSpec()
49 *b = *ics23.IavlSpec()
50 }, true},
51 {"differ — MaxDepth", func(a, b *ics23.ProofSpec) { b.MaxDepth = 10 }, false},
52 {"differ — MinDepth", func(a, b *ics23.ProofSpec) { b.MinDepth = 1 }, false},
53 {"differ — PrehashKeyBeforeComparison", func(a, b *ics23.ProofSpec) { b.PrehashKeyBeforeComparison = true }, false},
54 {"differ — LeafSpec.Hash", func(a, b *ics23.ProofSpec) { b.LeafSpec.Hash = ics23.HashOp_NO_HASH }, false},
55 {"differ — LeafSpec.PrehashKey", func(a, b *ics23.ProofSpec) { b.LeafSpec.PrehashKey = ics23.HashOp_SHA256 }, false},
56 {"differ — LeafSpec.PrehashValue", func(a, b *ics23.ProofSpec) { b.LeafSpec.PrehashValue = ics23.HashOp_NO_HASH }, false},
57 {"differ — LeafSpec.Length", func(a, b *ics23.ProofSpec) { b.LeafSpec.Length = ics23.LengthOp_NO_PREFIX }, false},
58 {"differ — LeafSpec.Prefix", func(a, b *ics23.ProofSpec) { b.LeafSpec.Prefix = []byte{1} }, false},
59 {"differ — LeafSpec nil vs non-nil", func(a, b *ics23.ProofSpec) { b.LeafSpec = nil }, false},
60 {"differ — InnerSpec.ChildSize", func(a, b *ics23.ProofSpec) { b.InnerSpec.ChildSize = 32 }, false},
61 {"differ — InnerSpec.MinPrefixLength", func(a, b *ics23.ProofSpec) { b.InnerSpec.MinPrefixLength = 1 }, false},
62 {"differ — InnerSpec.MaxPrefixLength", func(a, b *ics23.ProofSpec) { b.InnerSpec.MaxPrefixLength = 99 }, false},
63 {"differ — InnerSpec.Hash", func(a, b *ics23.ProofSpec) { b.InnerSpec.Hash = ics23.HashOp_NO_HASH }, false},
64 {"differ — InnerSpec.ChildOrder length", func(a, b *ics23.ProofSpec) { b.InnerSpec.ChildOrder = []int32{0, 1, 2} }, false},
65 {"differ — InnerSpec.ChildOrder content", func(a, b *ics23.ProofSpec) { b.InnerSpec.ChildOrder = []int32{1, 0} }, false},
66 {"differ — InnerSpec.EmptyChild", func(a, b *ics23.ProofSpec) { b.InnerSpec.EmptyChild = []byte{0, 0, 0} }, false},
67 {"differ — InnerSpec nil vs non-nil", func(a, b *ics23.ProofSpec) { b.InnerSpec = nil }, false},
68 }
69 for _, tc := range testCases {
70 t.Run(tc.name, func(t *testing.T) {
71 a, b := newSpec(), newSpec()
72 tc.malleate(a, b)
73 uassert.Equal(t, tc.expEqual, a.Equal(b), "a.Equal(b)")
74 // Equal must be symmetric.
75 uassert.Equal(t, tc.expEqual, b.Equal(a), "b.Equal(a)")
76 })
77 }
78}
79
80func TestProofSpecEqualNil(t *testing.T) {
81 spec := ics23.IavlSpec()
82
83 var nilSpec *ics23.ProofSpec
84 uassert.True(t, nilSpec.Equal(nil), "nil.Equal(nil) must be true")
85 uassert.False(t, spec.Equal(nil), "non-nil.Equal(nil) must be false")
86 uassert.False(t, nilSpec.Equal(spec), "nil.Equal(non-nil) must be false")
87}
88
89func TestLeafOpEqual(t *testing.T) {
90 var nilOp *ics23.LeafOp
91 uassert.True(t, nilOp.Equal(nil))
92
93 a := &ics23.LeafOp{Hash: ics23.HashOp_SHA256, Prefix: []byte{0x01}}
94 b := &ics23.LeafOp{Hash: ics23.HashOp_SHA256, Prefix: []byte{0x01}}
95 uassert.True(t, a.Equal(b))
96 uassert.False(t, a.Equal(nil))
97
98 b.Prefix = []byte{0x02}
99 uassert.False(t, a.Equal(b))
100}
101
102func TestInnerSpecEqual(t *testing.T) {
103 var nilSpec *ics23.InnerSpec
104 uassert.True(t, nilSpec.Equal(nil))
105
106 a := &ics23.InnerSpec{ChildOrder: []int32{0, 1}, ChildSize: 33, Hash: ics23.HashOp_SHA256}
107 b := &ics23.InnerSpec{ChildOrder: []int32{0, 1}, ChildSize: 33, Hash: ics23.HashOp_SHA256}
108 uassert.True(t, a.Equal(b))
109 uassert.False(t, a.Equal(nil))
110
111 b.ChildSize = 32
112 uassert.False(t, a.Equal(b))
113}
114
115func TestLeafOpProtoMarshal(t *testing.T) {
116 t.Run("nil receiver returns nil", func(t *testing.T) {
117 var nilLeaf *ics23.LeafOp
118 uassert.Equal(t, 0, len(nilLeaf.ProtoMarshal()))
119 })
120
121 t.Run("matches expected wire format for IavlSpec.LeafSpec", func(t *testing.T) {
122 bz := ics23.IavlSpec().LeafSpec.ProtoMarshal()
123 // Field 1 (Hash=SHA256=1): 08 01
124 // Field 2 (PrehashKey=0): omitted
125 // Field 3 (PrehashValue=1): 18 01
126 // Field 4 (Length=VAR_PROTO=1):20 01
127 // Field 5 (Prefix=[0x00]): 2a 01 00
128 uassert.Equal(t, "0801180120012a0100", hex.EncodeToString(bz))
129 })
130}
131
132func TestInnerSpecProtoMarshal(t *testing.T) {
133 t.Run("nil receiver returns nil", func(t *testing.T) {
134 var nilInner *ics23.InnerSpec
135 uassert.Equal(t, 0, len(nilInner.ProtoMarshal()))
136 })
137
138 t.Run("matches expected wire format for IavlSpec.InnerSpec", func(t *testing.T) {
139 bz := ics23.IavlSpec().InnerSpec.ProtoMarshal()
140 // Field 1 (ChildOrder=[0,1] packed): 0a 02 00 01
141 // Field 2 (ChildSize=33): 10 21
142 // Field 3 (MinPrefixLength=4): 18 04
143 // Field 4 (MaxPrefixLength=12): 20 0c
144 // Field 5 (EmptyChild=nil): omitted
145 // Field 6 (Hash=SHA256=1): 30 01
146 uassert.Equal(t, "0a02000110211804200c3001", hex.EncodeToString(bz))
147 })
148}
149
150func TestProofSpecProtoMarshal(t *testing.T) {
151 t.Run("nil receiver returns nil", func(t *testing.T) {
152 var nilSpec *ics23.ProofSpec
153 uassert.Equal(t, 0, len(nilSpec.ProtoMarshal()))
154 })
155
156 t.Run("matches expected wire format for IavlSpec", func(t *testing.T) {
157 bz := ics23.IavlSpec().ProtoMarshal()
158 // Field 1 (LeafSpec, len=9): 0a 09 <leaf bytes>
159 // Field 2 (InnerSpec, len=12):12 0c <inner bytes>
160 // Fields 3,4,5: omitted (zero defaults)
161 want := "0a090801180120012a0100" + "120c0a02000110211804200c3001"
162 uassert.Equal(t, want, hex.EncodeToString(bz))
163 })
164
165 t.Run("optional fields are emitted when set", func(t *testing.T) {
166 spec := &ics23.ProofSpec{
167 MaxDepth: 8,
168 MinDepth: 1,
169 PrehashKeyBeforeComparison: true,
170 }
171 bz := spec.ProtoMarshal()
172 // Field 3 (MaxDepth=8): 18 08
173 // Field 4 (MinDepth=1): 20 01
174 // Field 5 (PrehashKeyBeforeComparison=true): 28 01
175 uassert.Equal(t, "180820012801", hex.EncodeToString(bz))
176 })
177}
178
179func TestIsLeftNeighbor_NoPanicOnEdgeCases(cur realm, t *testing.T) {
180 spec := ics23.IavlSpec().InnerSpec
181 childSize := int(spec.ChildSize)
182
183 validOp := func() *ics23.InnerOp {
184 return &ics23.InnerOp{Prefix: []byte("aaaa"), Suffix: make([]byte, childSize)}
185 }
186 convergingOp := func() *ics23.InnerOp {
187 return &ics23.InnerOp{Prefix: []byte("aaaa"), Suffix: make([]byte, childSize)}
188 }
189 malformedOp := func() *ics23.InnerOp {
190 return &ics23.InnerOp{Prefix: make([]byte, 100), Suffix: nil}
191 }
192
193 cases := []struct {
194 name string
195 left []*ics23.InnerOp
196 right []*ics23.InnerOp
197 expectErr bool
198 }{
199 {"empty left path", nil, []*ics23.InnerOp{validOp()}, false},
200 {"empty right path", []*ics23.InnerOp{validOp()}, nil, false},
201 {"common suffix exhausted", []*ics23.InnerOp{convergingOp()}, []*ics23.InnerOp{convergingOp()}, false},
202 {"malformed left prefix", []*ics23.InnerOp{malformedOp()}, []*ics23.InnerOp{validOp()}, true},
203 {"malformed right prefix", []*ics23.InnerOp{validOp()}, []*ics23.InnerOp{malformedOp()}, true},
204 }
205 for _, tc := range cases {
206 t.Run(tc.name, func(t *testing.T) {
207 var (
208 ok bool
209 err error
210 )
211 uassert.NotPanics(t, cur, func() {
212 ok, err = ics23.IsLeftNeighbor(spec, tc.left, tc.right)
213 })
214 uassert.False(t, ok, "expected isNeighbor=false")
215 if tc.expectErr {
216 uassert.Error(t, err, "expected error for malformed input")
217 } else {
218 uassert.NoError(t, err)
219 }
220 })
221 }
222}