codec.gno
2.76 Kb · 124 lines
1package cometbls
2
3import (
4 abienc "gno.land/p/onbloc/encoding/abi"
5 "gno.land/p/onbloc/ibc/union/types"
6)
7
8// Wire formats for the cometbls client and consensus state.
9//
10// ibc-union heights carry a single revision (revision 0), so only the revision
11// height is encoded; decoding rebuilds the Height with types.NewHeight.
12
13var clientStateSchema = abienc.Schema{Fields: []abienc.Field{
14 {Type: abienc.TypeBytes32},
15 {Type: abienc.TypeUint64},
16 {Type: abienc.TypeUint64},
17 {Type: abienc.TypeUint64},
18 {Type: abienc.TypeUint64},
19 {Type: abienc.TypeBytes32},
20}}
21
22var consensusStateSchema = abienc.Schema{Fields: []abienc.Field{
23 {Type: abienc.TypeUint64}, // Timestamp
24 {Type: abienc.TypeBytes32}, // Root (app hash)
25 {Type: abienc.TypeBytes32}, // NextValidatorsHash
26}}
27
28func EncodeClientState(m *ClientState) ([]byte, error) {
29 var chainIdWord [32]byte
30
31 chainBytes := []byte(m.ChainID)
32 if len(chainBytes) > 31 {
33 chainBytes = chainBytes[:31]
34 }
35
36 copy(chainIdWord[:], chainBytes)
37
38 return abienc.Encode(clientStateSchema, []any{
39 chainIdWord,
40 m.TrustingPeriod,
41 m.MaxClockDrift,
42 uint64(m.FrozenHeight.RevisionHeight),
43 uint64(m.LatestHeight.RevisionHeight),
44 [32]byte(m.ContractAddress),
45 })
46}
47
48func DecodeClientState(buf []byte) (*ClientState, error) {
49 vals, err := abienc.Decode(clientStateSchema, buf)
50 if err != nil {
51 return nil, err
52 }
53
54 chainIdWord := vals[0].([32]byte)
55 chainID := trimNullBytes(chainIdWord)
56 trustingPeriod := vals[1].(uint64)
57 maxClockDrift := vals[2].(uint64)
58 frozenHeight := types.NewHeight(vals[3].(uint64))
59 latestHeight := types.NewHeight(vals[4].(uint64))
60 contractAddress := vals[5].([32]byte)
61
62 return NewClientState(
63 chainID,
64 trustingPeriod,
65 0,
66 maxClockDrift,
67 frozenHeight,
68 latestHeight,
69 contractAddress,
70 ), nil
71}
72
73// EncodeConsensusState ABI-encodes a ConsensusState (96 bytes).
74// Root.Hash must be exactly 32 bytes.
75func EncodeConsensusState(cs *ConsensusState) ([]byte, error) {
76 appHash, err := toBytes32(cs.Root.Hash)
77 if err != nil {
78 return nil, err
79 }
80
81 validatorsHash, err := toBytes32(cs.NextValidatorsHash)
82 if err != nil {
83 return nil, err
84 }
85
86 return abienc.Encode(
87 consensusStateSchema,
88 []any{cs.Timestamp, appHash, validatorsHash},
89 )
90}
91
92func DecodeConsensusState(buf []byte) (*ConsensusState, error) {
93 vals, err := abienc.Decode(consensusStateSchema, buf)
94 if err != nil {
95 return nil, err
96 }
97
98 var cs ConsensusState
99
100 rootHash, ok := vals[1].([32]byte)
101 if !ok {
102 return nil, ErrDecodeState
103 }
104
105 nextValidatorsHash, ok := vals[2].([32]byte)
106 if !ok {
107 return nil, ErrDecodeState
108 }
109
110 cs.Timestamp = vals[0].(uint64)
111 cs.Root.Hash = rootHash[:]
112 cs.NextValidatorsHash = nextValidatorsHash[:]
113
114 return &cs, nil
115}
116
117func trimNullBytes(b [32]byte) string {
118 end := 32
119 for end > 0 && b[end-1] == 0 {
120 end--
121 }
122
123 return string(b[:end])
124}