github.com/yimialmonte/fabric@v2.1.1+incompatible/discovery/client/signer.go (about) 1 /* 2 Copyright IBM Corp All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package discovery 8 9 import ( 10 "encoding/hex" 11 "sync" 12 13 "github.com/hyperledger/fabric/common/util" 14 ) 15 16 // MemoizeSigner signs messages with the same signature 17 // if the message was signed recently 18 type MemoizeSigner struct { 19 maxEntries uint 20 sync.RWMutex 21 memory map[string][]byte 22 sign Signer 23 } 24 25 // NewMemoizeSigner creates a new MemoizeSigner that signs 26 // message with the given sign function 27 func NewMemoizeSigner(signFunc Signer, maxEntries uint) *MemoizeSigner { 28 return &MemoizeSigner{ 29 maxEntries: maxEntries, 30 memory: make(map[string][]byte), 31 sign: signFunc, 32 } 33 } 34 35 // Signer signs a message and returns the signature and nil, 36 // or nil and error on failure 37 func (ms *MemoizeSigner) Sign(msg []byte) ([]byte, error) { 38 sig, isInMemory := ms.lookup(msg) 39 if isInMemory { 40 return sig, nil 41 } 42 sig, err := ms.sign(msg) 43 if err != nil { 44 return nil, err 45 } 46 ms.memorize(msg, sig) 47 return sig, nil 48 } 49 50 // lookup looks up the given message in memory and returns 51 // the signature, if the message is in memory 52 func (ms *MemoizeSigner) lookup(msg []byte) ([]byte, bool) { 53 ms.RLock() 54 defer ms.RUnlock() 55 sig, exists := ms.memory[msgDigest(msg)] 56 return sig, exists 57 } 58 59 func (ms *MemoizeSigner) memorize(msg, signature []byte) { 60 if ms.maxEntries == 0 { 61 return 62 } 63 ms.RLock() 64 shouldShrink := len(ms.memory) >= (int)(ms.maxEntries) 65 ms.RUnlock() 66 67 if shouldShrink { 68 ms.shrinkMemory() 69 } 70 ms.Lock() 71 defer ms.Unlock() 72 ms.memory[msgDigest(msg)] = signature 73 74 } 75 76 // shrinkMemory evicts random messages from memory 77 // until its size is smaller than maxEntries 78 func (ms *MemoizeSigner) shrinkMemory() { 79 ms.Lock() 80 defer ms.Unlock() 81 for len(ms.memory) > (int)(ms.maxEntries) { 82 ms.evictFromMemory() 83 } 84 } 85 86 // evictFromMemory evicts a random message from memory 87 func (ms *MemoizeSigner) evictFromMemory() { 88 for dig := range ms.memory { 89 delete(ms.memory, dig) 90 return 91 } 92 } 93 94 // msgDigest returns a digest of a given message 95 func msgDigest(msg []byte) string { 96 return hex.EncodeToString(util.ComputeSHA256(msg)) 97 }