github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/bccsp/sw"
    23  	configtxtest "github.com/osdi23p228/fabric/common/configtx/test"
    24  	"github.com/osdi23p228/fabric/common/genesis"
    25  	"github.com/osdi23p228/fabric/common/metrics/disabled"
    26  	"github.com/osdi23p228/fabric/common/policies"
    27  	"github.com/osdi23p228/fabric/core/aclmgmt"
    28  	"github.com/osdi23p228/fabric/core/chaincode"
    29  	"github.com/osdi23p228/fabric/core/config/configtest"
    30  	"github.com/osdi23p228/fabric/core/deliverservice"
    31  	"github.com/osdi23p228/fabric/core/ledger"
    32  	"github.com/osdi23p228/fabric/core/ledger/ledgermgmt"
    33  	"github.com/osdi23p228/fabric/core/ledger/ledgermgmt/ledgermgmttest"
    34  	"github.com/osdi23p228/fabric/core/peer"
    35  	"github.com/osdi23p228/fabric/core/policy"
    36  	"github.com/osdi23p228/fabric/core/scc/cscc/mocks"
    37  	"github.com/osdi23p228/fabric/core/transientstore"
    38  	"github.com/osdi23p228/fabric/gossip/gossip"
    39  	gossipmetrics "github.com/osdi23p228/fabric/gossip/metrics"
    40  	"github.com/osdi23p228/fabric/gossip/privdata"
    41  	"github.com/osdi23p228/fabric/gossip/service"
    42  	"github.com/osdi23p228/fabric/internal/configtxgen/encoder"
    43  	"github.com/osdi23p228/fabric/internal/configtxgen/genesisconfig"
    44  	peergossip "github.com/osdi23p228/fabric/internal/peer/gossip"
    45  	"github.com/osdi23p228/fabric/internal/pkg/comm"
    46  	"github.com/osdi23p228/fabric/msp/mgmt"
    47  	msptesttools "github.com/osdi23p228/fabric/msp/mgmt/testtools"
    48  	"github.com/osdi23p228/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("testChannelID")}
   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("testChannelID")}
   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("testChannelID")}
   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("testChannelID")}
   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][testChannelID]: 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  		return []grpc.DialOption{grpc.WithInsecure()}
   285  	}
   286  	var defaultDeliverClientDialOpts []grpc.DialOption
   287  	defaultDeliverClientDialOpts = append(
   288  		defaultDeliverClientDialOpts,
   289  		grpc.WithBlock(),
   290  		grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(comm.MaxRecvMsgSize), grpc.MaxCallSendMsgSize(comm.MaxSendMsgSize)),
   291  	)
   292  	defaultDeliverClientDialOpts = append(
   293  		defaultDeliverClientDialOpts,
   294  		comm.ClientKeepaliveOptions(comm.DefaultKeepaliveOptions)...,
   295  	)
   296  	gossipConfig, err := gossip.GlobalConfig(peerEndpoint, nil)
   297  	assert.NoError(t, err)
   298  
   299  	gossipService, err := service.New(
   300  		signer,
   301  		gossipmetrics.NewGossipMetrics(&disabled.Provider{}),
   302  		peerEndpoint,
   303  		grpcServer,
   304  		messageCryptoService,
   305  		secAdv,
   306  		defaultSecureDialOpts,
   307  		nil,
   308  		nil,
   309  		gossipConfig,
   310  		&service.ServiceConfig{},
   311  		&privdata.PrivdataConfig{},
   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][mytestchannelid]")
   386  	sProp.Signature = sProp.ProposalBytes
   387  
   388  	// Query the configuration block
   389  	//channelID := []byte{143, 222, 22, 192, 73, 145, 76, 110, 167, 154, 118, 66, 132, 204, 113, 168}
   390  	channelID, err := protoutil.GetChannelIDFromBlockBytes(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(channelID)}
   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("mytestchannelid")
   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("mytestchannelid")
   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  }