codec.gno
2.76 Kb · 123 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 maxClockDrift,
66 frozenHeight,
67 latestHeight,
68 contractAddress,
69 ), nil
70}
71
72// EncodeConsensusState ABI-encodes a ConsensusState (96 bytes).
73// Root.Hash must be exactly 32 bytes.
74func EncodeConsensusState(cs *ConsensusState) ([]byte, error) {
75 appHash, err := toBytes32(cs.Root.Hash)
76 if err != nil {
77 return nil, err
78 }
79
80 validatorsHash, err := toBytes32(cs.NextValidatorsHash)
81 if err != nil {
82 return nil, err
83 }
84
85 return abienc.Encode(
86 consensusStateSchema,
87 []any{cs.Timestamp, appHash, validatorsHash},
88 )
89}
90
91func DecodeConsensusState(buf []byte) (*ConsensusState, error) {
92 vals, err := abienc.Decode(consensusStateSchema, buf)
93 if err != nil {
94 return nil, err
95 }
96
97 var cs ConsensusState
98
99 rootHash, ok := vals[1].([32]byte)
100 if !ok {
101 return nil, ErrDecodeState
102 }
103
104 nextValidatorsHash, ok := vals[2].([32]byte)
105 if !ok {
106 return nil, ErrDecodeState
107 }
108
109 cs.Timestamp = vals[0].(uint64)
110 cs.Root.Hash = rootHash[:]
111 cs.NextValidatorsHash = nextValidatorsHash[:]
112
113 return &cs, nil
114}
115
116func trimNullBytes(b [32]byte) string {
117 end := 32
118 for end > 0 && b[end-1] == 0 {
119 end--
120 }
121
122 return string(b[:end])
123}