Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

proto.gno

6.59 Kb · 359 lines
  1package cometbls
  2
  3import (
  4	"errors"
  5
  6	"gno.land/p/aib/encoding/proto"
  7	"gno.land/p/aib/ics23"
  8)
  9
 10// DecodeProofs decodes a protobuf-encoded MerkleProof (repeated CommitmentProof field 1).
 11func DecodeProofs(buf []byte) ([]ics23.CommitmentProof, error) {
 12	var out []ics23.CommitmentProof
 13
 14	pos := 0
 15
 16	for pos < len(buf) {
 17		fieldNum, wireType, newPos, err := decodeTag(buf, pos)
 18		if err != nil {
 19			return nil, err
 20		}
 21
 22		pos = newPos
 23
 24		if wireType != proto.LEN {
 25			pos, err = skipField(buf, pos, wireType)
 26			if err != nil {
 27				return nil, err
 28			}
 29
 30			continue
 31		}
 32
 33		s, newPos, err := proto.DecodeString(buf, pos)
 34		if err != nil {
 35			return nil, err
 36		}
 37
 38		pos = newPos
 39		b := []byte(s)
 40
 41		if fieldNum != 1 {
 42			continue
 43		}
 44
 45		cp, err := decodeCommitmentProof(b)
 46		if err != nil {
 47			return nil, err
 48		}
 49
 50		out = append(out, cp)
 51	}
 52
 53	return out, nil
 54}
 55
 56func decodeCommitmentProof(buf []byte) (ics23.CommitmentProof, error) {
 57	pos := 0
 58
 59	for pos < len(buf) {
 60		fieldNum, wireType, newPos, err := decodeTag(buf, pos)
 61		if err != nil {
 62			return nil, err
 63		}
 64
 65		pos = newPos
 66
 67		if wireType != proto.LEN {
 68			pos, err = skipField(buf, pos, wireType)
 69			if err != nil {
 70				return nil, err
 71			}
 72
 73			continue
 74		}
 75
 76		s, newPos, err := proto.DecodeString(buf, pos)
 77		if err != nil {
 78			return nil, err
 79		}
 80
 81		pos = newPos
 82		b := []byte(s)
 83
 84		switch fieldNum {
 85		case 1:
 86			ep, err := decodeExistenceProof(b)
 87			if err != nil {
 88				return nil, err
 89			}
 90
 91			return ics23.CommitmentProof_Exist{Exist: ep}, nil
 92		case 2:
 93			nep, err := decodeNonExistenceProof(b)
 94			if err != nil {
 95				return nil, err
 96			}
 97
 98			return ics23.CommitmentProof_Nonexist{Nonexist: nep}, nil
 99		}
100	}
101
102	return nil, errors.New("empty commitment proof")
103}
104
105func decodeExistenceProof(buf []byte) (*ics23.ExistenceProof, error) {
106	ep := &ics23.ExistenceProof{Path: make([]*ics23.InnerOp, 0, 32)}
107	pos := 0
108
109	for pos < len(buf) {
110		fieldNum, wireType, newPos, err := decodeTag(buf, pos)
111		if err != nil {
112			return nil, err
113		}
114
115		pos = newPos
116
117		switch {
118		case (fieldNum == 1 || fieldNum == 2) && wireType == proto.LEN:
119			s, newPos, err := proto.DecodeString(buf, pos)
120			if err != nil {
121				return nil, err
122			}
123
124			pos = newPos
125			b := []byte(s)
126
127			if fieldNum == 1 {
128				ep.Key = b
129			} else {
130				ep.Value = b
131			}
132
133		case fieldNum == 3 && wireType == proto.LEN:
134			s, newPos, err := proto.DecodeString(buf, pos)
135			if err != nil {
136				return nil, err
137			}
138
139			pos = newPos
140			b := []byte(s)
141
142			ep.Leaf, err = decodeLeafOp(b)
143			if err != nil {
144				return nil, err
145			}
146		case fieldNum == 4 && wireType == proto.LEN:
147			s, newPos, err := proto.DecodeString(buf, pos)
148			if err != nil {
149				return nil, err
150			}
151
152			pos = newPos
153			b := []byte(s)
154
155			inner, err := decodeInnerOp(b)
156			if err != nil {
157				return nil, err
158			}
159
160			ep.Path = append(ep.Path, inner)
161		default:
162			pos, err = skipField(buf, pos, wireType)
163			if err != nil {
164				return nil, err
165			}
166		}
167	}
168
169	return ep, nil
170}
171
172func decodeLeafOp(buf []byte) (*ics23.LeafOp, error) {
173	lop := &ics23.LeafOp{}
174	pos := 0
175
176	for pos < len(buf) {
177		fieldNum, wireType, newPos, err := decodeTag(buf, pos)
178		if err != nil {
179			return nil, err
180		}
181
182		pos = newPos
183
184		switch {
185		case fieldNum >= 1 && fieldNum <= 4 && wireType == proto.VARINT:
186			v, newPos, err := proto.DecodeVarint(buf, pos)
187			if err != nil {
188				return nil, err
189			}
190
191			pos = newPos
192
193			switch fieldNum {
194			case 1:
195				lop.Hash = ics23.HashOp(v)
196			case 2:
197				lop.PrehashKey = ics23.HashOp(v)
198			case 3:
199				lop.PrehashValue = ics23.HashOp(v)
200			case 4:
201				lop.Length = ics23.LengthOp(v)
202			}
203		case fieldNum == 5 && wireType == proto.LEN:
204			s, newPos, err := proto.DecodeString(buf, pos)
205			if err != nil {
206				return nil, err
207			}
208
209			pos = newPos
210			b := []byte(s)
211			lop.Prefix = b
212		default:
213			pos, err = skipField(buf, pos, wireType)
214			if err != nil {
215				return nil, err
216			}
217		}
218	}
219
220	return lop, nil
221}
222
223func decodeInnerOp(buf []byte) (*ics23.InnerOp, error) {
224	iop := &ics23.InnerOp{}
225
226	pos := 0
227	for pos < len(buf) {
228		fieldNum, wireType, newPos, err := decodeTag(buf, pos)
229		if err != nil {
230			return nil, err
231		}
232
233		pos = newPos
234
235		switch {
236		case fieldNum == 1 && wireType == proto.VARINT:
237			v, newPos, err := proto.DecodeVarint(buf, pos)
238			if err != nil {
239				return nil, err
240			}
241
242			pos = newPos
243			iop.Hash = ics23.HashOp(v)
244		case (fieldNum == 2 || fieldNum == 3) && wireType == proto.LEN:
245			s, newPos, err := proto.DecodeString(buf, pos)
246			if err != nil {
247				return nil, err
248			}
249
250			pos = newPos
251
252			b := []byte(s)
253			if fieldNum == 2 {
254				iop.Prefix = b
255			} else {
256				iop.Suffix = b
257			}
258		default:
259			pos, err = skipField(buf, pos, wireType)
260			if err != nil {
261				return nil, err
262			}
263		}
264	}
265
266	return iop, nil
267}
268
269func decodeNonExistenceProof(buf []byte) (*ics23.NonExistenceProof, error) {
270	nep := &ics23.NonExistenceProof{}
271	pos := 0
272
273	for pos < len(buf) {
274		fieldNum, wireType, newPos, err := decodeTag(buf, pos)
275		if err != nil {
276			return nil, err
277		}
278
279		pos = newPos
280		if wireType != proto.LEN {
281			pos, err = skipField(buf, pos, wireType)
282			if err != nil {
283				return nil, err
284			}
285
286			continue
287		}
288
289		s, newPos, err := proto.DecodeString(buf, pos)
290		if err != nil {
291			return nil, err
292		}
293
294		pos = newPos
295		b := []byte(s)
296
297		switch fieldNum {
298		case 1:
299			nep.Key = b
300		case 2:
301			ep, err := decodeExistenceProof(b)
302			if err != nil {
303				return nil, err
304			}
305
306			nep.Left = ep
307		case 3:
308			ep, err := decodeExistenceProof(b)
309			if err != nil {
310				return nil, err
311			}
312
313			nep.Right = ep
314		}
315	}
316
317	return nep, nil
318}
319
320// decodeTag reads a protobuf tag at pos and splits it into the field number and
321// wire type. It is built on top of proto.DecodeVarint.
322func decodeTag(buf []byte, pos int) (fieldNum int, wireType proto.WireType, newPos int, err error) {
323	tag, newPos, err := proto.DecodeVarint(buf, pos)
324	if err != nil {
325		return 0, 0, newPos, err
326	}
327
328	return int(tag >> 3), proto.WireType(tag & 0x7), newPos, nil
329}
330
331// skipField advances pos past a field whose value should be ignored, according
332// to its wire type. Only the wire types used by the ICS23 proof messages are
333// supported.
334func skipField(buf []byte, pos int, wireType proto.WireType) (int, error) {
335	switch wireType {
336	case proto.VARINT:
337		_, newPos, err := proto.DecodeVarint(buf, pos)
338
339		return newPos, err
340	case proto.LEN:
341		_, newPos, err := proto.DecodeString(buf, pos)
342
343		return newPos, err
344	case proto.FIXED64:
345		if pos+8 > len(buf) {
346			return pos, errors.New("buffer underflow while skipping fixed64")
347		}
348
349		return pos + 8, nil
350	case proto.FIXED32:
351		if pos+4 > len(buf) {
352			return pos, errors.New("buffer underflow while skipping fixed32")
353		}
354
355		return pos + 4, nil
356	default:
357		return pos, errors.New("unsupported wire type")
358	}
359}