connection.gno
6.04 Kb · 149 lines
1package core
2
3import (
4 "gno.land/p/onbloc/ibc/union/types"
5 core "gno.land/r/onbloc/ibc/union/core"
6)
7
8// connection.gno: the connection handshake logic. The admin gate stays on the
9// proxy entrypoint; this realm holds the protocol logic. The Force* recovery
10// variants (no proof verification) remain on the proxy as admin operations.
11
12// ConnectionOpenInit starts a connection in the Init state.
13func (c *coreV1) ConnectionOpenInit(_ int, rlm realm, msg types.MsgConnectionOpenInit) {
14 assertIsRlmCurrent(0, rlm)
15
16 connectionId := c.store.NextConnectionId(0, rlm)
17 connection := core.NewConnection(types.ConnectionStateInit, msg.ClientId, msg.CounterpartyClientId, 0)
18 c.store.SaveConnection(0, rlm, connectionId, connection)
19 core.EmitConnectionOpenInit(0, rlm, connectionId, msg.ClientId, msg.CounterpartyClientId)
20}
21
22// ConnectionOpenTry acknowledges a counterparty Init by proving it and moving to
23// TryOpen.
24func (c *coreV1) ConnectionOpenTry(_ int, rlm realm, msg types.MsgConnectionOpenTry) {
25 assertIsRlmCurrent(0, rlm)
26
27 c.connectionOpenTry(0, rlm, msg, true)
28}
29
30// ForceConnectionOpenTry is the admin recovery variant of ConnectionOpenTry that
31// skips counterparty proof verification.
32func (c *coreV1) ForceConnectionOpenTry(_ int, rlm realm, msg types.MsgConnectionOpenTry) {
33 assertIsRlmCurrent(0, rlm)
34
35 c.connectionOpenTry(0, rlm, msg, false)
36}
37
38func (c *coreV1) connectionOpenTry(_ int, rlm realm, msg types.MsgConnectionOpenTry, verify bool) {
39 connectionId := c.store.NextConnectionId(0, rlm)
40 connection := core.NewConnection(types.ConnectionStateTryOpen, msg.ClientId, msg.CounterpartyClientId, msg.CounterpartyConnectionId)
41
42 if verify {
43 expectedConnection := core.NewConnection(types.ConnectionStateInit, msg.CounterpartyClientId, msg.ClientId, 0)
44 key := types.ConnectionPath(msg.CounterpartyConnectionId)
45 value := core.ConnectionValue(expectedConnection)
46 c.verifyMembership(msg.ClientId, types.NewHeight(msg.ProofHeight), msg.ProofInit, key[:], value[:])
47 }
48
49 c.store.SaveConnection(0, rlm, connectionId, connection)
50 core.EmitConnectionOpenTry(0, rlm, connectionId, msg.ClientId, msg.CounterpartyClientId, msg.CounterpartyConnectionId)
51}
52
53// ConnectionOpenAck proves the counterparty TryOpen and moves the local Init
54// connection to Open.
55func (c *coreV1) ConnectionOpenAck(_ int, rlm realm, msg types.MsgConnectionOpenAck) {
56 assertIsRlmCurrent(0, rlm)
57
58 c.connectionOpenAck(0, rlm, msg, true)
59}
60
61// ForceConnectionOpenAck is the admin recovery variant of ConnectionOpenAck that
62// skips counterparty proof verification.
63func (c *coreV1) ForceConnectionOpenAck(_ int, rlm realm, msg types.MsgConnectionOpenAck) {
64 assertIsRlmCurrent(0, rlm)
65
66 c.connectionOpenAck(0, rlm, msg, false)
67}
68
69func (c *coreV1) connectionOpenAck(_ int, rlm realm, msg types.MsgConnectionOpenAck, verify bool) {
70 connection, ok := c.store.GetConnection(msg.ConnectionId)
71 if !ok {
72 panic(makeError(core.ErrConnectionNotFound, msg.ConnectionId.String()))
73 }
74
75 if connection.State != types.ConnectionStateInit {
76 panic(makeError(core.ErrInvalidConnectionState))
77 }
78
79 if verify {
80 expectedConnection := core.NewConnection(types.ConnectionStateTryOpen, connection.CounterpartyClientId, connection.ClientId, msg.ConnectionId)
81 key := types.ConnectionPath(msg.CounterpartyConnectionId)
82 value := core.ConnectionValue(expectedConnection)
83 c.verifyMembership(connection.ClientId, types.NewHeight(msg.ProofHeight), msg.ProofTry, key[:], value[:])
84 }
85
86 // Build a fresh connection rather than mutating the store-owned one (the
87 // retrieved value is read-only under the borrow rule).
88 updated := core.NewConnection(types.ConnectionStateOpen, connection.ClientId, connection.CounterpartyClientId, msg.CounterpartyConnectionId)
89 c.store.SaveConnection(0, rlm, msg.ConnectionId, updated)
90
91 core.EmitConnectionOpenAck(0, rlm, msg.ConnectionId, connection.ClientId, connection.CounterpartyClientId, msg.CounterpartyConnectionId)
92}
93
94// ConnectionOpenConfirm proves the counterparty Open and moves the local TryOpen
95// connection to Open.
96func (c *coreV1) ConnectionOpenConfirm(_ int, rlm realm, msg types.MsgConnectionOpenConfirm) {
97 assertIsRlmCurrent(0, rlm)
98
99 c.connectionOpenConfirm(0, rlm, msg, true)
100}
101
102// ForceConnectionOpenConfirm is the admin recovery variant of
103// ConnectionOpenConfirm that skips counterparty proof verification.
104func (c *coreV1) ForceConnectionOpenConfirm(_ int, rlm realm, msg types.MsgConnectionOpenConfirm) {
105 assertIsRlmCurrent(0, rlm)
106
107 c.connectionOpenConfirm(0, rlm, msg, false)
108}
109
110func (c *coreV1) connectionOpenConfirm(_ int, rlm realm, msg types.MsgConnectionOpenConfirm, verify bool) {
111 connection, ok := c.store.GetConnection(msg.ConnectionId)
112 if !ok {
113 panic(makeError(core.ErrConnectionNotFound, msg.ConnectionId.String()))
114 }
115
116 if connection.State != types.ConnectionStateTryOpen {
117 panic(makeError(core.ErrInvalidConnectionState))
118 }
119
120 counterpartyConnectionId := connection.CounterpartyConnectionId
121
122 if verify {
123 expectedConnection := core.NewConnection(types.ConnectionStateOpen, connection.CounterpartyClientId, connection.ClientId, msg.ConnectionId)
124 key := types.ConnectionPath(counterpartyConnectionId)
125 value := core.ConnectionValue(expectedConnection)
126 c.verifyMembership(connection.ClientId, types.NewHeight(msg.ProofHeight), msg.ProofAck, key[:], value[:])
127 }
128
129 // Build a fresh connection rather than mutating the store-owned one.
130 updated := core.NewConnection(types.ConnectionStateOpen, connection.ClientId, connection.CounterpartyClientId, counterpartyConnectionId)
131 c.store.SaveConnection(0, rlm, msg.ConnectionId, updated)
132
133 core.EmitConnectionOpenConfirm(0, rlm, msg.ConnectionId, connection.ClientId, connection.CounterpartyClientId, counterpartyConnectionId)
134}
135
136// ensureConnectionState returns the connection for connectionId, requiring it to
137// be Open.
138func (c *coreV1) ensureConnectionState(connectionId types.ConnectionId) types.Connection {
139 connection, ok := c.store.GetConnection(connectionId)
140 if !ok {
141 panic(makeError(core.ErrConnectionNotFound, connectionId.String()))
142 }
143
144 if connection.State != types.ConnectionStateOpen {
145 panic(makeError(core.ErrInvalidConnectionState))
146 }
147
148 return connection
149}