github.com/binyushen/fabric@v2.1.1+incompatible/core/scc/cscc/configure_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package cscc
     8  
     9  import (
    10  	"errors"
    11  	"io/ioutil"
    12  	"net"
    13  	"os"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/golang/protobuf/proto"
    18  	"github.com/hyperledger/fabric-chaincode-go/shim"
    19  	"github.com/hyperledger/fabric-protos-go/common"
    20  	cb "github.com/hyperledger/fabric-protos-go/common"
    21  	pb "github.com/hyperledger/fabric-protos-go/peer"
    22  	"github.com/hyperledger/fabric/bccsp/sw"
    23  	configtxtest "github.com/hyperledger/fabric/common/configtx/test"
    24  	"github.com/hyperledger/fabric/common/genesis"
    25  	"github.com/hyperledger/fabric/common/metrics/disabled"
    26  	"github.com/hyperledger/fabric/common/policies"
    27  	"github.com/hyperledger/fabric/core/aclmgmt"
    28  	"github.com/hyperledger/fabric/core/chaincode"
    29  	"github.com/hyperledger/fabric/core/config/configtest"
    30  	"github.com/hyperledger/fabric/core/deliverservice"
    31  	"github.com/hyperledger/fabric/core/ledger"
    32  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
    33  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt/ledgermgmttest"
    34  	"github.com/hyperledger/fabric/core/peer"
    35  	"github.com/hyperledger/fabric/core/policy"
    36  	"github.com/hyperledger/fabric/core/scc/cscc/mocks"
    37  	"github.com/hyperledger/fabric/core/transientstore"
    38  	"github.com/hyperledger/fabric/gossip/gossip"
    39  	gossipmetrics "github.com/hyperledger/fabric/gossip/metrics"
    40  	"github.com/hyperledger/fabric/gossip/privdata"
    41  	"github.com/hyperledger/fabric/gossip/service"
    42  	"github.com/hyperledger/fabric/internal/configtxgen/encoder"
    43  	"github.com/hyperledger/fabric/internal/configtxgen/genesisconfig"
    44  	peergossip "github.com/hyperledger/fabric/internal/peer/gossip"
    45  	"github.com/hyperledger/fabric/internal/pkg/comm"
    46  	"github.com/hyperledger/fabric/msp/mgmt"
    47  	msptesttools "github.com/hyperledger/fabric/msp/mgmt/testtools"
    48  	"github.com/hyperledger/fabric/protoutil"
    49  	"github.com/spf13/viper"
    50  	"github.com/stretchr/testify/assert"
    51  	"github.com/stretchr/testify/require"
    52  	"google.golang.org/grpc"
    53  )
    54  
    55  //go:generate counterfeiter -o mocks/acl_provider.go --fake-name ACLProvider . aclProvider
    56  
    57  type aclProvider interface {
    58  	aclmgmt.ACLProvider
    59  }
    60  
    61  //go:generate counterfeiter -o mocks/chaincode_stub.go --fake-name ChaincodeStub . chaincodeStub
    62  
    63  type chaincodeStub interface {
    64  	shim.ChaincodeStubInterface
    65  }
    66  
    67  //go:generate counterfeiter -o mocks/channel_policy_manager_getter.go --fake-name ChannelPolicyManagerGetter . channelPolicyManagerGetter
    68  
    69  type channelPolicyManagerGetter interface {
    70  	policies.ChannelPolicyManagerGetter
    71  }
    72  
    73  //go:generate counterfeiter -o mocks/policy_checker.go --fake-name PolicyChecker . policyChecker
    74  
    75  type policyChecker interface {
    76  	policy.PolicyChecker
    77  }
    78  
    79  //go:generate counterfeiter -o mocks/store_provider.go --fake-name StoreProvider . storeProvider
    80  
    81  type storeProvider interface {
    82  	transientstore.StoreProvider
    83  }
    84  
    85  func TestMain(m *testing.M) {
    86  	msptesttools.LoadMSPSetupForTesting()
    87  	rc := m.Run()
    88  	os.Exit(rc)
    89  
    90  }
    91  
    92  func TestConfigerInit(t *testing.T) {
    93  	mockACLProvider := &mocks.ACLProvider{}
    94  	mockStub := &mocks.ChaincodeStub{}
    95  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    96  	assert.NoError(t, err)
    97  	cscc := &PeerConfiger{
    98  		aclProvider: mockACLProvider,
    99  		bccsp:       cryptoProvider,
   100  	}
   101  	res := cscc.Init(mockStub)
   102  	assert.Equal(t, int32(shim.OK), res.Status)
   103  }
   104  
   105  func TestConfigerInvokeInvalidParameters(t *testing.T) {
   106  	mockACLProvider := &mocks.ACLProvider{}
   107  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   108  	assert.NoError(t, err)
   109  	cscc := &PeerConfiger{
   110  		aclProvider: mockACLProvider,
   111  		bccsp:       cryptoProvider,
   112  	}
   113  	mockStub := &mocks.ChaincodeStub{}
   114  
   115  	mockStub.GetArgsReturns(nil)
   116  	mockStub.GetSignedProposalReturns(validSignedProposal(), nil)
   117  	res := cscc.Invoke(mockStub)
   118  	assert.NotEqual(
   119  		t,
   120  		int32(shim.OK),
   121  		res.Status,
   122  		"cscc invoke expected to fail having zero arguments",
   123  	)
   124  	assert.Equal(t, "Incorrect number of arguments, 0", res.Message)
   125  
   126  	mockACLProvider.CheckACLReturns(errors.New("Failed authorization"))
   127  	args := [][]byte{[]byte("GetChannels")}
   128  	mockStub.GetArgsReturns(args)
   129  	res = cscc.Invoke(mockStub)
   130  	assert.NotEqual(
   131  		t,
   132  		int32(shim.OK),
   133  		res.Status,
   134  		"invoke expected to fail no signed proposal provided",
   135  	)
   136  	assert.Equal(t, "access denied for [GetChannels]: Failed authorization", res.Message)
   137  
   138  	mockACLProvider.CheckACLReturns(nil)
   139  	args = [][]byte{[]byte("fooFunction"), []byte("testChainID")}
   140  	mockStub.GetArgsReturns(args)
   141  	res = cscc.Invoke(mockStub)
   142  	assert.NotEqual(
   143  		t,
   144  		int32(shim.OK),
   145  		res.Status,
   146  		"invoke invoke expected wrong function name provided",
   147  	)
   148  	assert.Equal(t, "Requested function fooFunction not found.", res.Message)
   149  
   150  	mockACLProvider.CheckACLReturns(nil)
   151  	args = [][]byte{[]byte("GetConfigBlock"), []byte("testChainID")}
   152  	mockStub.GetArgsReturns(args)
   153  	mockStub.GetSignedProposalReturns(&pb.SignedProposal{
   154  		ProposalBytes: []byte("garbage"),
   155  	}, nil)
   156  	res = cscc.Invoke(mockStub)
   157  	assert.NotEqual(
   158  		t,
   159  		int32(shim.OK),
   160  		res.Status,
   161  		"invoke expected to fail in ccc2cc context",
   162  	)
   163  	assert.Equal(
   164  		t,
   165  		"Failed to identify the called chaincode: could not unmarshal proposal: proto: can't skip unknown wire type 7",
   166  		res.Message,
   167  	)
   168  
   169  	mockACLProvider.CheckACLReturns(nil)
   170  	args = [][]byte{[]byte("GetConfigBlock"), []byte("testChainID")}
   171  	mockStub.GetArgsReturns(args)
   172  	mockStub.GetSignedProposalReturns(&pb.SignedProposal{
   173  		ProposalBytes: protoutil.MarshalOrPanic(&pb.Proposal{
   174  			Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
   175  				Input: protoutil.MarshalOrPanic(&pb.ChaincodeInvocationSpec{
   176  					ChaincodeSpec: &pb.ChaincodeSpec{
   177  						ChaincodeId: &pb.ChaincodeID{
   178  							Name: "fake-cc2cc",
   179  						},
   180  					},
   181  				}),
   182  			}),
   183  		}),
   184  	}, nil)
   185  	res = cscc.Invoke(mockStub)
   186  	assert.NotEqual(
   187  		t,
   188  		int32(shim.OK),
   189  		res.Status,
   190  		"invoke expected to fail in ccc2cc context",
   191  	)
   192  	assert.Equal(
   193  		t,
   194  		"Rejecting invoke of CSCC from another chaincode, original invocation for 'fake-cc2cc'",
   195  		res.Message,
   196  	)
   197  
   198  	mockACLProvider.CheckACLReturns(errors.New("Failed authorization"))
   199  	mockStub.GetSignedProposalReturns(validSignedProposal(), nil)
   200  	args = [][]byte{[]byte("GetConfigBlock"), []byte("testChainID")}
   201  	mockStub.GetArgsReturns(args)
   202  	res = cscc.Invoke(mockStub)
   203  	assert.NotEqual(
   204  		t,
   205  		int32(shim.OK),
   206  		res.Status,
   207  		"invoke expected to fail no signed proposal provided",
   208  	)
   209  	assert.Equal(
   210  		t,
   211  		"access denied for [GetConfigBlock][testChainID]: Failed authorization",
   212  		res.Message,
   213  	)
   214  }
   215  
   216  func TestConfigerInvokeJoinChainMissingParams(t *testing.T) {
   217  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   218  	assert.NoError(t, err)
   219  	cscc := &PeerConfiger{
   220  		aclProvider: &mocks.ACLProvider{},
   221  		bccsp:       cryptoProvider,
   222  	}
   223  	mockStub := &mocks.ChaincodeStub{}
   224  	mockStub.GetArgsReturns([][]byte{[]byte("JoinChain")})
   225  	res := cscc.Invoke(mockStub)
   226  	assert.NotEqual(
   227  		t,
   228  		int32(shim.OK),
   229  		res.Status,
   230  		"cscc invoke JoinChain should have failed with invalid number of args",
   231  	)
   232  }
   233  
   234  func TestConfigerInvokeJoinChainWrongParams(t *testing.T) {
   235  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   236  	assert.NoError(t, err)
   237  	cscc := &PeerConfiger{
   238  		aclProvider: &mocks.ACLProvider{},
   239  		bccsp:       cryptoProvider,
   240  	}
   241  	mockStub := &mocks.ChaincodeStub{}
   242  	mockStub.GetArgsReturns([][]byte{[]byte("JoinChain"), []byte("action")})
   243  	mockStub.GetSignedProposalReturns(validSignedProposal(), nil)
   244  	res := cscc.Invoke(mockStub)
   245  	assert.NotEqual(
   246  		t,
   247  		int32(shim.OK),
   248  		res.Status,
   249  		"cscc invoke JoinChain should have failed with null genesis block",
   250  	)
   251  }
   252  
   253  func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) {
   254  	viper.Set("chaincode.executetimeout", "3s")
   255  
   256  	testDir, err := ioutil.TempDir("", "cscc_test")
   257  	require.NoError(t, err, "error in creating test dir")
   258  	defer os.RemoveAll(testDir)
   259  
   260  	ledgerInitializer := ledgermgmttest.NewInitializer(testDir)
   261  	ledgerInitializer.CustomTxProcessors = map[common.HeaderType]ledger.CustomTxProcessor{
   262  		common.HeaderType_CONFIG: &peer.ConfigTxProcessor{},
   263  	}
   264  	ledgerMgr := ledgermgmt.NewLedgerMgr(ledgerInitializer)
   265  	defer ledgerMgr.Close()
   266  
   267  	peerEndpoint := "127.0.0.1:13611"
   268  
   269  	config := chaincode.GlobalConfig()
   270  	config.StartupTimeout = 30 * time.Second
   271  
   272  	grpcServer := grpc.NewServer()
   273  	socket, err := net.Listen("tcp", peerEndpoint)
   274  	require.NoError(t, err)
   275  
   276  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   277  	assert.NoError(t, err)
   278  
   279  	signer := mgmt.GetLocalSigningIdentityOrPanic(cryptoProvider)
   280  
   281  	messageCryptoService := peergossip.NewMCS(&mocks.ChannelPolicyManagerGetter{}, signer, mgmt.NewDeserializersManager(cryptoProvider), cryptoProvider)
   282  	secAdv := peergossip.NewSecurityAdvisor(mgmt.NewDeserializersManager(cryptoProvider))
   283  	var defaultSecureDialOpts = func() []grpc.DialOption {
   284  		var dialOpts []grpc.DialOption
   285  		dialOpts = append(dialOpts, grpc.WithInsecure())
   286  		return dialOpts
   287  	}
   288  	defaultDeliverClientDialOpts := []grpc.DialOption{grpc.WithBlock()}
   289  	defaultDeliverClientDialOpts = append(
   290  		defaultDeliverClientDialOpts,
   291  		grpc.WithDefaultCallOptions(
   292  			grpc.MaxCallRecvMsgSize(comm.MaxRecvMsgSize),
   293  			grpc.MaxCallSendMsgSize(comm.MaxSendMsgSize)))
   294  	defaultDeliverClientDialOpts = append(
   295  		defaultDeliverClientDialOpts,
   296  		comm.ClientKeepaliveOptions(comm.DefaultKeepaliveOptions)...,
   297  	)
   298  	gossipConfig, err := gossip.GlobalConfig(peerEndpoint, nil)
   299  	assert.NoError(t, err)
   300  
   301  	gossipService, err := service.New(
   302  		signer,
   303  		gossipmetrics.NewGossipMetrics(&disabled.Provider{}),
   304  		peerEndpoint,
   305  		grpcServer,
   306  		messageCryptoService,
   307  		secAdv,
   308  		defaultSecureDialOpts,
   309  		nil,
   310  		nil,
   311  		gossipConfig,
   312  		&service.ServiceConfig{},
   313  		&privdata.PrivdataConfig{},
   314  		&deliverservice.DeliverServiceConfig{
   315  			ReConnectBackoffThreshold:   deliverservice.DefaultReConnectBackoffThreshold,
   316  			ReconnectTotalTimeThreshold: deliverservice.DefaultReConnectTotalTimeThreshold,
   317  		},
   318  	)
   319  	assert.NoError(t, err)
   320  
   321  	go grpcServer.Serve(socket)
   322  	defer grpcServer.Stop()
   323  
   324  	assert.NoError(t, err)
   325  
   326  	// setup cscc instance
   327  	mockACLProvider := &mocks.ACLProvider{}
   328  	cscc := &PeerConfiger{
   329  		policyChecker: &mocks.PolicyChecker{},
   330  		aclProvider:   mockACLProvider,
   331  		peer: &peer.Peer{
   332  			StoreProvider:  &mocks.StoreProvider{},
   333  			GossipService:  gossipService,
   334  			LedgerMgr:      ledgerMgr,
   335  			CryptoProvider: cryptoProvider,
   336  		},
   337  		bccsp: cryptoProvider,
   338  	}
   339  	mockStub := &mocks.ChaincodeStub{}
   340  
   341  	// Successful path for JoinChain
   342  	blockBytes := mockConfigBlock()
   343  	if blockBytes == nil {
   344  		t.Fatalf("cscc invoke JoinChain failed because invalid block")
   345  	}
   346  	args := [][]byte{[]byte("JoinChain"), blockBytes}
   347  	sProp := validSignedProposal()
   348  	sProp.Signature = sProp.ProposalBytes
   349  
   350  	// Try fail path with nil block
   351  	mockStub.GetArgsReturns([][]byte{[]byte("JoinChain"), nil})
   352  	mockStub.GetSignedProposalReturns(sProp, nil)
   353  	res := cscc.Invoke(mockStub)
   354  	//res := stub.MockInvokeWithSignedProposal("2", [][]byte{[]byte("JoinChain"), nil}, sProp)
   355  	assert.Equal(t, int32(shim.ERROR), res.Status)
   356  
   357  	// Try fail path with block and nil payload header
   358  	payload, _ := proto.Marshal(&cb.Payload{})
   359  	env, _ := proto.Marshal(&cb.Envelope{
   360  		Payload: payload,
   361  	})
   362  	badBlock := &cb.Block{
   363  		Data: &cb.BlockData{
   364  			Data: [][]byte{env},
   365  		},
   366  	}
   367  	badBlockBytes := protoutil.MarshalOrPanic(badBlock)
   368  	mockStub.GetArgsReturns([][]byte{[]byte("JoinChain"), badBlockBytes})
   369  	res = cscc.Invoke(mockStub)
   370  	//res = stub.MockInvokeWithSignedProposal("2", [][]byte{[]byte("JoinChain"), badBlockBytes}, sProp)
   371  	assert.Equal(t, int32(shim.ERROR), res.Status)
   372  
   373  	// Now, continue with valid execution path
   374  	mockStub.GetArgsReturns(args)
   375  	mockStub.GetSignedProposalReturns(sProp, nil)
   376  	res = cscc.Invoke(mockStub)
   377  	assert.Equal(t, int32(shim.OK), res.Status, "invoke JoinChain failed with: %v", res.Message)
   378  
   379  	// This call must fail
   380  	sProp.Signature = nil
   381  	mockACLProvider.CheckACLReturns(errors.New("Failed authorization"))
   382  	mockStub.GetArgsReturns(args)
   383  	mockStub.GetSignedProposalReturns(sProp, nil)
   384  
   385  	res = cscc.Invoke(mockStub)
   386  	assert.Equal(t, int32(shim.ERROR), res.Status)
   387  	assert.Contains(t, res.Message, "access denied for [JoinChain][mytestchainid]")
   388  	sProp.Signature = sProp.ProposalBytes
   389  
   390  	// Query the configuration block
   391  	//chainID := []byte{143, 222, 22, 192, 73, 145, 76, 110, 167, 154, 118, 66, 132, 204, 113, 168}
   392  	chainID, err := protoutil.GetChainIDFromBlockBytes(blockBytes)
   393  	if err != nil {
   394  		t.Fatalf("cscc invoke JoinChain failed with: %v", err)
   395  	}
   396  
   397  	// Test an ACL failure on GetConfigBlock
   398  	mockACLProvider.CheckACLReturns(errors.New("Failed authorization"))
   399  	args = [][]byte{[]byte("GetConfigBlock"), []byte(chainID)}
   400  	mockStub.GetArgsReturns(args)
   401  	mockStub.GetSignedProposalReturns(sProp, nil)
   402  	res = cscc.Invoke(mockStub)
   403  	assert.Equal(t, int32(shim.ERROR), res.Status, "invoke GetConfigBlock should have failed: %v", res.Message)
   404  	assert.Contains(t, res.Message, "Failed authorization")
   405  
   406  	// Test with ACL okay
   407  	mockACLProvider.CheckACLReturns(nil)
   408  	res = cscc.Invoke(mockStub)
   409  	assert.Equal(t, int32(shim.OK), res.Status, "invoke GetConfigBlock failed with: %v", res.Message)
   410  
   411  	// get channels for the peer
   412  	mockACLProvider.CheckACLReturns(nil)
   413  	args = [][]byte{[]byte(GetChannels)}
   414  	mockStub.GetArgsReturns(args)
   415  	res = cscc.Invoke(mockStub)
   416  	if res.Status != shim.OK {
   417  		t.FailNow()
   418  	}
   419  
   420  	cqr := &pb.ChannelQueryResponse{}
   421  	err = proto.Unmarshal(res.Payload, cqr)
   422  	if err != nil {
   423  		t.FailNow()
   424  	}
   425  
   426  	// peer joined one channel so query should return an array with one channel
   427  	if len(cqr.GetChannels()) != 1 {
   428  		t.FailNow()
   429  	}
   430  }
   431  
   432  func TestPeerConfiger_SubmittingOrdererGenesis(t *testing.T) {
   433  	conf := genesisconfig.Load(genesisconfig.SampleSingleMSPSoloProfile, configtest.GetDevConfigDir())
   434  	conf.Application = nil
   435  	cg, err := encoder.NewChannelGroup(conf)
   436  	assert.NoError(t, err)
   437  	block := genesis.NewFactoryImpl(cg).Block("mytestchainid")
   438  	blockBytes := protoutil.MarshalOrPanic(block)
   439  
   440  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   441  	assert.NoError(t, err)
   442  	mockACLProvider := &mocks.ACLProvider{}
   443  	cscc := &PeerConfiger{
   444  		aclProvider: mockACLProvider,
   445  		bccsp:       cryptoProvider,
   446  	}
   447  	mockStub := &mocks.ChaincodeStub{}
   448  	// Failed path: wrong parameter type
   449  	args := [][]byte{[]byte("JoinChain"), []byte(blockBytes)}
   450  	mockStub.GetArgsReturns(args)
   451  	mockStub.GetSignedProposalReturns(validSignedProposal(), nil)
   452  	res := cscc.Invoke(mockStub)
   453  
   454  	assert.NotEqual(
   455  		t,
   456  		int32(shim.OK),
   457  		res.Status,
   458  		"invoke JoinChain should have failed with wrong genesis block",
   459  	)
   460  	assert.Contains(t, res.Message, "missing Application configuration group")
   461  }
   462  
   463  func mockConfigBlock() []byte {
   464  	var blockBytes []byte = nil
   465  	block, err := configtxtest.MakeGenesisBlock("mytestchainid")
   466  	if err == nil {
   467  		blockBytes = protoutil.MarshalOrPanic(block)
   468  	}
   469  	return blockBytes
   470  }
   471  
   472  func validSignedProposal() *pb.SignedProposal {
   473  	return &pb.SignedProposal{
   474  		ProposalBytes: protoutil.MarshalOrPanic(&pb.Proposal{
   475  			Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
   476  				Input: protoutil.MarshalOrPanic(&pb.ChaincodeInvocationSpec{
   477  					ChaincodeSpec: &pb.ChaincodeSpec{
   478  						ChaincodeId: &pb.ChaincodeID{
   479  							Name: "cscc",
   480  						},
   481  					},
   482  				}),
   483  			}),
   484  		}),
   485  	}
   486  }