store.gno
21.74 Kb · 693 lines
1package core
2
3import (
4 "chain/params"
5 "encoding/hex"
6
7 "gno.land/p/nt/bptree/v0"
8 "gno.land/p/nt/seqid/v0"
9 "gno.land/p/onbloc/ibc/union/app"
10 "gno.land/p/onbloc/ibc/union/lightclient"
11 "gno.land/p/onbloc/ibc/union/types"
12)
13
14var (
15 store *Store
16 proxyPkgPath string
17)
18
19func init(cur realm) {
20 store = newStore()
21 proxyPkgPath = cur.PkgPath()
22}
23
24// Store is the proxy-owned persistent state. It is a flat data layer: clients,
25// connections, channels, and commitments are keyed directly by their globally
26// allocated id or storage path, with no cross-entity indirection. All protocol
27// logic — handshake state machines, the acknowledge/timeout flow, proof
28// verification — lives in the impl (core/v1). The Store only stores and
29// retrieves, mirroring commitment values into chain params so counterparties
30// can prove them.
31type Store struct {
32 clientSeq seqid.ID
33 clientRegistry map[string]lightclient.ClientImpl // ClientRegistry: type → factory
34 clientTypeByID map[uint32]types.ClientType // ClientTypes: clientId → type
35 clientImplByID map[uint32]lightclient.ClientImpl // ClientImpls: clientId → factory
36 clientByID map[uint32]*client // clientId → instantiated state
37
38 connectionSeq seqid.ID
39 connections *bptree.BPTree // connectionKey(ConnectionId) → types.Connection
40
41 channelSeq seqid.ID
42 channels *bptree.BPTree // channelKey(ChannelId) → *channelEntry
43
44 // commitments holds every packet/batch commitment keyed by its global storage
45 // path. The path derivations (packet commitment, packet receipt, batch packets,
46 // batch receipts) are namespaced so they never collide, so a single flat map
47 // replaces the former per-client batch trees. Membership proofs keep their own
48 // maps because they are read back by a different key shape.
49 commitments map[types.H256]types.H256
50 membershipProofs map[types.H256]types.H256
51 nonMembershipProofs map[types.H256]types.H256
52
53 ports map[string]app.IApp
54}
55
56type client struct {
57 id types.ClientId
58 creator address
59 lightClient lightclient.Interface
60 clientState []byte
61 consensusByHeight *bptree.BPTree // string(height.Bytes()) → []byte
62 // clientStore holds the light client's own key/value storage writes
63 // (lightclient result StorageWrites). It stays per-client because the keys
64 // are opaque to the host; the flat commitment map only covers host-derived
65 // commitment paths.
66 clientStore map[string][]byte
67}
68
69type channelEntry struct {
70 channel types.Channel
71 portId types.Bytes
72}
73
74func newStore() *Store {
75 return &Store{
76 clientRegistry: make(map[string]lightclient.ClientImpl),
77 clientTypeByID: make(map[uint32]types.ClientType),
78 clientImplByID: make(map[uint32]lightclient.ClientImpl),
79 clientByID: make(map[uint32]*client),
80 connections: bptree.NewBPTree32(),
81 channels: bptree.NewBPTree32(),
82 commitments: make(map[types.H256]types.H256),
83 membershipProofs: make(map[types.H256]types.H256),
84 nonMembershipProofs: make(map[types.H256]types.H256),
85 ports: make(map[string]app.IApp),
86 }
87}
88
89// The Store satisfies the IStore interface the impl is injected with. Each
90// adapter routes to the flat data primitives below. Setters take the borrow-rule
91// (_ int, rlm realm, ...) form; the realm token is threaded by the caller and
92// unused here because the underlying writes already run in the proxy's ownership
93// context.
94var _ IStore = (*Store)(nil)
95
96// RegisterClient stores a factory function for typ in the client registry.
97func (s *Store) RegisterClient(_ int, rlm realm, typ types.ClientType, impl lightclient.ClientImpl) {
98 assertIsRlmCurrent(0, rlm)
99
100 s.registerClient(typ, impl)
101}
102
103// ClientRegistry returns the registered factory for typ.
104func (s *Store) ClientRegistry(typ types.ClientType) (lightclient.ClientImpl, bool) {
105 return s.clientRegistryEntry(typ)
106}
107
108// HasRegisteredClient reports whether a factory is registered for typ.
109func (s *Store) HasRegisteredClient(typ types.ClientType) bool {
110 _, found := s.clientRegistryEntry(typ)
111 return found
112}
113
114// AddClient allocates a new client id and stores the light client object,
115// returning the assigned id.
116func (s *Store) AddClient(_ int, rlm realm, typ types.ClientType, creator address, lc lightclient.Interface) types.ClientId {
117 assertIsRlmCurrent(0, rlm)
118
119 return s.addClient(s.nextClientId(), typ, creator, lc).id
120}
121
122// GetClientImpl returns the factory stored for clientId.
123func (s *Store) GetClientImpl(clientId types.ClientId) (lightclient.ClientImpl, bool) {
124 impl, found := s.clientImplByID[uint32(clientId)]
125 return impl, found
126}
127
128// SaveClientStore records a light client storage write (result StorageWrites),
129// returning false when the client is unknown.
130func (s *Store) SaveClientStore(_ int, rlm realm, clientId types.ClientId, key string, value []byte) bool {
131 assertIsRlmCurrent(0, rlm)
132
133 c := s.getClient(clientId)
134 if c == nil {
135 return false
136 }
137
138 c.saveClientStore(key, value)
139
140 return true
141}
142
143// ClientExists reports whether a client is registered under clientId.
144func (s *Store) ClientExists(clientId types.ClientId) bool {
145 _, found := s.clientTypeByID[uint32(clientId)]
146 return found
147}
148
149// ClientType returns the registered client type for clientId.
150func (s *Store) ClientType(clientId types.ClientId) (types.ClientType, bool) {
151 typ, found := s.clientTypeByID[uint32(clientId)]
152 return typ, found
153}
154
155// GetLightClient returns the stored light client object for clientId.
156func (s *Store) GetLightClient(clientId types.ClientId) (lightclient.Interface, bool) {
157 return s.lightClientOf(clientId)
158}
159
160// SetLightClient replaces a client's light client object (force-update recovery),
161// returning false when the client is unknown.
162func (s *Store) SetLightClient(_ int, rlm realm, clientId types.ClientId, lc lightclient.Interface) bool {
163 assertIsRlmCurrent(0, rlm)
164
165 c := s.getClient(clientId)
166 if c == nil {
167 return false
168 }
169
170 c.lightClient = lc
171
172 return true
173}
174
175// SaveClientState mirrors the client state bytes for queries and counterparty
176// proofs, returning false when the client is unknown.
177func (s *Store) SaveClientState(_ int, rlm realm, clientId types.ClientId, clientStateBytes []byte) bool {
178 assertIsRlmCurrent(0, rlm)
179
180 c := s.getClient(clientId)
181 if c == nil {
182 return false
183 }
184
185 c.saveClientState(clientStateBytes)
186
187 return true
188}
189
190// SaveConsensusState records the consensus state at height, returning false when
191// the client is unknown.
192func (s *Store) SaveConsensusState(_ int, rlm realm, clientId types.ClientId, height types.Height, consensusStateBytes []byte) bool {
193 assertIsRlmCurrent(0, rlm)
194
195 c := s.getClient(clientId)
196 if c == nil {
197 return false
198 }
199
200 c.saveConsensusState(height, consensusStateBytes)
201
202 return true
203}
204
205// NextConnectionId allocates the next connection id from the sequence.
206func (s *Store) NextConnectionId(_ int, rlm realm) types.ConnectionId {
207 assertIsRlmCurrent(0, rlm)
208
209 return s.nextConnectionId()
210}
211
212// SaveConnection persists a connection and mirrors its commitment.
213func (s *Store) SaveConnection(_ int, rlm realm, connectionId types.ConnectionId, connection types.Connection) {
214 assertIsRlmCurrent(0, rlm)
215
216 s.saveConnection(connectionId, connection)
217}
218
219// GetConnection returns the stored connection for connectionId.
220func (s *Store) GetConnection(connectionId types.ConnectionId) (types.Connection, bool) {
221 return s.getConnection(connectionId)
222}
223
224// NextChannelId allocates the next channel id from the sequence.
225func (s *Store) NextChannelId(_ int, rlm realm) types.ChannelId {
226 assertIsRlmCurrent(0, rlm)
227
228 return s.nextChannelId()
229}
230
231// CreateChannel persists a new channel owned by portId and mirrors its commitment.
232func (s *Store) CreateChannel(_ int, rlm realm, channelId types.ChannelId, channel types.Channel, portId types.Bytes) {
233 assertIsRlmCurrent(0, rlm)
234
235 s.createChannel(channelId, channel, portId)
236}
237
238// SaveChannel updates a stored channel and mirrors its commitment.
239func (s *Store) SaveChannel(_ int, rlm realm, channelId types.ChannelId, channel types.Channel) {
240 assertIsRlmCurrent(0, rlm)
241
242 s.saveChannel(channelId, channel)
243}
244
245// GetChannels returns all stored channel records.
246// The bptree callback returns false to keep iterating (returning true stops early),
247// and the empty range bounds walk every entry.
248func (s *Store) GetChannels() ([]types.Channel, error) {
249 channels := make([]types.Channel, 0)
250
251 s.channels.Iterate("", "", func(key string, value any) bool {
252 entry, ok := value.(*channelEntry)
253 if !ok {
254 return false
255 }
256
257 channels = append(channels, entry.channel)
258
259 return false
260 })
261
262 return channels, nil
263}
264
265// GetChannel returns the stored channel for channelId.
266func (s *Store) GetChannel(channelId types.ChannelId) (types.Channel, bool) {
267 entry, ok := s.getChannelEntry(channelId)
268 if !ok {
269 return types.Channel{}, false
270 }
271
272 return entry.channel, true
273}
274
275// GetChannelOwner returns the port id that owns channelId.
276func (s *Store) GetChannelOwner(channelId types.ChannelId) (types.Bytes, bool) {
277 entry, ok := s.getChannelEntry(channelId)
278 if !ok {
279 return nil, false
280 }
281
282 return entry.portId, true
283}
284
285// GetAppByPortId returns the IBC app registered at portId.
286func (s *Store) GetAppByPortId(portId types.Bytes) (app.IApp, bool) {
287 a, ok := s.ports[portKey(portId)]
288
289 return a, ok
290}
291
292// HasApp reports whether an app is registered at portId.
293func (s *Store) HasApp(portId types.Bytes) bool {
294 _, ok := s.ports[portKey(portId)]
295
296 return ok
297}
298
299// RegisterAppAtPort installs an app at portId, panicking if one is already
300// registered there.
301func (s *Store) RegisterAppAtPort(_ int, rlm realm, portId types.Bytes, a app.IApp) {
302 assertIsRlmCurrent(0, rlm)
303
304 key := portKey(portId)
305 if _, ok := s.ports[key]; ok {
306 panic("port " + string(portId) + " already registered")
307 }
308
309 s.ports[key] = a
310}
311
312// HasPacketCommitment reports whether the source-side packet commitment exists.
313func (s *Store) HasPacketCommitment(packet types.Packet) bool {
314 _, found := s.getCommitment(packetCommitmentPath(packet))
315 return found
316}
317
318// CommitPacket records the source-side commitment for a sent packet.
319func (s *Store) CommitPacket(_ int, rlm realm, packet types.Packet) {
320 assertIsRlmCurrent(0, rlm)
321
322 s.setCommitment(packetCommitmentPath(packet), types.COMMITMENT_MAGIC)
323}
324
325// SetPacketAcknowledged flips a source-side commitment to the acknowledged
326// marker. It is a pure write: the impl owns the state machine (verifying the
327// commitment exists and is not already acknowledged) before calling this. The
328// flip stays in memory only — the chain-param commitment keeps recording that
329// the packet was sent.
330func (s *Store) SetPacketAcknowledged(_ int, rlm realm, packet types.Packet) {
331 assertIsRlmCurrent(0, rlm)
332
333 s.setCommitmentMem(packetCommitmentPath(packet), types.COMMITMENT_MAGIC_ACK)
334}
335
336// HasPacketReceipt reports whether a destination-side receipt exists.
337func (s *Store) HasPacketReceipt(packet types.Packet) bool {
338 _, found := s.getCommitment(packetAcknowledgementPath(packet))
339 return found
340}
341
342// SetPacketReceipt records a destination-side receipt (replay protection).
343func (s *Store) SetPacketReceipt(_ int, rlm realm, packet types.Packet) {
344 assertIsRlmCurrent(0, rlm)
345
346 s.setCommitment(packetAcknowledgementPath(packet), types.COMMITMENT_MAGIC)
347}
348
349// CommitAcknowledgement records the acknowledgement for a received packet.
350func (s *Store) CommitAcknowledgement(_ int, rlm realm, packet types.Packet, ack []byte) {
351 assertIsRlmCurrent(0, rlm)
352
353 s.setCommitment(packetAcknowledgementPath(packet), types.CommitAcks([][]byte{ack}))
354}
355
356// AcknowledgementReceipt returns the receipt stored at a packet's ack path.
357func (s *Store) AcknowledgementReceipt(channelId types.ChannelId, packet types.Packet) (types.H256, bool) {
358 return s.getCommitment(packetAcknowledgementPath(packet))
359}
360
361// PacketCommitment returns the commitment stored at a packet's commitment path.
362func (s *Store) PacketCommitment(channelId types.ChannelId, packet types.Packet) (types.H256, bool) {
363 return s.getCommitment(packetCommitmentPath(packet))
364}
365
366// SaveBatchPackets records a batch commitment under batchHash.
367func (s *Store) SaveBatchPackets(_ int, rlm realm, channelId types.ChannelId, batchHash, value types.H256) {
368 assertIsRlmCurrent(0, rlm)
369
370 s.setCommitment(types.BatchPacketsPath(batchHash), value)
371}
372
373// SaveBatchReceipts records a batch receipt under batchHash.
374func (s *Store) SaveBatchReceipts(_ int, rlm realm, channelId types.ChannelId, batchHash, value types.H256) {
375 assertIsRlmCurrent(0, rlm)
376
377 s.setCommitment(types.BatchReceiptsPath(batchHash), value)
378}
379
380// SaveMembershipProof records a verified membership commitment.
381func (s *Store) SaveMembershipProof(_ int, rlm realm, clientId types.ClientId, proofHeight uint64, path []byte, value types.H256) {
382 assertIsRlmCurrent(0, rlm)
383
384 s.saveMembershipProof(clientId, proofHeight, path, value)
385}
386
387// SaveNonMembershipProof records a verified non-membership commitment.
388func (s *Store) SaveNonMembershipProof(_ int, rlm realm, clientId types.ClientId, proofHeight uint64, path []byte, value types.H256) {
389 assertIsRlmCurrent(0, rlm)
390
391 s.saveNonMembershipProof(clientId, proofHeight, path, value)
392}
393
394// ClientStateBytes returns the mirrored client state bytes for a client.
395func (s *Store) ClientStateBytes(clientId types.ClientId) ([]byte, bool) {
396 c := s.getClient(clientId)
397 if c == nil || len(c.clientState) == 0 {
398 return nil, false
399 }
400
401 return types.CloneBytes(c.clientState), true
402}
403
404// ConsensusStateBytes returns the consensus state bytes at a height.
405func (s *Store) ConsensusStateBytes(clientId types.ClientId, height types.Height) ([]byte, bool) {
406 c := s.getClient(clientId)
407 if c == nil {
408 return nil, false
409 }
410
411 return c.getConsensusState(height)
412}
413
414// BatchPacketsAt returns the batch packet commitment for a batch hash. The
415// commitment is keyed by the global batch path, so no channel id is required.
416func (s *Store) BatchPacketsAt(batchHash types.H256) (types.H256, bool) {
417 return s.getCommitment(types.BatchPacketsPath(batchHash))
418}
419
420// BatchReceiptsAt returns the batch receipt commitment for a batch hash. The
421// commitment is keyed by the global batch path, so no channel id is required.
422func (s *Store) BatchReceiptsAt(batchHash types.H256) (types.H256, bool) {
423 return s.getCommitment(types.BatchReceiptsPath(batchHash))
424}
425
426// MembershipProofAt returns the committed membership proof value for the
427// client/height/path key.
428func (s *Store) MembershipProofAt(clientId types.ClientId, proofHeight uint64, path []byte) (types.H256, bool) {
429 return s.getMembershipProof(clientId, proofHeight, path)
430}
431
432// HasNonMembershipProof reports whether a non-membership proof was committed
433// for the client/height/path key.
434func (s *Store) HasNonMembershipProof(clientId types.ClientId, proofHeight uint64, path []byte) bool {
435 return s.hasNonMembershipProof(clientId, proofHeight, path)
436}
437
438// --- Key helpers ---
439
440func connectionKey(id types.ConnectionId) string {
441 return seqid.ID(id).Binary()
442}
443
444func channelKey(id types.ChannelId) string {
445 return seqid.ID(id).Binary()
446}
447
448func setChainParam(key string, value []byte) {
449 // NOTE: find a way to assert this write in tests (difficult since params does
450 // not expose getters)
451 params.SetBytes(key, value)
452}
453
454// h256ChainParamKey encodes Union commitment paths for chain params. Unlike
455// classic IBC string paths, Union paths are H256 storage keys and are mirrored
456// into params as lowercase hex strings.
457func h256ChainParamKey(key types.H256) string {
458 return hex.EncodeToString(key[:])
459}
460
461// --- Commitment primitives (path → value) ---
462
463// setCommitment stores a commitment value and mirrors it into chain params so
464// counterparties can prove it.
465func (s *Store) setCommitment(path types.H256, value types.H256) {
466 s.commitments[path] = value
467 setChainParam(h256ChainParamKey(path), value[:])
468}
469
470// setCommitmentMem stores a commitment value in memory only (no chain-param
471// mirror). Used for the acknowledged flip, which is local bookkeeping.
472func (s *Store) setCommitmentMem(path types.H256, value types.H256) {
473 s.commitments[path] = value
474}
475
476// getCommitment reads the commitment value stored at path.
477func (s *Store) getCommitment(path types.H256) (types.H256, bool) {
478 v, found := s.commitments[path]
479 if !found {
480 var zero types.H256
481 return zero, false
482 }
483
484 return v, true
485}
486
487// --- Client state ---
488
489func (c *client) saveClientState(clientStateBytes []byte) {
490 c.clientState = types.CloneBytes(clientStateBytes)
491 setChainParam(h256ChainParamKey(types.ClientStatePath(c.id)), h256Bytes(keccak(clientStateBytes)))
492}
493
494func (c *client) saveConsensusState(height types.Height, consensusStateBytes []byte) {
495 c.consensusByHeight.Set(string(height.Bytes()), types.CloneBytes(consensusStateBytes))
496 setChainParam(h256ChainParamKey(types.ConsensusStatePath(c.id, height)), h256Bytes(keccak(consensusStateBytes)))
497}
498
499func (c *client) getConsensusState(height types.Height) ([]byte, bool) {
500 v := c.consensusByHeight.Get(string(height.Bytes()))
501 if v == nil {
502 return nil, false
503 }
504
505 return types.CloneBytes(v.([]byte)), true
506}
507
508// --- Client store (light client storage writes) ---
509
510func (c *client) saveClientStore(key string, value []byte) {
511 c.clientStore[key] = types.CloneBytes(value)
512}
513
514func (c *client) getClientStore(key string) ([]byte, bool) {
515 v, found := c.clientStore[key]
516 if !found {
517 return nil, false
518 }
519
520 return types.CloneBytes(v), true
521}
522
523// --- Committed proofs (global paths) ---
524
525func (s *Store) saveMembershipProof(clientId types.ClientId, proofHeight uint64, path []byte, value types.H256) {
526 key := types.MembershipProofPath(clientId, proofHeight, path)
527 s.membershipProofs[key] = value
528 setChainParam(h256ChainParamKey(key), value[:])
529}
530
531func (s *Store) getMembershipProof(clientId types.ClientId, proofHeight uint64, path []byte) (types.H256, bool) {
532 v, found := s.membershipProofs[types.MembershipProofPath(clientId, proofHeight, path)]
533 if !found {
534 var zero types.H256
535 return zero, false
536 }
537
538 return v, true
539}
540
541func (s *Store) saveNonMembershipProof(clientId types.ClientId, proofHeight uint64, path []byte, value types.H256) {
542 key := types.NonMembershipProofPath(clientId, proofHeight, path)
543 s.nonMembershipProofs[key] = value
544 setChainParam(h256ChainParamKey(key), value[:])
545}
546
547func (s *Store) hasNonMembershipProof(clientId types.ClientId, proofHeight uint64, path []byte) bool {
548 v, found := s.nonMembershipProofs[types.NonMembershipProofPath(clientId, proofHeight, path)]
549 return found && v == types.NON_MEMBERSHIP_COMMITMENT_VALUE
550}
551
552// --- ID sequences ---
553
554func (s *Store) nextConnectionId() types.ConnectionId {
555 return types.ConnectionId(uint32(s.connectionSeq.Next()))
556}
557
558func (s *Store) nextChannelId() types.ChannelId {
559 return types.ChannelId(uint32(s.channelSeq.Next()))
560}
561
562func (s *Store) nextClientId() types.ClientId {
563 return types.ClientId(uint32(s.clientSeq.Next()))
564}
565
566// --- Client ---
567
568func (s *Store) addClient(clientId types.ClientId, typ types.ClientType, creator address, lc lightclient.Interface) *client {
569 id := uint32(clientId)
570 clientImpl, _ := s.clientRegistryEntry(typ)
571 c := &client{
572 id: clientId,
573 creator: creator,
574 lightClient: lc,
575 consensusByHeight: bptree.NewBPTree32(),
576 clientStore: make(map[string][]byte),
577 }
578 s.clientTypeByID[id] = typ
579 s.clientImplByID[id] = clientImpl
580 s.clientByID[id] = c
581
582 return c
583}
584
585func (s *Store) registerClient(typ types.ClientType, impl lightclient.ClientImpl) {
586 key := typ.String()
587 if _, ok := s.clientRegistry[key]; ok {
588 panic("client type already exists")
589 }
590 s.clientRegistry[key] = impl
591}
592
593func (s *Store) clientRegistryEntry(typ types.ClientType) (lightclient.ClientImpl, bool) {
594 impl, found := s.clientRegistry[string(typ)]
595 return impl, found
596}
597
598func (s *Store) getClient(clientId types.ClientId) *client {
599 c, found := s.clientByID[uint32(clientId)]
600 if !found {
601 return nil
602 }
603
604 return c
605}
606
607func (s *Store) lightClientOf(clientId types.ClientId) (lightclient.Interface, bool) {
608 c := s.getClient(clientId)
609 if c == nil {
610 return nil, false
611 }
612
613 return c.lightClient, true
614}
615
616// --- App routing ---
617
618func portKey(portId types.Bytes) string {
619 return string(portId)
620}
621
622func (s *Store) getAppByPortId(portId types.Bytes) app.IApp {
623 a, ok := s.ports[portKey(portId)]
624 if !ok {
625 panic(makeError(ErrPortNotFound, string(portId)))
626 }
627
628 return a
629}
630
631// --- Connection ---
632
633func (s *Store) saveConnection(connectionId types.ConnectionId, connection types.Connection) {
634 s.connections.Set(connectionKey(connectionId), connection)
635 setChainParam(h256ChainParamKey(types.ConnectionPath(connectionId)), h256Bytes(connectionValue(connection)))
636}
637
638func (s *Store) getConnection(connectionId types.ConnectionId) (types.Connection, bool) {
639 v := s.connections.Get(connectionKey(connectionId))
640 if v == nil {
641 return types.Connection{}, false
642 }
643
644 return v.(types.Connection), true
645}
646
647// --- Channel ---
648
649func (s *Store) createChannel(channelId types.ChannelId, channel types.Channel, portId types.Bytes) {
650 entry := &channelEntry{
651 channel: cloneChannel(channel),
652 portId: portId.Clone(),
653 }
654 s.channels.Set(channelKey(channelId), entry)
655 setChainParam(h256ChainParamKey(types.ChannelPath(channelId)), h256Bytes(channelValue(channel)))
656}
657
658func (s *Store) saveChannel(channelId types.ChannelId, channel types.Channel) {
659 entry, found := s.getChannelEntry(channelId)
660 if !found {
661 panic(makeError(ErrChannelNotFound, channelId.String()))
662 }
663
664 entry.channel = cloneChannel(channel)
665 setChainParam(h256ChainParamKey(types.ChannelPath(channelId)), h256Bytes(channelValue(channel)))
666}
667
668func (s *Store) getChannelEntry(channelId types.ChannelId) (*channelEntry, bool) {
669 v := s.channels.Get(channelKey(channelId))
670 if v == nil {
671 return nil, false
672 }
673
674 return v.(*channelEntry), true
675}
676
677func (s *Store) getChannel(channelId types.ChannelId) types.Channel {
678 entry, found := s.getChannelEntry(channelId)
679 if !found {
680 panic(makeError(ErrChannelNotFound, channelId.String()))
681 }
682
683 return entry.channel
684}
685
686func (s *Store) getChannelOwner(channelId types.ChannelId) types.Bytes {
687 entry, found := s.getChannelEntry(channelId)
688 if !found {
689 panic(makeError(ErrChannelNotFound, channelId.String()))
690 }
691
692 return entry.portId
693}