github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/common/policies/convert.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package policies
     8  
     9  import (
    10  	"fmt"
    11  
    12  	cb "github.com/hyperledger/fabric-protos-go/common"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  // remap explores the policy tree depth first and remaps the "signed by"
    17  // entries according to the remapping rules; a "signed by" rule requires
    18  // a signature from a principal given its position in the array of principals;
    19  // the idRemap map tells us how to remap these integers given that merging two
    20  // policies implies deduplicating their principals
    21  func remap(sp *cb.SignaturePolicy, idRemap map[int]int) *cb.SignaturePolicy {
    22  	switch t := sp.Type.(type) {
    23  	case *cb.SignaturePolicy_NOutOf_:
    24  		rules := []*cb.SignaturePolicy{}
    25  		for _, rule := range t.NOutOf.Rules {
    26  			// here we call remap again - we're doing a
    27  			// depth-first traversal of this policy tree
    28  			rules = append(rules, remap(rule, idRemap))
    29  		}
    30  
    31  		return &cb.SignaturePolicy{
    32  			Type: &cb.SignaturePolicy_NOutOf_{
    33  				NOutOf: &cb.SignaturePolicy_NOutOf{
    34  					N:     t.NOutOf.N,
    35  					Rules: rules,
    36  				},
    37  			},
    38  		}
    39  	case *cb.SignaturePolicy_SignedBy:
    40  		// here we do the actual remapping because we have
    41  		// the "signed by" rule, whose reference to the
    42  		// principal we need to remap
    43  		newID, in := idRemap[int(t.SignedBy)]
    44  		if !in {
    45  			panic("programming error")
    46  		}
    47  
    48  		return &cb.SignaturePolicy{
    49  			Type: &cb.SignaturePolicy_SignedBy{
    50  				SignedBy: int32(newID),
    51  			},
    52  		}
    53  	default:
    54  		panic(fmt.Sprintf("invalid policy type %T", t))
    55  	}
    56  }
    57  
    58  // merge integrates the policy `that` into the
    59  // policy `this`. The first argument is changed
    60  // whereas the second isn't
    61  func merge(this *cb.SignaturePolicyEnvelope, that *cb.SignaturePolicyEnvelope) {
    62  	// at first we build a map of principals in `this`
    63  	IDs := this.Identities
    64  	idMap := map[string]int{}
    65  	for i, id := range this.Identities {
    66  		str := id.PrincipalClassification.String() + string(id.Principal)
    67  		idMap[str] = i
    68  	}
    69  
    70  	// then we traverse each of the principals in `that`,
    71  	// deduplicate them against the ones in `this` and
    72  	// create remapping rules so that if `that` references
    73  	// a duplicate policy in this, the merged policy will
    74  	// ensure that the references in `that` point to the
    75  	// correct principal
    76  	idRemap := map[int]int{}
    77  	for i, id := range that.Identities {
    78  		str := id.PrincipalClassification.String() + string(id.Principal)
    79  		if j, in := idMap[str]; in {
    80  			idRemap[i] = j
    81  		} else {
    82  			idRemap[i] = len(IDs)
    83  			idMap[str] = len(IDs)
    84  			IDs = append(IDs, id)
    85  		}
    86  	}
    87  
    88  	this.Identities = IDs
    89  
    90  	newEntry := remap(that.Rule, idRemap)
    91  
    92  	existingRules := this.Rule.Type.(*cb.SignaturePolicy_NOutOf_).NOutOf.Rules
    93  	this.Rule.Type.(*cb.SignaturePolicy_NOutOf_).NOutOf.Rules = append(existingRules, newEntry)
    94  }
    95  
    96  // Convert implements the policies.Converter function to
    97  // convert an implicit meta policy into a signature policy envelope.
    98  func (p *ImplicitMetaPolicy) Convert() (*cb.SignaturePolicyEnvelope, error) {
    99  	converted := &cb.SignaturePolicyEnvelope{
   100  		Version: 0,
   101  		Rule: &cb.SignaturePolicy{
   102  			Type: &cb.SignaturePolicy_NOutOf_{
   103  				NOutOf: &cb.SignaturePolicy_NOutOf{
   104  					N: int32(p.Threshold),
   105  				},
   106  			},
   107  		},
   108  	}
   109  
   110  	// the conversion approach for an implicit meta
   111  	// policy is to convert each of the subpolicies,
   112  	// merge it with the previous one and return the
   113  	// merged policy
   114  	for i, subPolicy := range p.SubPolicies {
   115  		convertibleSubpolicy, ok := subPolicy.(Converter)
   116  		if !ok {
   117  			return nil, errors.Errorf("subpolicy number %d type %T of policy %s is not convertible", i, subPolicy, p.SubPolicyName)
   118  		}
   119  
   120  		spe, err := convertibleSubpolicy.Convert()
   121  		if err != nil {
   122  			return nil, errors.WithMessagef(err, "failed to convert subpolicy number %d of policy %s", i, p.SubPolicyName)
   123  		}
   124  
   125  		merge(converted, spe)
   126  	}
   127  
   128  	return converted, nil
   129  }