-
Notifications
You must be signed in to change notification settings - Fork 122
/
relay_util.go
182 lines (156 loc) · 6.47 KB
/
relay_util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package simibc
import (
clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
host "github.com/cosmos/ibc-go/v8/modules/core/24-host"
ibctmtypes "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint"
ibctesting "github.com/cosmos/ibc-go/v8/testing"
simapp "github.com/cosmos/ibc-go/v8/testing/simapp"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
tmtypes "github.com/cometbft/cometbft/types"
)
// UpdateReceiverClient DELIVERs a header to the receiving endpoint
// and update the respective client of the receiving chain.
//
// The header is a header of the sender chain. The receiver chain
// must have a client of the sender chain that it can update.
//
// NOTE: this function MAY be used independently of the rest of simibc.
func UpdateReceiverClient(sender, receiver *ibctesting.Endpoint, header *ibctmtypes.Header, expectExpiration bool) (err error) {
err = augmentHeader(sender.Chain, receiver.Chain, receiver.ClientID, header)
if err != nil {
return err
}
msg, err := clienttypes.NewMsgUpdateClient(
receiver.ClientID, header,
receiver.Chain.SenderAccount.GetAddress().String(),
)
if err != nil {
return err
}
_, err = simapp.SignAndDeliver(
receiver.Chain.TB,
receiver.Chain.TxConfig,
receiver.Chain.App.GetBaseApp(),
[]sdk.Msg{msg},
receiver.Chain.ChainID,
[]uint64{receiver.Chain.SenderAccount.GetAccountNumber()},
[]uint64{receiver.Chain.SenderAccount.GetSequence()},
!expectExpiration,
receiver.Chain.GetContext().BlockHeader().Time,
receiver.Chain.GetContext().BlockHeader().NextValidatorsHash,
receiver.Chain.SenderPrivKey,
)
setSequenceErr := receiver.Chain.SenderAccount.SetSequence(receiver.Chain.SenderAccount.GetSequence() + 1)
if err != nil {
return err
}
if setSequenceErr != nil {
return setSequenceErr
}
return nil
}
// TryRecvPacket will try once to DELIVER a packet from sender to receiver. If successful,
// it will return the acknowledgement bytes.
//
// The packet must be sent from the sender chain to the receiver chain, and the
// receiver chain must have a client for the sender chain which has been updated
// to a recent height of the sender chain so that it can verify the packet.
func TryRecvPacket(sender, receiver *ibctesting.Endpoint, packet channeltypes.Packet, expectError bool) (ack []byte, err error) {
packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
proof, proofHeight := sender.Chain.QueryProof(packetKey)
RPmsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, receiver.Chain.SenderAccount.GetAddress().String())
resWithAck, err := simapp.SignAndDeliver(
receiver.Chain.TB,
receiver.Chain.TxConfig,
receiver.Chain.App.GetBaseApp(),
[]sdk.Msg{RPmsg},
receiver.Chain.ChainID,
[]uint64{receiver.Chain.SenderAccount.GetAccountNumber()},
[]uint64{receiver.Chain.SenderAccount.GetSequence()},
!expectError,
receiver.Chain.GetContext().BlockHeader().Time,
receiver.Chain.GetContext().BlockHeader().NextValidatorsHash,
receiver.Chain.SenderPrivKey,
)
// need to set the sequence even if there was an error in delivery
setSequenceErr := receiver.Chain.SenderAccount.SetSequence(receiver.Chain.SenderAccount.GetSequence() + 1)
if err != nil {
return nil, err
}
if setSequenceErr != nil {
return nil, setSequenceErr
}
ack, err = ibctesting.ParseAckFromEvents(resWithAck.GetEvents())
if err != nil {
return nil, err
}
return ack, nil
}
// TryRecvAck will try once to DELIVER an ack from sender to receiver.
//
// The ack must have been sent from the sender to the receiver, in response
// to packet which was previously delivered from the receiver to the sender.
// The receiver chain must have a client for the sender chain which has been
// updated to a recent height of the sender chain so that it can verify the packet.
func TryRecvAck(sender, receiver *ibctesting.Endpoint, packet channeltypes.Packet, ack []byte) (err error) {
p := packet
packetKey := host.PacketAcknowledgementKey(p.GetDestPort(), p.GetDestChannel(), p.GetSequence())
proof, proofHeight := sender.Chain.QueryProof(packetKey)
ackMsg := channeltypes.NewMsgAcknowledgement(p, ack, proof, proofHeight, receiver.Chain.SenderAccount.GetAddress().String())
_, err = simapp.SignAndDeliver(
receiver.Chain.TB,
receiver.Chain.TxConfig,
receiver.Chain.App.GetBaseApp(),
[]sdk.Msg{ackMsg},
receiver.Chain.ChainID,
[]uint64{receiver.Chain.SenderAccount.GetAccountNumber()},
[]uint64{receiver.Chain.SenderAccount.GetSequence()},
true,
receiver.Chain.GetContext().BlockHeader().Time,
receiver.Chain.GetContext().BlockHeader().NextValidatorsHash,
receiver.Chain.SenderPrivKey,
)
setSequenceErr := receiver.Chain.SenderAccount.SetSequence(receiver.Chain.SenderAccount.GetSequence() + 1)
if err != nil {
return err
}
if setSequenceErr != nil {
return setSequenceErr
}
return nil
}
// augmentHeader is a helper that augments the header with the height and validators that are most recently trusted
// by the receiver chain. If there is an error, the header will not be modified.
func augmentHeader(sender, receiver *ibctesting.TestChain, clientID string, header *ibctmtypes.Header) error {
trustedHeight := receiver.GetClientState(clientID).GetLatestHeight().(clienttypes.Height)
var (
tmTrustedVals *tmtypes.ValidatorSet
ok bool
)
// Once we get TrustedHeight from client, we must query the validators from the counterparty chain
// If the LatestHeight == LastHeader.Height, then TrustedValidators are current validators
// If LatestHeight < LastHeader.Height, we can query the historical validator set from HistoricalInfo
if trustedHeight == sender.LastHeader.GetHeight() {
tmTrustedVals = sender.Vals
} else {
// NOTE: We need to get validators from counterparty at height: trustedHeight+1
// since the last trusted validators for a header at height h
// is the NextValidators at h+1 committed to in header h by
// NextValidatorsHash
tmTrustedVals, ok = sender.GetValsAtHeight(int64(trustedHeight.RevisionHeight + 1))
if !ok {
return errorsmod.Wrapf(ibctmtypes.ErrInvalidHeaderHeight, "could not retrieve trusted validators at trustedHeight: %d", trustedHeight)
}
}
trustedVals, err := tmTrustedVals.ToProto()
if err != nil {
return err
}
// inject trusted fields into last header
// for now assume revision number is 0
header.TrustedHeight = trustedHeight
header.TrustedValidators = trustedVals
return nil
}