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  }