github.com/okex/exchain@v1.8.0/libs/ibc-go/testing/solomachine.go (about) 1 package ibctesting 2 3 import ( 4 "github.com/okex/exchain/libs/cosmos-sdk/codec" 5 codectypes "github.com/okex/exchain/libs/cosmos-sdk/codec/types" 6 "github.com/okex/exchain/libs/cosmos-sdk/types/tx/signing" 7 ibc_tx "github.com/okex/exchain/libs/cosmos-sdk/x/auth/ibc-tx" 8 clienttypes "github.com/okex/exchain/libs/ibc-go/modules/core/02-client/types" 9 commitmenttypes "github.com/okex/exchain/libs/ibc-go/modules/core/23-commitment/types" 10 host "github.com/okex/exchain/libs/ibc-go/modules/core/24-host" 11 "github.com/okex/exchain/libs/ibc-go/modules/core/exported" 12 solomachinetypes "github.com/okex/exchain/libs/ibc-go/modules/light-clients/06-solomachine/types" 13 "github.com/okex/exchain/libs/tendermint/crypto" 14 "github.com/okex/exchain/libs/tendermint/crypto/secp256k1" 15 "github.com/stretchr/testify/require" 16 "testing" 17 ) 18 19 // import ( 20 // "testing" 21 22 // "github.com/stretchr/testify/require" 23 24 // "github.com/cosmos/cosmos-sdk/codec" 25 // codectypes "github.com/cosmos/cosmos-sdk/codec/types" 26 // kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" 27 // "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" 28 // cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 29 // "github.com/cosmos/cosmos-sdk/crypto/types/multisig" 30 // "github.com/cosmos/cosmos-sdk/types/tx/signing" 31 // clienttypes "github.com/okex/exchain/libs/ibc-go/modules/core/02-client/types" 32 // commitmenttypes "github.com/okex/exchain/libs/ibc-go/modules/core/23-commitment/types" 33 // host "github.com/okex/exchain/libs/ibc-go/modules/core/24-host" 34 // "github.com/okex/exchain/libs/ibc-go/modules/core/exported" 35 // solomachinetypes "github.com/okex/exchain/libs/ibc-go/modules/light-clients/06-solomachine/types" 36 // ) 37 38 // Solomachine is a testing helper used to simulate a counterparty 39 // solo machine client. 40 type Solomachine struct { 41 t *testing.T 42 43 cdc *codec.CodecProxy 44 ClientID string 45 PrivateKeys []crypto.PrivKey // keys used for signing 46 PublicKeys []crypto.PubKey // keys used for generating solo machine pub key 47 PublicKey crypto.PubKey // key used for verification 48 Sequence uint64 49 Time uint64 50 Diversifier string 51 } 52 53 // // NewSolomachine returns a new solomachine instance with an `nKeys` amount of 54 // // generated private/public key pairs and a sequence starting at 1. If nKeys 55 // // is greater than 1 then a multisig public key is used. 56 func NewSolomachine(t *testing.T, cdc *codec.CodecProxy, clientID, diversifier string, nKeys uint64) *Solomachine { 57 privKeys, pubKeys, pk := GenerateKeys(t, nKeys) 58 59 return &Solomachine{ 60 t: t, 61 cdc: cdc, 62 ClientID: clientID, 63 PrivateKeys: privKeys, 64 PublicKeys: pubKeys, 65 PublicKey: pk, 66 Sequence: 1, 67 Time: 10, 68 Diversifier: diversifier, 69 } 70 } 71 72 // GenerateKeys generates a new set of secp256k1 private keys and public keys. 73 // If the number of keys is greater than one then the public key returned represents 74 // a multisig public key. The private keys are used for signing, the public 75 // keys are used for generating the public key and the public key is used for 76 // solo machine verification. The usage of secp256k1 is entirely arbitrary. 77 // The key type can be swapped for any key type supported by the PublicKey 78 // interface, if needed. The same is true for the amino based Multisignature 79 // public key. 80 func GenerateKeys(t *testing.T, n uint64) ([]crypto.PrivKey, []crypto.PubKey, crypto.PubKey) { 81 require.NotEqual(t, uint64(0), n, "generation of zero keys is not allowed") 82 83 // privKeys := make([]cryptotypes.PrivKey, n) 84 privKeys := make([]crypto.PrivKey, n) 85 pubKeys := make([]crypto.PubKey, n) 86 for i := uint64(0); i < n; i++ { 87 privKeys[i] = secp256k1.GenPrivKey() 88 pubKeys[i] = privKeys[i].PubKey() 89 } 90 91 // var pk cryptotypes.PubKey 92 var pk crypto.PubKey 93 if len(privKeys) > 1 { 94 // generate multi sig pk 95 //pk = kmultisig.NewLegacyAminoPubKey(int(n), pubKeys) 96 //todo Ywmet 97 panic("donot surport multi sig") 98 } else { 99 pk = privKeys[0].PubKey() 100 } 101 102 return privKeys, pubKeys, pk 103 } 104 105 // ClientState returns a new solo machine ClientState instance. Default usage does not allow update 106 // after governance proposal 107 func (solo *Solomachine) ClientState() *solomachinetypes.ClientState { 108 return solomachinetypes.NewClientState(solo.Sequence, solo.ConsensusState(), false) 109 } 110 111 // ConsensusState returns a new solo machine ConsensusState instance 112 func (solo *Solomachine) ConsensusState() *solomachinetypes.ConsensusState { 113 pbPk := ibc_tx.LagacyKey2PbKey(solo.PublicKey) 114 publicKey, err := codectypes.NewAnyWithValue(pbPk) 115 require.NoError(solo.t, err) 116 117 return &solomachinetypes.ConsensusState{ 118 PublicKey: publicKey, 119 Diversifier: solo.Diversifier, 120 Timestamp: solo.Time, 121 } 122 } 123 124 // GetHeight returns an exported.Height with Sequence as RevisionHeight 125 func (solo *Solomachine) GetHeight() exported.Height { 126 return clienttypes.NewHeight(0, solo.Sequence) 127 } 128 129 // CreateHeader generates a new private/public key pair and creates the 130 // necessary signature to construct a valid solo machine header. 131 func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { 132 // generate new private keys and signature for header 133 newPrivKeys, newPubKeys, newPubKey := GenerateKeys(solo.t, uint64(len(solo.PrivateKeys))) 134 newPbPubKey := ibc_tx.LagacyKey2PbKey(newPubKey) 135 publicKey, err := codectypes.NewAnyWithValue(newPbPubKey) 136 require.NoError(solo.t, err) 137 138 data := &solomachinetypes.HeaderData{ 139 NewPubKey: publicKey, 140 NewDiversifier: solo.Diversifier, 141 } 142 143 dataBz, err := solo.cdc.GetProtocMarshal().MarshalBinaryBare(data) 144 require.NoError(solo.t, err) 145 146 signBytes := &solomachinetypes.SignBytes{ 147 Sequence: solo.Sequence, 148 Timestamp: solo.Time, 149 Diversifier: solo.Diversifier, 150 DataType: solomachinetypes.HEADER, 151 Data: dataBz, 152 } 153 154 bz, err := solo.cdc.GetProtocMarshal().MarshalBinaryBare(signBytes) 155 require.NoError(solo.t, err) 156 157 sig := solo.GenerateSignature(bz) 158 159 header := &solomachinetypes.Header{ 160 Sequence: solo.Sequence, 161 Timestamp: solo.Time, 162 Signature: sig, 163 NewPublicKey: publicKey, 164 NewDiversifier: solo.Diversifier, 165 } 166 167 // assumes successful header update 168 solo.Sequence++ 169 solo.PrivateKeys = newPrivKeys 170 solo.PublicKeys = newPubKeys 171 solo.PublicKey = newPubKey 172 173 return header 174 } 175 176 // CreateMisbehaviour constructs testing misbehaviour for the solo machine client 177 // by signing over two different data bytes at the same sequence. 178 func (solo *Solomachine) CreateMisbehaviour() *solomachinetypes.Misbehaviour { 179 path := solo.GetClientStatePath("counterparty") 180 dataOne, err := solomachinetypes.ClientStateDataBytes(solo.cdc, path, solo.ClientState()) 181 require.NoError(solo.t, err) 182 183 path = solo.GetConsensusStatePath("counterparty", clienttypes.NewHeight(0, 1)) 184 dataTwo, err := solomachinetypes.ConsensusStateDataBytes(solo.cdc, path, solo.ConsensusState()) 185 require.NoError(solo.t, err) 186 187 signBytes := &solomachinetypes.SignBytes{ 188 Sequence: solo.Sequence, 189 Timestamp: solo.Time, 190 Diversifier: solo.Diversifier, 191 DataType: solomachinetypes.CLIENT, 192 Data: dataOne, 193 } 194 195 bz, err := solo.cdc.GetProtocMarshal().MarshalBinaryBare(signBytes) 196 require.NoError(solo.t, err) 197 198 sig := solo.GenerateSignature(bz) 199 signatureOne := solomachinetypes.SignatureAndData{ 200 Signature: sig, 201 DataType: solomachinetypes.CLIENT, 202 Data: dataOne, 203 Timestamp: solo.Time, 204 } 205 206 // misbehaviour signaturess can have different timestamps 207 solo.Time++ 208 209 signBytes = &solomachinetypes.SignBytes{ 210 Sequence: solo.Sequence, 211 Timestamp: solo.Time, 212 Diversifier: solo.Diversifier, 213 DataType: solomachinetypes.CONSENSUS, 214 Data: dataTwo, 215 } 216 217 bz, err = solo.cdc.GetCdc().MarshalBinaryBare(signBytes) 218 require.NoError(solo.t, err) 219 220 sig = solo.GenerateSignature(bz) 221 signatureTwo := solomachinetypes.SignatureAndData{ 222 Signature: sig, 223 DataType: solomachinetypes.CONSENSUS, 224 Data: dataTwo, 225 Timestamp: solo.Time, 226 } 227 228 return &solomachinetypes.Misbehaviour{ 229 ClientId: solo.ClientID, 230 Sequence: solo.Sequence, 231 SignatureOne: &signatureOne, 232 SignatureTwo: &signatureTwo, 233 } 234 } 235 236 // GenerateSignature uses the stored private keys to generate a signature 237 // over the sign bytes with each key. If the amount of keys is greater than 238 // 1 then a multisig data type is returned. 239 func (solo *Solomachine) GenerateSignature(signBytes []byte) []byte { 240 sigs := make([]signing.SignatureData, len(solo.PrivateKeys)) 241 for i, key := range solo.PrivateKeys { 242 sig, err := key.Sign(signBytes) 243 require.NoError(solo.t, err) 244 245 sigs[i] = &signing.SingleSignatureData{ 246 Signature: sig, 247 } 248 } 249 250 var sigData signing.SignatureData 251 if len(sigs) == 1 { 252 // single public key 253 sigData = sigs[0] 254 } else { 255 // generate multi signature data 256 //todo Ywmet 257 panic("donot surport multi sigs") 258 //multiSigData := multisig.NewMultisig(len(sigs)) 259 //for i, sig := range sigs { 260 // multisig.AddSignature(multiSigData, sig, i) 261 //} 262 // 263 //sigData = multiSigData 264 } 265 266 protoSigData := signing.SignatureDataToProto(sigData) 267 bz, err := solo.cdc.GetProtocMarshal().MarshalInterface(protoSigData) 268 require.NoError(solo.t, err) 269 270 return bz 271 } 272 273 // GetClientStatePath returns the commitment path for the client state. 274 func (solo *Solomachine) GetClientStatePath(counterpartyClientIdentifier string) commitmenttypes.MerklePath { 275 path, err := commitmenttypes.ApplyPrefix(prefix, commitmenttypes.NewMerklePath(host.FullClientStatePath(counterpartyClientIdentifier))) 276 require.NoError(solo.t, err) 277 278 return path 279 } 280 281 // GetConsensusStatePath returns the commitment path for the consensus state. 282 func (solo *Solomachine) GetConsensusStatePath(counterpartyClientIdentifier string, consensusHeight exported.Height) commitmenttypes.MerklePath { 283 path, err := commitmenttypes.ApplyPrefix(prefix, commitmenttypes.NewMerklePath(host.FullConsensusStatePath(counterpartyClientIdentifier, consensusHeight))) 284 require.NoError(solo.t, err) 285 286 return path 287 } 288 289 // GetConnectionStatePath returns the commitment path for the connection state. 290 func (solo *Solomachine) GetConnectionStatePath(connID string) commitmenttypes.MerklePath { 291 connectionPath := commitmenttypes.NewMerklePath(host.ConnectionPath(connID)) 292 path, err := commitmenttypes.ApplyPrefix(prefix, connectionPath) 293 require.NoError(solo.t, err) 294 295 return path 296 } 297 298 // GetChannelStatePath returns the commitment path for that channel state. 299 func (solo *Solomachine) GetChannelStatePath(portID, channelID string) commitmenttypes.MerklePath { 300 channelPath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) 301 path, err := commitmenttypes.ApplyPrefix(prefix, channelPath) 302 require.NoError(solo.t, err) 303 304 return path 305 } 306 307 // GetPacketCommitmentPath returns the commitment path for a packet commitment. 308 func (solo *Solomachine) GetPacketCommitmentPath(portID, channelID string) commitmenttypes.MerklePath { 309 commitmentPath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, solo.Sequence)) 310 path, err := commitmenttypes.ApplyPrefix(prefix, commitmentPath) 311 require.NoError(solo.t, err) 312 313 return path 314 } 315 316 // GetPacketAcknowledgementPath returns the commitment path for a packet acknowledgement. 317 func (solo *Solomachine) GetPacketAcknowledgementPath(portID, channelID string) commitmenttypes.MerklePath { 318 ackPath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, solo.Sequence)) 319 path, err := commitmenttypes.ApplyPrefix(prefix, ackPath) 320 require.NoError(solo.t, err) 321 322 return path 323 } 324 325 // GetPacketReceiptPath returns the commitment path for a packet receipt 326 // and an absent receipts. 327 func (solo *Solomachine) GetPacketReceiptPath(portID, channelID string) commitmenttypes.MerklePath { 328 receiptPath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, solo.Sequence)) 329 path, err := commitmenttypes.ApplyPrefix(prefix, receiptPath) 330 require.NoError(solo.t, err) 331 332 return path 333 } 334 335 // GetNextSequenceRecvPath returns the commitment path for the next sequence recv counter. 336 func (solo *Solomachine) GetNextSequenceRecvPath(portID, channelID string) commitmenttypes.MerklePath { 337 nextSequenceRecvPath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(portID, channelID)) 338 path, err := commitmenttypes.ApplyPrefix(prefix, nextSequenceRecvPath) 339 require.NoError(solo.t, err) 340 341 return path 342 }