ethabi.gno
3.64 Kb · 164 lines
1package ics23_mpt
2
3import (
4 "errors"
5
6 abienc "gno.land/p/onbloc/encoding/abi"
7)
8
9var (
10 clientStateSchema = abienc.Schema{Fields: []abienc.Field{
11 {Type: abienc.TypeString},
12 {Type: abienc.TypeUint32},
13 {Type: abienc.TypeUint32},
14 {Type: abienc.TypeUint64},
15 {Type: abienc.TypeUint32},
16 {Type: abienc.TypeUint32},
17 {Type: abienc.TypeUint32},
18 }}
19
20 consensusStateSchema = abienc.Schema{Fields: []abienc.Field{
21 {Type: abienc.TypeUint64},
22 {Type: abienc.TypeBytes32},
23 {Type: abienc.TypeBytes32},
24 }}
25
26 headerSchema = abienc.Schema{Fields: []abienc.Field{
27 {Type: abienc.TypeUint64},
28 {Type: abienc.TypeUint64},
29 {Type: abienc.TypeBytes},
30 {Type: abienc.TypeBytes},
31 }}
32)
33
34func EncodeClientState(cs ClientState) ([]byte, error) {
35 return abienc.Encode(clientStateSchema, []any{
36 cs.L2ChainID,
37 cs.L1ClientID,
38 cs.L2ClientID,
39 uint64(cs.L2LatestHeight),
40 uint32(cs.TimestampOffset),
41 uint32(cs.StateRootOffset),
42 uint32(cs.StorageRootOffset),
43 })
44}
45
46func DecodeClientState(buf []byte) (ClientState, error) {
47 vals, err := abienc.Decode(clientStateSchema, buf)
48 if err != nil {
49 return ClientState{}, wrapErr(err)
50 }
51
52 timestampOffset, err := toUint16(vals[4].(uint32), "timestamp offset")
53 if err != nil {
54 return ClientState{}, err
55 }
56
57 stateRootOffset, err := toUint16(vals[5].(uint32), "state root offset")
58 if err != nil {
59 return ClientState{}, err
60 }
61
62 storageRootOffset, err := toUint16(vals[6].(uint32), "storage root offset")
63 if err != nil {
64 return ClientState{}, err
65 }
66
67 return ClientState{
68 L2ChainID: vals[0].(string),
69 L1ClientID: vals[1].(uint32),
70 L2ClientID: vals[2].(uint32),
71 L2LatestHeight: vals[3].(uint64),
72 TimestampOffset: timestampOffset,
73 StateRootOffset: stateRootOffset,
74 StorageRootOffset: storageRootOffset,
75 }, nil
76}
77
78func EncodeConsensusState(cs ConsensusState) ([]byte, error) {
79 stateRoot, err := toBytes32(cs.StateRoot, "state root")
80 if err != nil {
81 return nil, err
82 }
83
84 storageRoot, err := toBytes32(cs.StorageRoot, "storage root")
85 if err != nil {
86 return nil, err
87 }
88
89 return abienc.Encode(consensusStateSchema, []any{
90 cs.Timestamp,
91 stateRoot,
92 storageRoot,
93 })
94}
95
96func DecodeConsensusState(buf []byte) (ConsensusState, error) {
97 vals, err := abienc.Decode(consensusStateSchema, buf)
98 if err != nil {
99 return ConsensusState{}, wrapErr(err)
100 }
101
102 stateRoot := vals[1].([32]byte)
103 storageRoot := vals[2].([32]byte)
104
105 return ConsensusState{
106 Timestamp: vals[0].(uint64),
107 StateRoot: cloneBytes(stateRoot[:]),
108 StorageRoot: cloneBytes(storageRoot[:]),
109 }, nil
110}
111
112func EncodeHeader(h Header) ([]byte, error) {
113 return abienc.Encode(headerSchema, []any{
114 uint64(h.L1Height),
115 uint64(h.L2Height),
116 h.L2ConsensusStateProof,
117 h.L2ConsensusState,
118 })
119}
120
121func DecodeHeader(buf []byte) (Header, error) {
122 vals, err := abienc.Decode(headerSchema, buf)
123 if err != nil {
124 return Header{}, wrapErr(err)
125 }
126
127 return Header{
128 L1Height: vals[0].(uint64),
129 L2Height: vals[1].(uint64),
130 L2ConsensusStateProof: vals[2].([]byte),
131 L2ConsensusState: vals[3].([]byte),
132 }, nil
133}
134
135// wrapErr prefixes a wrapped decode error with the package domain.
136func wrapErr(err error) error {
137 return errors.New("ics23mpt: " + err.Error())
138}
139
140func toUint16(v uint32, name string) (uint16, error) {
141 if v > 0xFFFF {
142 return 0, errors.New("ics23mpt: " + name + " exceeds uint16")
143 }
144
145 return uint16(v), nil
146}
147
148func toBytes32(b []byte, name string) ([32]byte, error) {
149 if len(b) != 32 {
150 return [32]byte{}, errors.New("ics23mpt: " + name + " must be 32 bytes")
151 }
152
153 var out [32]byte
154 copy(out[:], b)
155
156 return out, nil
157}
158
159func cloneBytes(b []byte) []byte {
160 out := make([]byte, len(b))
161 copy(out, b)
162
163 return out
164}