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