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