From f4ea5f79593000f278100654f530f2ca52194676 Mon Sep 17 00:00:00 2001 From: Andrew Coleman Date: Thu, 18 Aug 2022 18:27:24 +0100 Subject: [PATCH] Move BlockSignatureVerifier into protoutils (#3594) And refactor VerifyBlock() in orderer and peer gossip to use the common code. Signed-off-by: andrew-coleman Signed-off-by: andrew-coleman --- internal/peer/gossip/mcs.go | 65 +-------------- orderer/common/cluster/export_test.go | 10 --- orderer/common/cluster/util.go | 78 ++--------------- orderer/common/cluster/util_test.go | 113 ------------------------- protoutil/blockutils.go | 78 +++++++++++++++++ protoutil/blockutils_test.go | 115 ++++++++++++++++++++++++++ protoutil/mocks/policy.go | 114 +++++++++++++++++++++++++ 7 files changed, 314 insertions(+), 259 deletions(-) delete mode 100644 orderer/common/cluster/export_test.go create mode 100644 protoutil/mocks/policy.go diff --git a/internal/peer/gossip/mcs.go b/internal/peer/gossip/mcs.go index 12f0993a13d..a91e6dbd489 100644 --- a/internal/peer/gossip/mcs.go +++ b/internal/peer/gossip/mcs.go @@ -11,14 +11,11 @@ import ( "fmt" "time" - "github.com/golang/protobuf/proto" pcommon "github.com/hyperledger/fabric-protos-go/common" - pmsp "github.com/hyperledger/fabric-protos-go/msp" "github.com/hyperledger/fabric/bccsp" "github.com/hyperledger/fabric/common/channelconfig" "github.com/hyperledger/fabric/common/flogging" "github.com/hyperledger/fabric/common/policies" - "github.com/hyperledger/fabric/common/util" "github.com/hyperledger/fabric/gossip/api" "github.com/hyperledger/fabric/gossip/common" "github.com/hyperledger/fabric/internal/pkg/identity" @@ -159,15 +156,6 @@ func (s *MSPMessageCryptoService) VerifyBlock(chainID common.ChannelID, seqNum u return fmt.Errorf("Header.DataHash is different from Hash(block.Data) for block with id [%d] on channel [%s]", block.Header.Number, chainID) } - if len(block.Metadata.Metadata) < int(pcommon.BlockMetadataIndex_SIGNATURES)+1 { - return errors.Errorf("no signatures in block metadata") - } - - md := &pcommon.Metadata{} - if err := proto.Unmarshal(block.Metadata.Metadata[pcommon.BlockMetadataIndex_SIGNATURES], md); err != nil { - return errors.Wrapf(err, "error unmarshalling signatures from metadata: %v", err) - } - // Get the policy manager for channelID cpm := s.channelPolicyManagerGetter.Manager(channelID) if cpm == nil { @@ -192,57 +180,8 @@ func (s *MSPMessageCryptoService) VerifyBlock(chainID common.ChannelID, seqNum u consenters = cfg.Consenters() } - var signatureSet []*protoutil.SignedData - for _, metadataSignature := range md.Signatures { - var signerIdentity []byte - var signedPayload []byte - // if the SignatureHeader is empty and the IdentifierHeader is present, then the consenter expects us to fetch its identity by its numeric identifier - if bftEnabled && len(metadataSignature.GetSignatureHeader()) == 0 && len(metadataSignature.GetIdentifierHeader()) > 0 { - identifierHeader, err := protoutil.UnmarshalIdentifierHeader(metadataSignature.IdentifierHeader) - if err != nil { - return fmt.Errorf("failed unmarshalling identifier header for block %d: %v", block.Header.Number, err) - } - identifier := identifierHeader.GetIdentifier() - signerIdentity = searchConsenterIdentityByID(consenters, identifier) - if len(signerIdentity) == 0 { - // The identifier is not within the consenter set - continue - } - signedPayload = util.ConcatenateBytes(md.Value, metadataSignature.IdentifierHeader, protoutil.BlockHeaderBytes(block.Header)) - } else { - signatureHeader, err := protoutil.UnmarshalSignatureHeader(metadataSignature.GetSignatureHeader()) - if err != nil { - return fmt.Errorf("failed unmarshalling signature header for block %d: %v", block.Header.Number, err) - } - - signedPayload = util.ConcatenateBytes(md.Value, metadataSignature.SignatureHeader, protoutil.BlockHeaderBytes(block.Header)) - - signerIdentity = signatureHeader.Creator - } - - signatureSet = append( - signatureSet, - &protoutil.SignedData{ - Identity: signerIdentity, - Data: signedPayload, - Signature: metadataSignature.Signature, - }, - ) - } - - return policy.EvaluateSignedData(signatureSet) -} - -func searchConsenterIdentityByID(consenters []*pcommon.Consenter, identifier uint32) []byte { - for _, consenter := range consenters { - if consenter.Id == identifier { - return protoutil.MarshalOrPanic(&pmsp.SerializedIdentity{ - Mspid: consenter.MspId, - IdBytes: consenter.Identity, - }) - } - } - return nil + verifier := protoutil.BlockSignatureVerifier(bftEnabled, consenters, policy) + return verifier(block.Header, block.Metadata) } // Sign signs msg with this peer's signing key and outputs diff --git a/orderer/common/cluster/export_test.go b/orderer/common/cluster/export_test.go deleted file mode 100644 index ae1b339d4c7..00000000000 --- a/orderer/common/cluster/export_test.go +++ /dev/null @@ -1,10 +0,0 @@ -/* -Copyright IBM Corp. 2022 All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package cluster - -// export for testing -var BlockSignatureVerifier = blockSignatureVerifier diff --git a/orderer/common/cluster/util.go b/orderer/common/cluster/util.go index b64f1121497..ac7140c3a30 100644 --- a/orderer/common/cluster/util.go +++ b/orderer/common/cluster/util.go @@ -21,7 +21,6 @@ import ( "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric-config/protolator" "github.com/hyperledger/fabric-protos-go/common" - "github.com/hyperledger/fabric-protos-go/msp" "github.com/hyperledger/fabric/bccsp" "github.com/hyperledger/fabric/common/channelconfig" "github.com/hyperledger/fabric/common/configtx" @@ -489,10 +488,8 @@ func globalEndpointsFromConfig(aggregatedTLSCerts [][]byte, bundle *channelconfi return globalEndpoints } -type BlockVerifierFunc func(header *common.BlockHeader, metadata *common.BlockMetadata) error - -func BlockVerifierBuilder(bccsp bccsp.BCCSP) func(block *common.Block) BlockVerifierFunc { - return func(block *common.Block) BlockVerifierFunc { +func BlockVerifierBuilder(bccsp bccsp.BCCSP) func(block *common.Block) protoutil.BlockVerifierFunc { + return func(block *common.Block) protoutil.BlockVerifierFunc { bundle, failed := bundleFromConfigBlock(block, bccsp) if failed != nil { return failed @@ -514,76 +511,11 @@ func BlockVerifierBuilder(bccsp bccsp.BCCSP) func(block *common.Block) BlockVeri consenters = cfg.Consenters() } - return blockSignatureVerifier(bftEnabled, consenters, policy) - } -} - -func blockSignatureVerifier(bftEnabled bool, consenters []*common.Consenter, policy policies.Policy) BlockVerifierFunc { - return func(header *common.BlockHeader, metadata *common.BlockMetadata) error { - if len(metadata.Metadata) < int(common.BlockMetadataIndex_SIGNATURES)+1 { - return errors.Errorf("no signatures in block metadata") - } - - md := &common.Metadata{} - if err := proto.Unmarshal(metadata.Metadata[common.BlockMetadataIndex_SIGNATURES], md); err != nil { - return errors.Wrapf(err, "error unmarshalling signatures from metadata: %v", err) - } - - var signatureSet []*protoutil.SignedData - for _, metadataSignature := range md.Signatures { - var signerIdentity []byte - var signedPayload []byte - // if the SignatureHeader is empty and the IdentifierHeader is present, then the consenter expects us to fetch its identity by its numeric identifier - if bftEnabled && len(metadataSignature.GetSignatureHeader()) == 0 && len(metadataSignature.GetIdentifierHeader()) > 0 { - identifierHeader, err := protoutil.UnmarshalIdentifierHeader(metadataSignature.IdentifierHeader) - if err != nil { - return fmt.Errorf("failed unmarshalling identifier header for block %d: %v", header.Number, err) - } - identifier := identifierHeader.GetIdentifier() - signerIdentity = searchConsenterIdentityByID(consenters, identifier) - if len(signerIdentity) == 0 { - // The identifier is not within the consenter set - continue - } - signedPayload = util.ConcatenateBytes(md.Value, metadataSignature.IdentifierHeader, protoutil.BlockHeaderBytes(header)) - } else { - signatureHeader, err := protoutil.UnmarshalSignatureHeader(metadataSignature.GetSignatureHeader()) - if err != nil { - return fmt.Errorf("failed unmarshalling signature header for block %d: %v", header.Number, err) - } - - signedPayload = util.ConcatenateBytes(md.Value, metadataSignature.SignatureHeader, protoutil.BlockHeaderBytes(header)) - - signerIdentity = signatureHeader.Creator - } - - signatureSet = append( - signatureSet, - &protoutil.SignedData{ - Identity: signerIdentity, - Data: signedPayload, - Signature: metadataSignature.Signature, - }, - ) - } - - return policy.EvaluateSignedData(signatureSet) + return protoutil.BlockSignatureVerifier(bftEnabled, consenters, policy) } } -func searchConsenterIdentityByID(consenters []*common.Consenter, identifier uint32) []byte { - for _, consenter := range consenters { - if consenter.Id == identifier { - return protoutil.MarshalOrPanic(&msp.SerializedIdentity{ - Mspid: consenter.MspId, - IdBytes: consenter.Identity, - }) - } - } - return nil -} - -func bundleFromConfigBlock(block *common.Block, bccsp bccsp.BCCSP) (*channelconfig.Bundle, BlockVerifierFunc) { +func bundleFromConfigBlock(block *common.Block, bccsp bccsp.BCCSP) (*channelconfig.Bundle, protoutil.BlockVerifierFunc) { if block.Data == nil || len(block.Data.Data) == 0 { return nil, createErrorFunc(errors.New("block contains no data")) } @@ -601,7 +533,7 @@ func bundleFromConfigBlock(block *common.Block, bccsp bccsp.BCCSP) (*channelconf return bundle, nil } -func createErrorFunc(err error) BlockVerifierFunc { +func createErrorFunc(err error) protoutil.BlockVerifierFunc { return func(_ *common.BlockHeader, _ *common.BlockMetadata) error { return errors.Wrap(err, "initialized with an invalid config block") } diff --git a/orderer/common/cluster/util_test.go b/orderer/common/cluster/util_test.go index 3c4145b4c3d..1e8ec7cf81f 100644 --- a/orderer/common/cluster/util_test.go +++ b/orderer/common/cluster/util_test.go @@ -1274,119 +1274,6 @@ func TestBlockVerifierFunc(t *testing.T) { require.NoError(t, err) } -func TestBlockSignatureVerifierEmptyMetadata(t *testing.T) { - policies := mocks.Policy{} - - verify := cluster.BlockSignatureVerifier(true, nil, &policies) - - header := &common.BlockHeader{} - md := &common.BlockMetadata{} - - err := verify(header, md) - require.ErrorContains(t, err, "no signatures in block metadata") -} - -func TestBlockSignatureVerifierByIdentifier(t *testing.T) { - consenters := []*common.Consenter{ - { - Id: 1, - Host: "host1", - Port: 8001, - MspId: "msp1", - Identity: []byte("identity1"), - }, - { - Id: 2, - Host: "host2", - Port: 8002, - MspId: "msp2", - Identity: []byte("identity2"), - }, - { - Id: 3, - Host: "host3", - Port: 8003, - MspId: "msp3", - Identity: []byte("identity3"), - }, - } - - policies := mocks.Policy{} - - verify := cluster.BlockSignatureVerifier(true, consenters, &policies) - - header := &common.BlockHeader{} - md := &common.BlockMetadata{ - Metadata: [][]byte{ - protoutil.MarshalOrPanic(&common.Metadata{Signatures: []*common.MetadataSignature{ - { - Signature: []byte{}, - IdentifierHeader: protoutil.MarshalOrPanic(&common.IdentifierHeader{Identifier: 1}), - }, - { - Signature: []byte{}, - IdentifierHeader: protoutil.MarshalOrPanic(&common.IdentifierHeader{Identifier: 3}), - }, - }}), - }, - } - - err := verify(header, md) - require.NoError(t, err) - signatureSet := policies.EvaluateSignedDataArgsForCall(0) - require.Len(t, signatureSet, 2) - require.Equal(t, protoutil.MarshalOrPanic(&msp.SerializedIdentity{Mspid: "msp1", IdBytes: []byte("identity1")}), signatureSet[0].Identity) - require.Equal(t, protoutil.MarshalOrPanic(&msp.SerializedIdentity{Mspid: "msp3", IdBytes: []byte("identity3")}), signatureSet[1].Identity) -} - -func TestBlockSignatureVerifierByCreator(t *testing.T) { - consenters := []*common.Consenter{ - { - Id: 1, - Host: "host1", - Port: 8001, - MspId: "msp1", - Identity: []byte("identity1"), - }, - { - Id: 2, - Host: "host2", - Port: 8002, - MspId: "msp2", - Identity: []byte("identity2"), - }, - { - Id: 3, - Host: "host3", - Port: 8003, - MspId: "msp3", - Identity: []byte("identity3"), - }, - } - - policies := mocks.Policy{} - - verify := cluster.BlockSignatureVerifier(true, consenters, &policies) - - header := &common.BlockHeader{} - md := &common.BlockMetadata{ - Metadata: [][]byte{ - protoutil.MarshalOrPanic(&common.Metadata{Signatures: []*common.MetadataSignature{ - { - Signature: []byte{}, - SignatureHeader: protoutil.MarshalOrPanic(&common.SignatureHeader{Creator: []byte("creator1")}), - }, - }}), - }, - } - - err := verify(header, md) - require.NoError(t, err) - signatureSet := policies.EvaluateSignedDataArgsForCall(0) - require.Len(t, signatureSet, 1) - require.Equal(t, []byte("creator1"), signatureSet[0].Identity) -} - func sampleConfigBlock() *common.Block { return &common.Block{ Header: &common.BlockHeader{ diff --git a/protoutil/blockutils.go b/protoutil/blockutils.go index 4217015d643..6afd77deba5 100644 --- a/protoutil/blockutils.go +++ b/protoutil/blockutils.go @@ -10,10 +10,13 @@ import ( "bytes" "crypto/sha256" "encoding/asn1" + "fmt" "math/big" "github.com/golang/protobuf/proto" cb "github.com/hyperledger/fabric-protos-go/common" + "github.com/hyperledger/fabric-protos-go/msp" + "github.com/hyperledger/fabric/common/util" "github.com/pkg/errors" ) @@ -218,3 +221,78 @@ func InitBlockMetadata(block *cb.Block) { } } } + +type BlockVerifierFunc func(header *cb.BlockHeader, metadata *cb.BlockMetadata) error + +//go:generate counterfeiter -o mocks/policy.go --fake-name Policy . policy +type policy interface { // copied from common.policies to avoid circular import. + // EvaluateSignedData takes a set of SignedData and evaluates whether + // 1) the signatures are valid over the related message + // 2) the signing identities satisfy the policy + EvaluateSignedData(signatureSet []*SignedData) error +} + +func BlockSignatureVerifier(bftEnabled bool, consenters []*cb.Consenter, policy policy) BlockVerifierFunc { + return func(header *cb.BlockHeader, metadata *cb.BlockMetadata) error { + if len(metadata.Metadata) < int(cb.BlockMetadataIndex_SIGNATURES)+1 { + return errors.Errorf("no signatures in block metadata") + } + + md := &cb.Metadata{} + if err := proto.Unmarshal(metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES], md); err != nil { + return errors.Wrapf(err, "error unmarshalling signatures from metadata: %v", err) + } + + var signatureSet []*SignedData + for _, metadataSignature := range md.Signatures { + var signerIdentity []byte + var signedPayload []byte + // if the SignatureHeader is empty and the IdentifierHeader is present, then the consenter expects us to fetch its identity by its numeric identifier + if bftEnabled && len(metadataSignature.GetSignatureHeader()) == 0 && len(metadataSignature.GetIdentifierHeader()) > 0 { + identifierHeader, err := UnmarshalIdentifierHeader(metadataSignature.IdentifierHeader) + if err != nil { + return fmt.Errorf("failed unmarshalling identifier header for block %d: %v", header.Number, err) + } + identifier := identifierHeader.GetIdentifier() + signerIdentity = searchConsenterIdentityByID(consenters, identifier) + if len(signerIdentity) == 0 { + // The identifier is not within the consenter set + continue + } + signedPayload = util.ConcatenateBytes(md.Value, metadataSignature.IdentifierHeader, BlockHeaderBytes(header)) + } else { + signatureHeader, err := UnmarshalSignatureHeader(metadataSignature.GetSignatureHeader()) + if err != nil { + return fmt.Errorf("failed unmarshalling signature header for block %d: %v", header.Number, err) + } + + signedPayload = util.ConcatenateBytes(md.Value, metadataSignature.SignatureHeader, BlockHeaderBytes(header)) + + signerIdentity = signatureHeader.Creator + } + + signatureSet = append( + signatureSet, + &SignedData{ + Identity: signerIdentity, + Data: signedPayload, + Signature: metadataSignature.Signature, + }, + ) + } + + return policy.EvaluateSignedData(signatureSet) + } +} + +func searchConsenterIdentityByID(consenters []*cb.Consenter, identifier uint32) []byte { + for _, consenter := range consenters { + if consenter.Id == identifier { + return MarshalOrPanic(&msp.SerializedIdentity{ + Mspid: consenter.MspId, + IdBytes: consenter.Identity, + }) + } + } + return nil +} diff --git a/protoutil/blockutils_test.go b/protoutil/blockutils_test.go index a57f1aed80c..b2159da9f55 100644 --- a/protoutil/blockutils_test.go +++ b/protoutil/blockutils_test.go @@ -14,8 +14,10 @@ import ( "github.com/golang/protobuf/proto" cb "github.com/hyperledger/fabric-protos-go/common" + "github.com/hyperledger/fabric-protos-go/msp" configtxtest "github.com/hyperledger/fabric/common/configtx/test" "github.com/hyperledger/fabric/protoutil" + "github.com/hyperledger/fabric/protoutil/mocks" "github.com/stretchr/testify/require" ) @@ -374,3 +376,116 @@ func TestGetLastConfigIndexFromBlock(t *testing.T) { }, "Expected panic with malformed last config metadata") }) } + +func TestBlockSignatureVerifierEmptyMetadata(t *testing.T) { + policies := mocks.Policy{} + + verify := protoutil.BlockSignatureVerifier(true, nil, &policies) + + header := &cb.BlockHeader{} + md := &cb.BlockMetadata{} + + err := verify(header, md) + require.ErrorContains(t, err, "no signatures in block metadata") +} + +func TestBlockSignatureVerifierByIdentifier(t *testing.T) { + consenters := []*cb.Consenter{ + { + Id: 1, + Host: "host1", + Port: 8001, + MspId: "msp1", + Identity: []byte("identity1"), + }, + { + Id: 2, + Host: "host2", + Port: 8002, + MspId: "msp2", + Identity: []byte("identity2"), + }, + { + Id: 3, + Host: "host3", + Port: 8003, + MspId: "msp3", + Identity: []byte("identity3"), + }, + } + + policies := mocks.Policy{} + + verify := protoutil.BlockSignatureVerifier(true, consenters, &policies) + + header := &cb.BlockHeader{} + md := &cb.BlockMetadata{ + Metadata: [][]byte{ + protoutil.MarshalOrPanic(&cb.Metadata{Signatures: []*cb.MetadataSignature{ + { + Signature: []byte{}, + IdentifierHeader: protoutil.MarshalOrPanic(&cb.IdentifierHeader{Identifier: 1}), + }, + { + Signature: []byte{}, + IdentifierHeader: protoutil.MarshalOrPanic(&cb.IdentifierHeader{Identifier: 3}), + }, + }}), + }, + } + + err := verify(header, md) + require.NoError(t, err) + signatureSet := policies.EvaluateSignedDataArgsForCall(0) + require.Len(t, signatureSet, 2) + require.Equal(t, protoutil.MarshalOrPanic(&msp.SerializedIdentity{Mspid: "msp1", IdBytes: []byte("identity1")}), signatureSet[0].Identity) + require.Equal(t, protoutil.MarshalOrPanic(&msp.SerializedIdentity{Mspid: "msp3", IdBytes: []byte("identity3")}), signatureSet[1].Identity) +} + +func TestBlockSignatureVerifierByCreator(t *testing.T) { + consenters := []*cb.Consenter{ + { + Id: 1, + Host: "host1", + Port: 8001, + MspId: "msp1", + Identity: []byte("identity1"), + }, + { + Id: 2, + Host: "host2", + Port: 8002, + MspId: "msp2", + Identity: []byte("identity2"), + }, + { + Id: 3, + Host: "host3", + Port: 8003, + MspId: "msp3", + Identity: []byte("identity3"), + }, + } + + policies := mocks.Policy{} + + verify := protoutil.BlockSignatureVerifier(true, consenters, &policies) + + header := &cb.BlockHeader{} + md := &cb.BlockMetadata{ + Metadata: [][]byte{ + protoutil.MarshalOrPanic(&cb.Metadata{Signatures: []*cb.MetadataSignature{ + { + Signature: []byte{}, + SignatureHeader: protoutil.MarshalOrPanic(&cb.SignatureHeader{Creator: []byte("creator1")}), + }, + }}), + }, + } + + err := verify(header, md) + require.NoError(t, err) + signatureSet := policies.EvaluateSignedDataArgsForCall(0) + require.Len(t, signatureSet, 1) + require.Equal(t, []byte("creator1"), signatureSet[0].Identity) +} diff --git a/protoutil/mocks/policy.go b/protoutil/mocks/policy.go new file mode 100644 index 00000000000..674fa0023d1 --- /dev/null +++ b/protoutil/mocks/policy.go @@ -0,0 +1,114 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package mocks + +import ( + "sync" + + "github.com/hyperledger/fabric/protoutil" +) + +type Policy struct { + EvaluateSignedDataStub func([]*protoutil.SignedData) error + evaluateSignedDataMutex sync.RWMutex + evaluateSignedDataArgsForCall []struct { + arg1 []*protoutil.SignedData + } + evaluateSignedDataReturns struct { + result1 error + } + evaluateSignedDataReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *Policy) EvaluateSignedData(arg1 []*protoutil.SignedData) error { + var arg1Copy []*protoutil.SignedData + if arg1 != nil { + arg1Copy = make([]*protoutil.SignedData, len(arg1)) + copy(arg1Copy, arg1) + } + fake.evaluateSignedDataMutex.Lock() + ret, specificReturn := fake.evaluateSignedDataReturnsOnCall[len(fake.evaluateSignedDataArgsForCall)] + fake.evaluateSignedDataArgsForCall = append(fake.evaluateSignedDataArgsForCall, struct { + arg1 []*protoutil.SignedData + }{arg1Copy}) + stub := fake.EvaluateSignedDataStub + fakeReturns := fake.evaluateSignedDataReturns + fake.recordInvocation("EvaluateSignedData", []interface{}{arg1Copy}) + fake.evaluateSignedDataMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *Policy) EvaluateSignedDataCallCount() int { + fake.evaluateSignedDataMutex.RLock() + defer fake.evaluateSignedDataMutex.RUnlock() + return len(fake.evaluateSignedDataArgsForCall) +} + +func (fake *Policy) EvaluateSignedDataCalls(stub func([]*protoutil.SignedData) error) { + fake.evaluateSignedDataMutex.Lock() + defer fake.evaluateSignedDataMutex.Unlock() + fake.EvaluateSignedDataStub = stub +} + +func (fake *Policy) EvaluateSignedDataArgsForCall(i int) []*protoutil.SignedData { + fake.evaluateSignedDataMutex.RLock() + defer fake.evaluateSignedDataMutex.RUnlock() + argsForCall := fake.evaluateSignedDataArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *Policy) EvaluateSignedDataReturns(result1 error) { + fake.evaluateSignedDataMutex.Lock() + defer fake.evaluateSignedDataMutex.Unlock() + fake.EvaluateSignedDataStub = nil + fake.evaluateSignedDataReturns = struct { + result1 error + }{result1} +} + +func (fake *Policy) EvaluateSignedDataReturnsOnCall(i int, result1 error) { + fake.evaluateSignedDataMutex.Lock() + defer fake.evaluateSignedDataMutex.Unlock() + fake.EvaluateSignedDataStub = nil + if fake.evaluateSignedDataReturnsOnCall == nil { + fake.evaluateSignedDataReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.evaluateSignedDataReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *Policy) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.evaluateSignedDataMutex.RLock() + defer fake.evaluateSignedDataMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *Policy) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +}