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  }