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

codec.gno

2.61 Kb · 141 lines
  1package storage
  2
  3import (
  4	"encoding/binary"
  5	"errors"
  6)
  7
  8var (
  9	ErrInvalidProofBytes  = errors.New("storage: invalid proof bytes")
 10	ErrTrailingProofBytes = errors.New("storage: trailing proof bytes")
 11)
 12
 13// DecodeProof decodes Union's ethereum_light_client_types::StorageProof
 14// bincode wire form into the normalized Proof shape used by this package.
 15//
 16// Wire layout with fixed-int/little-endian bincode:
 17//   - key: U256 as 32 little-endian bytes
 18//   - value: U256 as 32 little-endian bytes
 19//   - proof: Vec<Bytes> as u64 length followed by repeated byte vectors
 20func DecodeProof(buf []byte) (Proof, error) {
 21	d := proofDecoder{buf: buf}
 22
 23	key, err := d.readU256()
 24	if err != nil {
 25		return Proof{}, err
 26	}
 27
 28	value, err := d.readU256()
 29	if err != nil {
 30		return Proof{}, err
 31	}
 32
 33	count, err := d.readUint64()
 34	if err != nil {
 35		return Proof{}, err
 36	}
 37
 38	if count > uint64(len(buf)) {
 39		return Proof{}, ErrInvalidProofBytes
 40	}
 41
 42	proof := make([][]byte, int(count))
 43	for i := 0; i < int(count); i++ {
 44		proof[i], err = d.readBytes()
 45		if err != nil {
 46			return Proof{}, err
 47		}
 48	}
 49
 50	if d.pos != len(buf) {
 51		return Proof{}, ErrTrailingProofBytes
 52	}
 53
 54	return Proof{Key: key, Value: value, Proof: proof}, nil
 55}
 56
 57func EncodeProof(proof Proof) []byte {
 58	var out []byte
 59
 60	out = append(out, reverse32(proof.Key)...)
 61	out = append(out, reverse32(proof.Value)...)
 62	out = appendUint64LE(out, uint64(len(proof.Proof)))
 63
 64	for _, node := range proof.Proof {
 65		out = appendUint64LE(out, uint64(len(node)))
 66		out = append(out, node...)
 67	}
 68
 69	return out
 70}
 71
 72type proofDecoder struct {
 73	buf []byte
 74	pos int
 75}
 76
 77func (d *proofDecoder) readU256() ([]byte, error) {
 78	if d.pos+32 > len(d.buf) {
 79		return nil, ErrInvalidProofBytes
 80	}
 81
 82	le := d.buf[d.pos : d.pos+32]
 83	d.pos += 32
 84
 85	out := make([]byte, 32)
 86	for i := 0; i < 32; i++ {
 87		out[i] = le[31-i]
 88	}
 89
 90	return out, nil
 91}
 92
 93func (d *proofDecoder) readBytes() ([]byte, error) {
 94	n, err := d.readUint64()
 95	if err != nil {
 96		return nil, err
 97	}
 98
 99	if n > uint64(len(d.buf)-d.pos) {
100		return nil, ErrInvalidProofBytes
101	}
102
103	out := make([]byte, int(n))
104	copy(out, d.buf[d.pos:d.pos+int(n)])
105	d.pos += int(n)
106
107	return out, nil
108}
109
110func (d *proofDecoder) readUint64() (uint64, error) {
111	if d.pos+8 > len(d.buf) {
112		return 0, ErrInvalidProofBytes
113	}
114
115	v := binary.LittleEndian.Uint64(d.buf[d.pos : d.pos+8])
116	d.pos += 8
117
118	return v, nil
119}
120
121func appendUint64LE(out []byte, v uint64) []byte {
122	var word [8]byte
123	binary.LittleEndian.PutUint64(word[:], v)
124
125	return append(out, word[:]...)
126}
127
128func reverse32(b []byte) []byte {
129	out := make([]byte, 32)
130
131	n := len(b)
132	if n > 32 {
133		n = 32
134	}
135
136	for i := 0; i < n; i++ {
137		out[i] = b[len(b)-1-i]
138	}
139
140	return out
141}