97 lines
2.1 KiB
Go
97 lines
2.1 KiB
Go
/*
|
|
Copyright IBM Corp All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package discovery
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"sync"
|
|
|
|
"github.com/hyperledger/fabric/common/util"
|
|
)
|
|
|
|
// MemoizeSigner signs messages with the same signature
|
|
// if the message was signed recently
|
|
type MemoizeSigner struct {
|
|
maxEntries uint
|
|
sync.RWMutex
|
|
memory map[string][]byte
|
|
sign Signer
|
|
}
|
|
|
|
// NewMemoizeSigner creates a new MemoizeSigner that signs
|
|
// message with the given sign function
|
|
func NewMemoizeSigner(signFunc Signer, maxEntries uint) *MemoizeSigner {
|
|
return &MemoizeSigner{
|
|
maxEntries: maxEntries,
|
|
memory: make(map[string][]byte),
|
|
sign: signFunc,
|
|
}
|
|
}
|
|
|
|
// Signer signs a message and returns the signature and nil,
|
|
// or nil and error on failure
|
|
func (ms *MemoizeSigner) Sign(msg []byte) ([]byte, error) {
|
|
sig, isInMemory := ms.lookup(msg)
|
|
if isInMemory {
|
|
return sig, nil
|
|
}
|
|
sig, err := ms.sign(msg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ms.memorize(msg, sig)
|
|
return sig, nil
|
|
}
|
|
|
|
// lookup looks up the given message in memory and returns
|
|
// the signature, if the message is in memory
|
|
func (ms *MemoizeSigner) lookup(msg []byte) ([]byte, bool) {
|
|
ms.RLock()
|
|
defer ms.RUnlock()
|
|
sig, exists := ms.memory[msgDigest(msg)]
|
|
return sig, exists
|
|
}
|
|
|
|
func (ms *MemoizeSigner) memorize(msg, signature []byte) {
|
|
if ms.maxEntries == 0 {
|
|
return
|
|
}
|
|
ms.RLock()
|
|
shouldShrink := len(ms.memory) >= (int)(ms.maxEntries)
|
|
ms.RUnlock()
|
|
|
|
if shouldShrink {
|
|
ms.shrinkMemory()
|
|
}
|
|
ms.Lock()
|
|
defer ms.Unlock()
|
|
ms.memory[msgDigest(msg)] = signature
|
|
}
|
|
|
|
// shrinkMemory evicts random messages from memory
|
|
// until its size is smaller than maxEntries
|
|
func (ms *MemoizeSigner) shrinkMemory() {
|
|
ms.Lock()
|
|
defer ms.Unlock()
|
|
for len(ms.memory) > (int)(ms.maxEntries) {
|
|
ms.evictFromMemory()
|
|
}
|
|
}
|
|
|
|
// evictFromMemory evicts a random message from memory
|
|
func (ms *MemoizeSigner) evictFromMemory() {
|
|
for dig := range ms.memory {
|
|
delete(ms.memory, dig)
|
|
return
|
|
}
|
|
}
|
|
|
|
// msgDigest returns a digest of a given message
|
|
func msgDigest(msg []byte) string {
|
|
return hex.EncodeToString(util.ComputeSHA256(msg))
|
|
}
|