github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/deployedcc_infoprovider.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lifecycle
     8  
     9  import (
    10  	"fmt"
    11  	"regexp"
    12  
    13  	"github.com/hechain20/hechain/common/policydsl"
    14  	"github.com/hechain20/hechain/common/util"
    15  	"github.com/hechain20/hechain/core/chaincode/implicitcollection"
    16  	validationState "github.com/hechain20/hechain/core/handlers/validation/api/state"
    17  	"github.com/hechain20/hechain/core/ledger"
    18  	"github.com/hechain20/hechain/core/peer"
    19  	"github.com/hechain20/hechain/gossip/privdata"
    20  	"github.com/hechain20/hechain/protoutil"
    21  	cb "github.com/hyperledger/fabric-protos-go/common"
    22  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    23  	pb "github.com/hyperledger/fabric-protos-go/peer"
    24  
    25  	"github.com/pkg/errors"
    26  )
    27  
    28  //go:generate counterfeiter -o mock/legacy_ccinfo.go --fake-name LegacyDeployedCCInfoProvider . LegacyDeployedCCInfoProvider
    29  type LegacyDeployedCCInfoProvider interface {
    30  	ledger.DeployedChaincodeInfoProvider
    31  }
    32  
    33  const (
    34  	LifecycleEndorsementPolicyRef = "/Channel/Application/LifecycleEndorsement"
    35  )
    36  
    37  // This is a channel which was created with a lifecycle endorsement policy
    38  var LifecycleDefaultEndorsementPolicyBytes = protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
    39  	Type: &cb.ApplicationPolicy_ChannelConfigPolicyReference{
    40  		ChannelConfigPolicyReference: LifecycleEndorsementPolicyRef,
    41  	},
    42  })
    43  
    44  type ValidatorCommitter struct {
    45  	CoreConfig                   *peer.Config
    46  	PrivdataConfig               *privdata.PrivdataConfig
    47  	Resources                    *Resources
    48  	LegacyDeployedCCInfoProvider LegacyDeployedCCInfoProvider
    49  }
    50  
    51  // Namespaces returns the list of namespaces which are relevant to chaincode lifecycle
    52  func (vc *ValidatorCommitter) Namespaces() []string {
    53  	return append([]string{LifecycleNamespace}, vc.LegacyDeployedCCInfoProvider.Namespaces()...)
    54  }
    55  
    56  var SequenceMatcher = regexp.MustCompile("^" + NamespacesName + "/fields/([^/]+)/Sequence$")
    57  
    58  // UpdatedChaincodes returns the chaincodes that are getting updated by the supplied 'stateUpdates'
    59  func (vc *ValidatorCommitter) UpdatedChaincodes(stateUpdates map[string][]*kvrwset.KVWrite) ([]*ledger.ChaincodeLifecycleInfo, error) {
    60  	lifecycleInfo := []*ledger.ChaincodeLifecycleInfo{}
    61  
    62  	// If the lifecycle table was updated, report only modified chaincodes
    63  	lifecycleUpdates := stateUpdates[LifecycleNamespace]
    64  
    65  	for _, kvWrite := range lifecycleUpdates {
    66  		matches := SequenceMatcher.FindStringSubmatch(kvWrite.Key)
    67  		if len(matches) != 2 {
    68  			continue
    69  		}
    70  		// XXX Note, this may not be a chaincode namespace, handle this later
    71  		lifecycleInfo = append(lifecycleInfo, &ledger.ChaincodeLifecycleInfo{Name: matches[1]})
    72  	}
    73  
    74  	legacyUpdates, err := vc.LegacyDeployedCCInfoProvider.UpdatedChaincodes(stateUpdates)
    75  	if err != nil {
    76  		return nil, errors.WithMessage(err, "error invoking legacy deployed cc info provider")
    77  	}
    78  
    79  	return append(lifecycleInfo, legacyUpdates...), nil
    80  }
    81  
    82  func (vc *ValidatorCommitter) ChaincodeInfo(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*ledger.DeployedChaincodeInfo, error) {
    83  	exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{
    84  		Namespace:           LifecycleNamespace,
    85  		SimpleQueryExecutor: qe,
    86  	})
    87  	if err != nil {
    88  		return nil, errors.WithMessage(err, "could not get info about chaincode")
    89  	}
    90  
    91  	if !exists {
    92  		return vc.LegacyDeployedCCInfoProvider.ChaincodeInfo(channelName, chaincodeName, qe)
    93  	}
    94  
    95  	return &ledger.DeployedChaincodeInfo{
    96  		Name:                        chaincodeName,
    97  		Version:                     definedChaincode.EndorsementInfo.Version,
    98  		Hash:                        util.ComputeSHA256([]byte(chaincodeName + ":" + definedChaincode.EndorsementInfo.Version)),
    99  		ExplicitCollectionConfigPkg: definedChaincode.Collections,
   100  		IsLegacy:                    false,
   101  	}, nil
   102  }
   103  
   104  // AllChaincodesInfo returns the mapping of chaincode name to DeployedChaincodeInfo for all the deployed chaincodes
   105  func (vc *ValidatorCommitter) AllChaincodesInfo(channelName string, sqe ledger.SimpleQueryExecutor) (map[string]*ledger.DeployedChaincodeInfo, error) {
   106  	sqes := &SimpleQueryExecutorShim{
   107  		Namespace:           LifecycleNamespace,
   108  		SimpleQueryExecutor: sqe,
   109  	}
   110  	ccQuery := &ExternalFunctions{Resources: vc.Resources}
   111  	namespaceDefs, err := ccQuery.QueryNamespaceDefinitions(sqes)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	result := make(map[string]*ledger.DeployedChaincodeInfo)
   117  	for ccName, value := range namespaceDefs {
   118  		if value != FriendlyChaincodeDefinitionType {
   119  			continue
   120  		}
   121  		deployedccInfo, err := vc.ChaincodeInfo(channelName, ccName, sqe)
   122  		if err != nil {
   123  			return nil, err
   124  		}
   125  		result[ccName] = deployedccInfo
   126  	}
   127  
   128  	legacyCCs, err := vc.LegacyDeployedCCInfoProvider.AllChaincodesInfo(channelName, sqe)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	for ccName, deployedccInfo := range legacyCCs {
   134  		if _, ok := result[ccName]; !ok {
   135  			result[ccName] = deployedccInfo
   136  		}
   137  	}
   138  
   139  	return result, nil
   140  }
   141  
   142  // AllCollectionsConfigPkg implements function in interface ledger.DeployedChaincodeInfoProvider
   143  // this implementation returns a combined collection config pkg that contains both explicit and implicit collections
   144  func (vc *ValidatorCommitter) AllCollectionsConfigPkg(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*pb.CollectionConfigPackage, error) {
   145  	chaincodeInfo, err := vc.ChaincodeInfo(channelName, chaincodeName, qe)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	explicitCollectionConfigPkg := chaincodeInfo.ExplicitCollectionConfigPkg
   150  
   151  	if chaincodeInfo.IsLegacy {
   152  		return explicitCollectionConfigPkg, nil
   153  	}
   154  
   155  	implicitCollections, err := vc.ImplicitCollections(channelName, chaincodeName, qe)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	var combinedColls []*pb.CollectionConfig
   161  	if explicitCollectionConfigPkg != nil {
   162  		combinedColls = append(combinedColls, explicitCollectionConfigPkg.Config...)
   163  	}
   164  	for _, implicitColl := range implicitCollections {
   165  		c := &pb.CollectionConfig{}
   166  		c.Payload = &pb.CollectionConfig_StaticCollectionConfig{StaticCollectionConfig: implicitColl}
   167  		combinedColls = append(combinedColls, c)
   168  	}
   169  	return &pb.CollectionConfigPackage{
   170  		Config: combinedColls,
   171  	}, nil
   172  }
   173  
   174  // CollectionInfo implements function in interface ledger.DeployedChaincodeInfoProvider, it returns config for
   175  // both static and implicit collections.
   176  func (vc *ValidatorCommitter) CollectionInfo(channelName, chaincodeName, collectionName string, qe ledger.SimpleQueryExecutor) (*pb.StaticCollectionConfig, error) {
   177  	exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{
   178  		Namespace:           LifecycleNamespace,
   179  		SimpleQueryExecutor: qe,
   180  	})
   181  	if err != nil {
   182  		return nil, errors.WithMessage(err, "could not get chaincode")
   183  	}
   184  
   185  	if !exists {
   186  		return vc.LegacyDeployedCCInfoProvider.CollectionInfo(channelName, chaincodeName, collectionName, qe)
   187  	}
   188  
   189  	isImplicitCollection, mspID := implicitcollection.MspIDIfImplicitCollection(collectionName)
   190  	if isImplicitCollection {
   191  		return vc.GenerateImplicitCollectionForOrg(mspID), nil
   192  	}
   193  
   194  	if definedChaincode.Collections != nil {
   195  		for _, conf := range definedChaincode.Collections.Config {
   196  			staticCollConfig := conf.GetStaticCollectionConfig()
   197  			if staticCollConfig != nil && staticCollConfig.Name == collectionName {
   198  				return staticCollConfig, nil
   199  			}
   200  		}
   201  	}
   202  	return nil, nil
   203  }
   204  
   205  // ImplicitCollections implements function in interface ledger.DeployedChaincodeInfoProvider.  It returns
   206  // a slice that contains one proto msg for each of the implicit collections
   207  func (vc *ValidatorCommitter) ImplicitCollections(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) ([]*pb.StaticCollectionConfig, error) {
   208  	exists, _, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{
   209  		Namespace:           LifecycleNamespace,
   210  		SimpleQueryExecutor: qe,
   211  	})
   212  	if err != nil {
   213  		return nil, errors.WithMessage(err, "could not get info about chaincode")
   214  	}
   215  
   216  	if !exists {
   217  		// Implicit collections are a v2.0 lifecycle concept, if the chaincode is not in the new lifecycle, return nothing
   218  		return nil, nil
   219  	}
   220  
   221  	return vc.ChaincodeImplicitCollections(channelName)
   222  }
   223  
   224  // ChaincodeImplicitCollections assumes the chaincode exists in the new lifecycle and returns the implicit collections
   225  func (vc *ValidatorCommitter) ChaincodeImplicitCollections(channelName string) ([]*pb.StaticCollectionConfig, error) {
   226  	channelConfig := vc.Resources.ChannelConfigSource.GetStableChannelConfig(channelName)
   227  	if channelConfig == nil {
   228  		return nil, errors.Errorf("could not get channelconfig for channel %s", channelName)
   229  	}
   230  	ac, ok := channelConfig.ApplicationConfig()
   231  	if !ok {
   232  		return nil, errors.Errorf("could not get application config for channel %s", channelName)
   233  	}
   234  
   235  	orgs := ac.Organizations()
   236  	implicitCollections := make([]*pb.StaticCollectionConfig, 0, len(orgs))
   237  	for _, org := range orgs {
   238  		implicitCollections = append(implicitCollections, vc.GenerateImplicitCollectionForOrg(org.MSPID()))
   239  	}
   240  
   241  	return implicitCollections, nil
   242  }
   243  
   244  // GenerateImplicitCollectionForOrg generates implicit collection for the org
   245  func (vc *ValidatorCommitter) GenerateImplicitCollectionForOrg(mspid string) *pb.StaticCollectionConfig {
   246  	// set Required/MaxPeerCount to 0 if it is other org's implicit collection (mspid does not match peer's local mspid)
   247  	// set Required/MaxPeerCount to the config values if it is the peer org's implicit collection (mspid matches peer's local mspid)
   248  	requiredPeerCount := 0
   249  	maxPeerCount := 0
   250  	if mspid == vc.CoreConfig.LocalMSPID {
   251  		requiredPeerCount = vc.PrivdataConfig.ImplicitCollDisseminationPolicy.RequiredPeerCount
   252  		maxPeerCount = vc.PrivdataConfig.ImplicitCollDisseminationPolicy.MaxPeerCount
   253  	}
   254  	return &pb.StaticCollectionConfig{
   255  		Name: implicitcollection.NameForOrg(mspid),
   256  		MemberOrgsPolicy: &pb.CollectionPolicyConfig{
   257  			Payload: &pb.CollectionPolicyConfig_SignaturePolicy{
   258  				SignaturePolicy: policydsl.SignedByMspMember(mspid),
   259  			},
   260  		},
   261  		RequiredPeerCount: int32(requiredPeerCount),
   262  		MaximumPeerCount:  int32(maxPeerCount),
   263  	}
   264  }
   265  
   266  func (vc *ValidatorCommitter) ImplicitCollectionEndorsementPolicyAsBytes(channelID, orgMSPID string) (policy []byte, unexpectedErr, validationErr error) {
   267  	channelConfig := vc.Resources.ChannelConfigSource.GetStableChannelConfig(channelID)
   268  	if channelConfig == nil {
   269  		return nil, errors.Errorf("could not get channel config for channel '%s'", channelID), nil
   270  	}
   271  
   272  	ac, ok := channelConfig.ApplicationConfig()
   273  	if !ok {
   274  		return nil, errors.Errorf("could not get application config for channel '%s'", channelID), nil
   275  	}
   276  
   277  	matchedOrgName := ""
   278  	for orgName, org := range ac.Organizations() {
   279  		if org.MSPID() == orgMSPID {
   280  			matchedOrgName = orgName
   281  			break
   282  		}
   283  	}
   284  
   285  	if matchedOrgName == "" {
   286  		return nil, nil, errors.Errorf("no org found in channel with MSPID '%s'", orgMSPID)
   287  	}
   288  
   289  	policyName := fmt.Sprintf("/Channel/Application/%s/Endorsement", matchedOrgName)
   290  	if _, ok := channelConfig.PolicyManager().GetPolicy(policyName); ok {
   291  		return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
   292  			Type: &cb.ApplicationPolicy_ChannelConfigPolicyReference{
   293  				ChannelConfigPolicyReference: policyName,
   294  			},
   295  		}), nil, nil
   296  	}
   297  
   298  	// This was a channel which was upgraded or did not define an org level endorsement policy, use a default
   299  	// of "any member of the org"
   300  
   301  	return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
   302  		Type: &cb.ApplicationPolicy_SignaturePolicy{
   303  			SignaturePolicy: policydsl.SignedByAnyMember([]string{orgMSPID}),
   304  		},
   305  	}), nil, nil
   306  }
   307  
   308  // ValidationInfo returns the name and arguments of the validation plugin for the supplied
   309  // chaincode. The function returns two types of errors, unexpected errors and validation
   310  // errors. The reason for this is that this function is called from the validation code,
   311  // which needs to differentiate the two types of error to halt processing on the channel
   312  // if the unexpected error is not nil and mark the transaction as invalid if the validation
   313  // error is not nil.
   314  func (vc *ValidatorCommitter) ValidationInfo(channelID, chaincodeName string, qe ledger.SimpleQueryExecutor) (plugin string, args []byte, unexpectedErr error, validationErr error) {
   315  	// TODO, this is a bit of an overkill check, and will need to be scaled back for non-chaincode type namespaces
   316  	exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{
   317  		Namespace:           LifecycleNamespace,
   318  		SimpleQueryExecutor: qe,
   319  	})
   320  	if err != nil {
   321  		return "", nil, errors.WithMessage(err, "could not get chaincode"), nil
   322  	}
   323  
   324  	if !exists {
   325  		// TODO, this is inconsistent with how the legacy lifecycle reports
   326  		// that a missing chaincode is a validation error.  But, for now
   327  		// this is required to make the passthrough work.
   328  		return "", nil, nil, nil
   329  	}
   330  
   331  	if chaincodeName == LifecycleNamespace {
   332  		b, err := vc.Resources.LifecycleEndorsementPolicyAsBytes(channelID)
   333  		if err != nil {
   334  			return "", nil, errors.WithMessage(err, "unexpected failure to create lifecycle endorsement policy"), nil
   335  		}
   336  		return "vscc", b, nil, nil
   337  	}
   338  
   339  	return definedChaincode.ValidationInfo.ValidationPlugin, definedChaincode.ValidationInfo.ValidationParameter, nil, nil
   340  }
   341  
   342  // CollectionValidationInfo returns information about collections to the validation component
   343  func (vc *ValidatorCommitter) CollectionValidationInfo(channelID, chaincodeName, collectionName string, state validationState.State) (args []byte, unexpectedErr, validationErr error) {
   344  	exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &ValidatorStateShim{
   345  		Namespace:      LifecycleNamespace,
   346  		ValidatorState: state,
   347  	})
   348  	if err != nil {
   349  		return nil, errors.WithMessage(err, "could not get chaincode"), nil
   350  	}
   351  
   352  	if !exists {
   353  		// TODO, this is inconsistent with how the legacy lifecycle reports
   354  		// that a missing chaincode is a validation error.  But, for now
   355  		// this is required to make the passthrough work.
   356  		return nil, nil, nil
   357  	}
   358  
   359  	isImplicitCollection, mspID := implicitcollection.MspIDIfImplicitCollection(collectionName)
   360  	if isImplicitCollection {
   361  		return vc.ImplicitCollectionEndorsementPolicyAsBytes(channelID, mspID)
   362  	}
   363  
   364  	if definedChaincode.Collections != nil {
   365  		for _, conf := range definedChaincode.Collections.Config {
   366  			staticCollConfig := conf.GetStaticCollectionConfig()
   367  			if staticCollConfig != nil && staticCollConfig.Name == collectionName {
   368  				if staticCollConfig.EndorsementPolicy != nil {
   369  					return protoutil.MarshalOrPanic(staticCollConfig.EndorsementPolicy), nil, nil
   370  				}
   371  				// default to chaincode endorsement policy
   372  				return definedChaincode.ValidationInfo.ValidationParameter, nil, nil
   373  			}
   374  		}
   375  	}
   376  
   377  	return nil, nil, errors.Errorf("no such collection '%s'", collectionName)
   378  }