github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/chaincode/executetransaction_pvtdata_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package chaincode
     8  
     9  import (
    10  	"encoding/json"
    11  	"fmt"
    12  	"testing"
    13  	"time"
    14  
    15  	pb "github.com/hyperledger/fabric-protos-go/peer"
    16  	"github.com/hyperledger/fabric/common/util"
    17  	"github.com/hyperledger/fabric/core/peer"
    18  	"github.com/spf13/viper"
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  // Test the invocation of a transaction for private data.
    23  func TestQueriesPrivateData(t *testing.T) {
    24  	// Skipping this tests as this test requires the application configuration to be set such that the private data capability is set to 'true'
    25  	// However, with the latest restructuring of some of the packages, it is not possible to register system chaincodes with desired configurations for test.
    26  	// see function RegisterSysCCs in file 'fabric/core/scc/register.go'. In absence of this lscc returns error while deploying a chaincode with collection configurations.
    27  	// This test should be moved as an integration test outside of chaincode package.
    28  	t.Skip()
    29  	channelID := "testchannelid"
    30  	_, _, chaincodeSupport, cleanup, err := initPeer(channelID)
    31  	if err != nil {
    32  		t.Fail()
    33  		t.Logf("Error creating peer: %s", err)
    34  	}
    35  
    36  	defer cleanup()
    37  
    38  	peer.CreateMockChannel(chaincodeSupport.Peer, channelID, nil)
    39  
    40  	url := "github.com/hyperledger/fabric/core/chaincode/testdata/src/chaincodes/map"
    41  	cID := &pb.ChaincodeID{Name: "tmap", Path: url, Version: "0"}
    42  
    43  	f := "init"
    44  	args := util.ToChaincodeArgs(f)
    45  
    46  	spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
    47  
    48  	ccContext := &CCContext{
    49  		Name:    "tmap",
    50  		Version: "0",
    51  	}
    52  
    53  	var nextBlockNumber uint64 = 1
    54  	// this test assumes four collections
    55  	collectionConfig := []*pb.StaticCollectionConfig{{Name: "c1"}, {Name: "c2"}, {Name: "c3"}, {Name: "c4"}}
    56  	collectionConfigPkg := constructCollectionConfigPkg(collectionConfig)
    57  	defer chaincodeSupport.Runtime.Stop(cID.Name + ":" + cID.Version)
    58  	_, err = deployWithCollectionConfigs(channelID, ccContext, spec, collectionConfigPkg, nextBlockNumber, chaincodeSupport)
    59  	nextBlockNumber++
    60  	ccID := spec.ChaincodeId.Name
    61  	if err != nil {
    62  		t.Fail()
    63  		t.Logf("Error initializing chaincode %s(%s)", ccID, err)
    64  		return
    65  	}
    66  
    67  	// Add 101 marbles for testing range queries and rich queries (for capable ledgers)
    68  	// on both public and private data. The tests will test both range and rich queries
    69  	// and queries with query limits
    70  	for i := 1; i <= 101; i++ {
    71  		f = "put"
    72  
    73  		// 51 owned by tom, 50 by jerry
    74  		owner := "tom"
    75  		if i%2 == 0 {
    76  			owner = "jerry"
    77  		}
    78  
    79  		// one marble color is red, 100 are blue
    80  		color := "blue"
    81  		if i == 12 {
    82  			color = "red"
    83  		}
    84  
    85  		key := fmt.Sprintf("marble%03d", i)
    86  		argsString := fmt.Sprintf("{\"docType\":\"marble\",\"name\":\"%s\",\"color\":\"%s\",\"size\":35,\"owner\":\"%s\"}", key, color, owner)
    87  		args = util.ToChaincodeArgs(f, key, argsString)
    88  		spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
    89  		_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
    90  		nextBlockNumber++
    91  
    92  		if err != nil {
    93  			t.Fail()
    94  			t.Logf("Error invoking <%s>: %s", ccID, err)
    95  			return
    96  		}
    97  
    98  		f = "putPrivate"
    99  
   100  		key = fmt.Sprintf("pmarble%03d", i)
   101  		args = util.ToChaincodeArgs(f, "c1", key, argsString)
   102  		spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   103  		_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   104  		nextBlockNumber++
   105  
   106  		if err != nil {
   107  			t.Fail()
   108  			t.Logf("Error invoking <%s>: %s", ccID, err)
   109  			return
   110  		}
   111  
   112  	}
   113  
   114  	// Insert a marble in 3 private collections
   115  	for i := 2; i <= 4; i++ {
   116  		collection := fmt.Sprintf("c%d", i)
   117  		value := fmt.Sprintf("value_c%d", i)
   118  
   119  		f = "putPrivate"
   120  		t.Logf("invoking PutPrivateData with collection:<%s> key:%s", collection, "marble001")
   121  		args = util.ToChaincodeArgs(f, collection, "pmarble001", value)
   122  		spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   123  		_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   124  		nextBlockNumber++
   125  
   126  		if err != nil {
   127  			t.Fail()
   128  			t.Logf("Error invoking <%s>: %s", ccID, err)
   129  			return
   130  		}
   131  	}
   132  
   133  	// read a marble from collection c3
   134  	f = "getPrivate"
   135  	args = util.ToChaincodeArgs(f, "c3", "pmarble001")
   136  
   137  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   138  	_, _, retval, err := invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   139  	nextBlockNumber++
   140  
   141  	if err != nil {
   142  		t.Fail()
   143  		t.Logf("Error invoking <%s>: %s", ccID, err)
   144  		return
   145  	}
   146  
   147  	var val string
   148  	err = json.Unmarshal(retval, &val)
   149  	assert.NoError(t, err)
   150  	expectedValue := fmt.Sprintf("value_c%d", 3)
   151  	if val != expectedValue {
   152  		t.Fail()
   153  		t.Logf("Error detected with the GetPrivateData: expected '%s' but got '%s'", expectedValue, val)
   154  		return
   155  	}
   156  
   157  	// delete a marble from collection c3
   158  	f = "removePrivate"
   159  	args = util.ToChaincodeArgs(f, "c3", "pmarble001")
   160  
   161  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   162  	_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   163  	nextBlockNumber++
   164  
   165  	if err != nil {
   166  		t.Fail()
   167  		t.Logf("Error invoking <%s>: %s", ccID, err)
   168  		return
   169  	}
   170  
   171  	// delete a marble from collection c4
   172  	f = "removePrivate"
   173  	args = util.ToChaincodeArgs(f, "c4", "pmarble001")
   174  
   175  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   176  	_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   177  	nextBlockNumber++
   178  
   179  	if err != nil {
   180  		t.Fail()
   181  		t.Logf("Error invoking <%s>: %s", ccID, err)
   182  		return
   183  	}
   184  
   185  	// read deleted marble from collection c3 to verify whether delete executed correctly
   186  	f = "getPrivate"
   187  	args = util.ToChaincodeArgs(f, "c3", "pmarble001")
   188  
   189  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   190  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   191  	nextBlockNumber++
   192  
   193  	if err != nil {
   194  		t.Fail()
   195  		t.Logf("Error invoking <%s>: %s", ccID, err)
   196  		return
   197  	}
   198  
   199  	err = json.Unmarshal(retval, &val)
   200  	assert.NoError(t, err)
   201  	if val != "" {
   202  		t.Fail()
   203  		t.Logf("Error detected with the GetPrivateData")
   204  		return
   205  	}
   206  
   207  	// try to read the marble inserted in collection c2 from public state to check
   208  	// whether it returns the marble (for correct operation, it should not return)
   209  	f = "get"
   210  	args = util.ToChaincodeArgs(f, "pmarble001")
   211  
   212  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   213  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   214  	nextBlockNumber++
   215  
   216  	if err != nil {
   217  		t.Fail()
   218  		t.Logf("Error invoking <%s>: %s", ccID, err)
   219  		return
   220  	}
   221  
   222  	err = json.Unmarshal(retval, &val)
   223  	assert.NoError(t, err)
   224  	if val != "" {
   225  		t.Fail()
   226  		t.Logf("Error detected with the GetState: %s", val)
   227  		return
   228  	}
   229  	//The following range query for "marble001" to "marble011" should return 10 marbles
   230  	f = "keysPrivate"
   231  	args = util.ToChaincodeArgs(f, "c1", "pmarble001", "pmarble011")
   232  
   233  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   234  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   235  	nextBlockNumber++
   236  	if err != nil {
   237  		t.Fail()
   238  		t.Logf("Error invoking <%s>: %s", ccID, err)
   239  		return
   240  	}
   241  	var keys []interface{}
   242  	err = json.Unmarshal(retval, &keys)
   243  	assert.NoError(t, err)
   244  	if len(keys) != 10 {
   245  		t.Fail()
   246  		t.Logf("Error detected with the range query, should have returned 10 but returned %v", len(keys))
   247  		return
   248  	}
   249  
   250  	//The following range query for "marble001" to "marble011" should return 10 marbles
   251  	f = "keys"
   252  	args = util.ToChaincodeArgs(f, "marble001", "marble011")
   253  
   254  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   255  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   256  	nextBlockNumber++
   257  	if err != nil {
   258  		t.Fail()
   259  		t.Logf("Error invoking <%s>: %s", ccID, err)
   260  		return
   261  	}
   262  
   263  	err = json.Unmarshal(retval, &keys)
   264  	assert.NoError(t, err)
   265  	if len(keys) != 10 {
   266  		t.Fail()
   267  		t.Logf("Error detected with the range query, should have returned 10 but returned %v", len(keys))
   268  		return
   269  	}
   270  
   271  	//FAB-1163- The following range query should timeout and produce an error
   272  	//the peer should handle this gracefully and not die
   273  
   274  	//save the original timeout and set a new timeout of 1 sec
   275  	origTimeout := chaincodeSupport.ExecuteTimeout
   276  	chaincodeSupport.ExecuteTimeout = time.Duration(1) * time.Second
   277  
   278  	//chaincode to sleep for 2 secs with timeout 1
   279  	args = util.ToChaincodeArgs(f, "marble001", "marble002", "2000")
   280  
   281  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   282  	_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   283  	if err == nil {
   284  		t.Fail()
   285  		t.Logf("expected timeout error but succeeded")
   286  		return
   287  	}
   288  
   289  	//restore timeout
   290  	chaincodeSupport.ExecuteTimeout = origTimeout
   291  
   292  	// querying for all marbles will return 101 marbles
   293  	// this query should return exactly 101 results (one call to Next())
   294  	//The following range query for "marble001" to "marble102" should return 101 marbles
   295  	f = "keys"
   296  	args = util.ToChaincodeArgs(f, "marble001", "marble102")
   297  
   298  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   299  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   300  	nextBlockNumber++
   301  	if err != nil {
   302  		t.Fail()
   303  		t.Logf("Error invoking <%s>: %s", ccID, err)
   304  		return
   305  	}
   306  
   307  	//unmarshal the results
   308  	err = json.Unmarshal(retval, &keys)
   309  	assert.NoError(t, err)
   310  
   311  	//check to see if there are 101 values
   312  	//default query limit of 10000 is used, this query is effectively unlimited
   313  	if len(keys) != 101 {
   314  		t.Fail()
   315  		t.Logf("Error detected with the range query, should have returned 101 but returned %v", len(keys))
   316  		return
   317  	}
   318  
   319  	// querying for all simple key. This query should return exactly 101 simple keys (one
   320  	// call to Next()) no composite keys.
   321  	//The following open ended range query for "" to "" should return 101 marbles
   322  	f = "keys"
   323  	args = util.ToChaincodeArgs(f, "", "")
   324  
   325  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   326  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   327  	nextBlockNumber++
   328  	if err != nil {
   329  		t.Fail()
   330  		t.Logf("Error invoking <%s>: %s", ccID, err)
   331  		return
   332  	}
   333  
   334  	//unmarshal the results
   335  	err = json.Unmarshal(retval, &keys)
   336  	assert.NoError(t, err)
   337  
   338  	//check to see if there are 101 values
   339  	//default query limit of 10000 is used, this query is effectively unlimited
   340  	if len(keys) != 101 {
   341  		t.Fail()
   342  		t.Logf("Error detected with the range query, should have returned 101 but returned %v", len(keys))
   343  		return
   344  	}
   345  
   346  	// ExecuteQuery supported only for CouchDB and
   347  	// query limits apply for CouchDB range and rich queries only
   348  	// corner cases for shim batching. currnt shim batch size is 100
   349  	// this query should return exactly 100 results (no call to Next())
   350  	f = "query"
   351  	args = util.ToChaincodeArgs(f, "{\"selector\":{\"color\":\"blue\"}}")
   352  
   353  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   354  	_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   355  	nextBlockNumber++
   356  
   357  	if err != nil {
   358  		t.Fail()
   359  		t.Logf("Error invoking <%s>: %s", ccID, err)
   360  		return
   361  	}
   362  
   363  	//unmarshal the results
   364  	err = json.Unmarshal(retval, &keys)
   365  	assert.NoError(t, err)
   366  
   367  	//check to see if there are 100 values
   368  	if len(keys) != 100 {
   369  		t.Fail()
   370  		t.Logf("Error detected with the rich query, should have returned 100 but returned %v %s", len(keys), keys)
   371  		return
   372  	}
   373  	f = "queryPrivate"
   374  	args = util.ToChaincodeArgs(f, "c1", "{\"selector\":{\"color\":\"blue\"}}")
   375  
   376  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   377  	_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   378  	nextBlockNumber++
   379  	if err != nil {
   380  		t.Fail()
   381  		t.Logf("Error invoking <%s>: %s", ccID, err)
   382  		return
   383  	}
   384  
   385  	//unmarshal the results
   386  	err = json.Unmarshal(retval, &keys)
   387  	assert.NoError(t, err)
   388  
   389  	//check to see if there are 100 values
   390  	if len(keys) != 100 {
   391  		t.Fail()
   392  		t.Logf("Error detected with the rich query, should have returned 100 but returned %v %s", len(keys), keys)
   393  		return
   394  	}
   395  	//Reset the query limit to 5
   396  	viper.Set("ledger.state.queryLimit", 5)
   397  
   398  	//The following range query for "marble01" to "marble11" should return 5 marbles due to the queryLimit
   399  	f = "keys"
   400  	args = util.ToChaincodeArgs(f, "marble001", "marble011")
   401  
   402  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   403  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   404  	nextBlockNumber++
   405  	if err != nil {
   406  		t.Fail()
   407  		t.Logf("Error invoking <%s>: %s", ccID, err)
   408  		return
   409  	}
   410  
   411  	//unmarshal the results
   412  	err = json.Unmarshal(retval, &keys)
   413  	assert.NoError(t, err)
   414  	//check to see if there are 5 values
   415  	if len(keys) != 5 {
   416  		t.Fail()
   417  		t.Logf("Error detected with the range query, should have returned 5 but returned %v", len(keys))
   418  		return
   419  	}
   420  
   421  	//Reset the query limit to 10000
   422  	viper.Set("ledger.state.queryLimit", 10000)
   423  
   424  	//The following rich query for should return 50 marbles
   425  	f = "query"
   426  	args = util.ToChaincodeArgs(f, "{\"selector\":{\"owner\":\"jerry\"}}")
   427  
   428  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   429  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   430  	nextBlockNumber++
   431  
   432  	if err != nil {
   433  		t.Fail()
   434  		t.Logf("Error invoking <%s>: %s", ccID, err)
   435  		return
   436  	}
   437  
   438  	//unmarshal the results
   439  	err = json.Unmarshal(retval, &keys)
   440  	assert.NoError(t, err)
   441  
   442  	//check to see if there are 50 values
   443  	//default query limit of 10000 is used, this query is effectively unlimited
   444  	if len(keys) != 50 {
   445  		t.Fail()
   446  		t.Logf("Error detected with the rich query, should have returned 50 but returned %v", len(keys))
   447  		return
   448  	}
   449  
   450  	//Reset the query limit to 5
   451  	viper.Set("ledger.state.queryLimit", 5)
   452  
   453  	//The following rich query should return 5 marbles due to the queryLimit
   454  	f = "query"
   455  	args = util.ToChaincodeArgs(f, "{\"selector\":{\"owner\":\"jerry\"}}")
   456  
   457  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   458  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   459  	nextBlockNumber++
   460  	if err != nil {
   461  		t.Fail()
   462  		t.Logf("Error invoking <%s>: %s", ccID, err)
   463  		return
   464  	}
   465  
   466  	//unmarshal the results
   467  	err = json.Unmarshal(retval, &keys)
   468  	assert.NoError(t, err)
   469  
   470  	//check to see if there are 5 values
   471  	if len(keys) != 5 {
   472  		t.Fail()
   473  		t.Logf("Error detected with the rich query, should have returned 5 but returned %v", len(keys))
   474  		return
   475  	}
   476  
   477  	// modifications for history query
   478  	f = "put"
   479  	args = util.ToChaincodeArgs(f, "marble012", "{\"docType\":\"marble\",\"name\":\"marble012\",\"color\":\"red\",\"size\":30,\"owner\":\"jerry\"}")
   480  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   481  	_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   482  	nextBlockNumber++
   483  	if err != nil {
   484  		t.Fail()
   485  		t.Logf("Error invoking <%s>: %s", ccID, err)
   486  		return
   487  	}
   488  
   489  	f = "put"
   490  	args = util.ToChaincodeArgs(f, "marble012", "{\"docType\":\"marble\",\"name\":\"marble012\",\"color\":\"red\",\"size\":30,\"owner\":\"jerry\"}")
   491  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   492  	_, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   493  	nextBlockNumber++
   494  	if err != nil {
   495  		t.Fail()
   496  		t.Logf("Error invoking <%s>: %s", ccID, err)
   497  		return
   498  	}
   499  
   500  	//The following history query for "marble12" should return 3 records
   501  	f = "history"
   502  	args = util.ToChaincodeArgs(f, "marble012")
   503  	spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
   504  	_, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport)
   505  	nextBlockNumber++
   506  	if err != nil {
   507  		t.Fail()
   508  		t.Logf("Error invoking <%s>: %s", ccID, err)
   509  		return
   510  	}
   511  
   512  	var history []interface{}
   513  	err = json.Unmarshal(retval, &history)
   514  	assert.NoError(t, err)
   515  	if len(history) != 3 {
   516  		t.Fail()
   517  		t.Logf("Error detected with the history query, should have returned 3 but returned %v", len(history))
   518  		return
   519  	}
   520  }
   521  
   522  func constructCollectionConfigPkg(staticCollectionConfigs []*pb.StaticCollectionConfig) *pb.CollectionConfigPackage {
   523  	var cc []*pb.CollectionConfig
   524  	for _, sc := range staticCollectionConfigs {
   525  		cc = append(cc, &pb.CollectionConfig{
   526  			Payload: &pb.CollectionConfig_StaticCollectionConfig{
   527  				StaticCollectionConfig: sc}})
   528  	}
   529  	return &pb.CollectionConfigPackage{Config: cc}
   530  }