From 2b1c241fa83987f53251b3c93b7db50a2bd2c4df Mon Sep 17 00:00:00 2001 From: Alexandros Filios Date: Tue, 14 Jan 2025 06:56:37 +0100 Subject: [PATCH 1/4] Performance improvement: Second-chance cache now has a buffer before evicting entries instead of evicting one every time once we exceed its size. Signed-off-by: Alexandros Filios --- .../view/services/cache/secondcache/second_chance.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/platform/view/services/cache/secondcache/second_chance.go b/platform/view/services/cache/secondcache/second_chance.go index 3adec809d..bb0d4e913 100644 --- a/platform/view/services/cache/secondcache/second_chance.go +++ b/platform/view/services/cache/secondcache/second_chance.go @@ -24,6 +24,8 @@ type typedSecondChanceCache[T any] struct { // holds a list of cached items. items []*cacheItem[T] + buffer int + // indicates the next candidate of a victim in the items list position int @@ -47,8 +49,9 @@ func New(cacheSize int) *secondChanceCache { func NewTyped[T any](cacheSize int) *typedSecondChanceCache[T] { var cache typedSecondChanceCache[T] cache.position = 0 + cache.buffer = max(cacheSize/3, 1) // One third of the entries will be evicted when the cache is full cache.items = make([]*cacheItem[T], cacheSize) - cache.table = make(map[string]*cacheItem[T]) + cache.table = make(map[string]*cacheItem[T], cacheSize) return &cache } @@ -126,7 +129,7 @@ func (cache *typedSecondChanceCache[T]) add(key string, value T) { } // starts victim scan since cache is full - for { + for evicted := 0; evicted < cache.buffer; { // checks whether this item is recently accessed or not victim := cache.items[cache.position] if atomic.LoadInt32(&victim.referenced) == 0 { @@ -135,7 +138,8 @@ func (cache *typedSecondChanceCache[T]) add(key string, value T) { cache.table[key] = &item cache.items[cache.position] = &item cache.position = (cache.position + 1) % size - return + evicted++ + continue } // referenced bit is set to false so that this item will be Get purged From 2e4881b57c434a7bf14b7b044de7c5fa3978ccb4 Mon Sep 17 00:00:00 2001 From: Alexandros Filios Date: Wed, 15 Jan 2025 05:21:34 +0100 Subject: [PATCH 2/4] Performance improvement: Batch query for IsMe Signed-off-by: Alexandros Filios --- platform/common/driver/sigservice.go | 3 + platform/common/services/sig/service.go | 41 ++++++-- platform/view/driver/mock/sig_service.go | 124 ++++++++++++++++++----- platform/view/services/kvs/kvs.go | 61 +++++++---- platform/view/sig.go | 5 + 5 files changed, 178 insertions(+), 56 deletions(-) diff --git a/platform/common/driver/sigservice.go b/platform/common/driver/sigservice.go index 0b958f590..0f8b5790b 100644 --- a/platform/common/driver/sigservice.go +++ b/platform/common/driver/sigservice.go @@ -54,6 +54,9 @@ type SigService interface { // IsMe returns true if a signer was ever registered for the passed identity IsMe(identity view.Identity) bool + + // AreMe returns the hashes of the passed identities that have a signer registered before + AreMe(identities ...view.Identity) []string } // AuditRegistry models a repository of identities' audit information diff --git a/platform/common/services/sig/service.go b/platform/common/services/sig/service.go index 685d55e7a..d6bce3731 100644 --- a/platform/common/services/sig/service.go +++ b/platform/common/services/sig/service.go @@ -13,6 +13,7 @@ import ( "sync" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" "github.com/hyperledger-labs/fabric-smart-client/platform/view/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" @@ -24,6 +25,7 @@ var logger = logging.MustGetLogger("common-sdk.sig") type KVS interface { Exists(id string) bool + GetExisting(ids ...string) []string Put(id string, state interface{}) error Get(id string, state interface{}) error } @@ -180,25 +182,42 @@ func (o *Service) GetAuditInfo(identity view.Identity) ([]byte, error) { } func (o *Service) IsMe(identity view.Identity) bool { - idHash := identity.UniqueID() + return len(o.AreMe(identity)) > 0 +} + +func (o *Service) AreMe(identities ...view.Identity) []string { + idHashes := make([]string, len(identities)) + for i, id := range identities { + idHashes[i] = id.UniqueID() + } + result := collections.NewSet[string]() + notFound := make([]string, 0) // check local cache o.mutex.RLock() - _, ok := o.signers[idHash] + for _, idHash := range idHashes { + if _, ok := o.signers[idHash]; ok { + result.Add(idHash) + } else { + notFound = append(notFound, idHash) + } + } o.mutex.RUnlock() - if ok { - return true + if len(notFound) == 0 || o.kvs == nil { + return result.ToSlice() } // check kvs - if o.kvs != nil { - k, err := kvs.CreateCompositeKey("sigService", []string{"signer", idHash}) + keys := make([]string, len(notFound)) + for i, idHash := range notFound { + key, err := kvs.CreateCompositeKey("sigService", []string{"signer", idHash}) if err != nil { - return false - } - if o.kvs.Exists(k) { - return true + logger.Errorf("failed creating composite key: %v", err) } + keys[i] = key } - return false + + result.Add(o.kvs.GetExisting(keys...)...) + + return result.ToSlice() } func (o *Service) Info(id view.Identity) string { diff --git a/platform/view/driver/mock/sig_service.go b/platform/view/driver/mock/sig_service.go index bd9f49139..3beafdf1e 100644 --- a/platform/view/driver/mock/sig_service.go +++ b/platform/view/driver/mock/sig_service.go @@ -5,15 +5,26 @@ import ( "sync" drivera "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/identity" "github.com/hyperledger-labs/fabric-smart-client/platform/view/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" ) type SigService struct { - GetSignerStub func(view.Identity) (drivera.Signer, error) + AreMeStub func(...identity.Identity) []string + areMeMutex sync.RWMutex + areMeArgsForCall []struct { + arg1 []identity.Identity + } + areMeReturns struct { + result1 []string + } + areMeReturnsOnCall map[int]struct { + result1 []string + } + GetSignerStub func(identity.Identity) (drivera.Signer, error) getSignerMutex sync.RWMutex getSignerArgsForCall []struct { - arg1 view.Identity + arg1 identity.Identity } getSignerReturns struct { result1 drivera.Signer @@ -23,10 +34,10 @@ type SigService struct { result1 drivera.Signer result2 error } - GetSigningIdentityStub func(view.Identity) (drivera.SigningIdentity, error) + GetSigningIdentityStub func(identity.Identity) (drivera.SigningIdentity, error) getSigningIdentityMutex sync.RWMutex getSigningIdentityArgsForCall []struct { - arg1 view.Identity + arg1 identity.Identity } getSigningIdentityReturns struct { result1 drivera.SigningIdentity @@ -36,10 +47,10 @@ type SigService struct { result1 drivera.SigningIdentity result2 error } - GetVerifierStub func(view.Identity) (drivera.Verifier, error) + GetVerifierStub func(identity.Identity) (drivera.Verifier, error) getVerifierMutex sync.RWMutex getVerifierArgsForCall []struct { - arg1 view.Identity + arg1 identity.Identity } getVerifierReturns struct { result1 drivera.Verifier @@ -49,10 +60,10 @@ type SigService struct { result1 drivera.Verifier result2 error } - IsMeStub func(view.Identity) bool + IsMeStub func(identity.Identity) bool isMeMutex sync.RWMutex isMeArgsForCall []struct { - arg1 view.Identity + arg1 identity.Identity } isMeReturns struct { result1 bool @@ -64,11 +75,72 @@ type SigService struct { invocationsMutex sync.RWMutex } -func (fake *SigService) GetSigner(arg1 view.Identity) (drivera.Signer, error) { +func (fake *SigService) AreMe(arg1 ...identity.Identity) []string { + fake.areMeMutex.Lock() + ret, specificReturn := fake.areMeReturnsOnCall[len(fake.areMeArgsForCall)] + fake.areMeArgsForCall = append(fake.areMeArgsForCall, struct { + arg1 []identity.Identity + }{arg1}) + stub := fake.AreMeStub + fakeReturns := fake.areMeReturns + fake.recordInvocation("AreMe", []interface{}{arg1}) + fake.areMeMutex.Unlock() + if stub != nil { + return stub(arg1...) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *SigService) AreMeCallCount() int { + fake.areMeMutex.RLock() + defer fake.areMeMutex.RUnlock() + return len(fake.areMeArgsForCall) +} + +func (fake *SigService) AreMeCalls(stub func(...identity.Identity) []string) { + fake.areMeMutex.Lock() + defer fake.areMeMutex.Unlock() + fake.AreMeStub = stub +} + +func (fake *SigService) AreMeArgsForCall(i int) []identity.Identity { + fake.areMeMutex.RLock() + defer fake.areMeMutex.RUnlock() + argsForCall := fake.areMeArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *SigService) AreMeReturns(result1 []string) { + fake.areMeMutex.Lock() + defer fake.areMeMutex.Unlock() + fake.AreMeStub = nil + fake.areMeReturns = struct { + result1 []string + }{result1} +} + +func (fake *SigService) AreMeReturnsOnCall(i int, result1 []string) { + fake.areMeMutex.Lock() + defer fake.areMeMutex.Unlock() + fake.AreMeStub = nil + if fake.areMeReturnsOnCall == nil { + fake.areMeReturnsOnCall = make(map[int]struct { + result1 []string + }) + } + fake.areMeReturnsOnCall[i] = struct { + result1 []string + }{result1} +} + +func (fake *SigService) GetSigner(arg1 identity.Identity) (drivera.Signer, error) { fake.getSignerMutex.Lock() ret, specificReturn := fake.getSignerReturnsOnCall[len(fake.getSignerArgsForCall)] fake.getSignerArgsForCall = append(fake.getSignerArgsForCall, struct { - arg1 view.Identity + arg1 identity.Identity }{arg1}) stub := fake.GetSignerStub fakeReturns := fake.getSignerReturns @@ -89,13 +161,13 @@ func (fake *SigService) GetSignerCallCount() int { return len(fake.getSignerArgsForCall) } -func (fake *SigService) GetSignerCalls(stub func(view.Identity) (drivera.Signer, error)) { +func (fake *SigService) GetSignerCalls(stub func(identity.Identity) (drivera.Signer, error)) { fake.getSignerMutex.Lock() defer fake.getSignerMutex.Unlock() fake.GetSignerStub = stub } -func (fake *SigService) GetSignerArgsForCall(i int) view.Identity { +func (fake *SigService) GetSignerArgsForCall(i int) identity.Identity { fake.getSignerMutex.RLock() defer fake.getSignerMutex.RUnlock() argsForCall := fake.getSignerArgsForCall[i] @@ -128,11 +200,11 @@ func (fake *SigService) GetSignerReturnsOnCall(i int, result1 drivera.Signer, re }{result1, result2} } -func (fake *SigService) GetSigningIdentity(arg1 view.Identity) (drivera.SigningIdentity, error) { +func (fake *SigService) GetSigningIdentity(arg1 identity.Identity) (drivera.SigningIdentity, error) { fake.getSigningIdentityMutex.Lock() ret, specificReturn := fake.getSigningIdentityReturnsOnCall[len(fake.getSigningIdentityArgsForCall)] fake.getSigningIdentityArgsForCall = append(fake.getSigningIdentityArgsForCall, struct { - arg1 view.Identity + arg1 identity.Identity }{arg1}) stub := fake.GetSigningIdentityStub fakeReturns := fake.getSigningIdentityReturns @@ -153,13 +225,13 @@ func (fake *SigService) GetSigningIdentityCallCount() int { return len(fake.getSigningIdentityArgsForCall) } -func (fake *SigService) GetSigningIdentityCalls(stub func(view.Identity) (drivera.SigningIdentity, error)) { +func (fake *SigService) GetSigningIdentityCalls(stub func(identity.Identity) (drivera.SigningIdentity, error)) { fake.getSigningIdentityMutex.Lock() defer fake.getSigningIdentityMutex.Unlock() fake.GetSigningIdentityStub = stub } -func (fake *SigService) GetSigningIdentityArgsForCall(i int) view.Identity { +func (fake *SigService) GetSigningIdentityArgsForCall(i int) identity.Identity { fake.getSigningIdentityMutex.RLock() defer fake.getSigningIdentityMutex.RUnlock() argsForCall := fake.getSigningIdentityArgsForCall[i] @@ -192,11 +264,11 @@ func (fake *SigService) GetSigningIdentityReturnsOnCall(i int, result1 drivera.S }{result1, result2} } -func (fake *SigService) GetVerifier(arg1 view.Identity) (drivera.Verifier, error) { +func (fake *SigService) GetVerifier(arg1 identity.Identity) (drivera.Verifier, error) { fake.getVerifierMutex.Lock() ret, specificReturn := fake.getVerifierReturnsOnCall[len(fake.getVerifierArgsForCall)] fake.getVerifierArgsForCall = append(fake.getVerifierArgsForCall, struct { - arg1 view.Identity + arg1 identity.Identity }{arg1}) stub := fake.GetVerifierStub fakeReturns := fake.getVerifierReturns @@ -217,13 +289,13 @@ func (fake *SigService) GetVerifierCallCount() int { return len(fake.getVerifierArgsForCall) } -func (fake *SigService) GetVerifierCalls(stub func(view.Identity) (drivera.Verifier, error)) { +func (fake *SigService) GetVerifierCalls(stub func(identity.Identity) (drivera.Verifier, error)) { fake.getVerifierMutex.Lock() defer fake.getVerifierMutex.Unlock() fake.GetVerifierStub = stub } -func (fake *SigService) GetVerifierArgsForCall(i int) view.Identity { +func (fake *SigService) GetVerifierArgsForCall(i int) identity.Identity { fake.getVerifierMutex.RLock() defer fake.getVerifierMutex.RUnlock() argsForCall := fake.getVerifierArgsForCall[i] @@ -256,11 +328,11 @@ func (fake *SigService) GetVerifierReturnsOnCall(i int, result1 drivera.Verifier }{result1, result2} } -func (fake *SigService) IsMe(arg1 view.Identity) bool { +func (fake *SigService) IsMe(arg1 identity.Identity) bool { fake.isMeMutex.Lock() ret, specificReturn := fake.isMeReturnsOnCall[len(fake.isMeArgsForCall)] fake.isMeArgsForCall = append(fake.isMeArgsForCall, struct { - arg1 view.Identity + arg1 identity.Identity }{arg1}) stub := fake.IsMeStub fakeReturns := fake.isMeReturns @@ -281,13 +353,13 @@ func (fake *SigService) IsMeCallCount() int { return len(fake.isMeArgsForCall) } -func (fake *SigService) IsMeCalls(stub func(view.Identity) bool) { +func (fake *SigService) IsMeCalls(stub func(identity.Identity) bool) { fake.isMeMutex.Lock() defer fake.isMeMutex.Unlock() fake.IsMeStub = stub } -func (fake *SigService) IsMeArgsForCall(i int) view.Identity { +func (fake *SigService) IsMeArgsForCall(i int) identity.Identity { fake.isMeMutex.RLock() defer fake.isMeMutex.RUnlock() argsForCall := fake.isMeArgsForCall[i] @@ -320,6 +392,8 @@ func (fake *SigService) IsMeReturnsOnCall(i int, result1 bool) { func (fake *SigService) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() + fake.areMeMutex.RLock() + defer fake.areMeMutex.RUnlock() fake.getSignerMutex.RLock() defer fake.getSignerMutex.RUnlock() fake.getSigningIdentityMutex.RLock() diff --git a/platform/view/services/kvs/kvs.go b/platform/view/services/kvs/kvs.go index fffc1da49..f70ad091f 100644 --- a/platform/view/services/kvs/kvs.go +++ b/platform/view/services/kvs/kvs.go @@ -84,13 +84,21 @@ func NewWithConfig(dbDriver driver.Driver, namespace string, cp ConfigProvider) }, nil } -func (o *KVS) Exists(id string) bool { +func (o *KVS) GetExisting(ids ...string) []string { + result := make([]string, 0) + notFound := make([]string, 0) // is in cache? o.putMutex.RLock() - v, ok := o.cache.Get(id) - if ok { - o.putMutex.RUnlock() - return v != nil && len(v.([]byte)) != 0 + for _, id := range ids { + if v, ok := o.cache.Get(id); !ok { + notFound = append(notFound, id) + } else if v != nil && len(v.([]byte)) > 0 { + result = append(result, id) + } + } + if len(notFound) == 0 { + defer o.putMutex.RUnlock() + return result } o.putMutex.RUnlock() @@ -99,28 +107,41 @@ func (o *KVS) Exists(id string) bool { defer o.putMutex.Unlock() // is in cache, first? - v, ok = o.cache.Get(id) - if ok { - if logger.IsEnabledFor(zapcore.DebugLevel) { - logger.Debugf("hit the cache, len state [%d]", len(v.([]byte))) + ids = notFound + notFound = make([]string, 0) + for _, id := range ids { + if v, ok := o.cache.Get(id); !ok { + notFound = append(notFound, id) + } else if v != nil && len(v.([]byte)) > 0 { + result = append(result, id) } - return v != nil && len(v.([]byte)) != 0 } + if len(notFound) == 0 { + return result + } + + ids = notFound // get from store and store in cache - raw, err := o.store.GetState(o.namespace, id) + it, err := o.store.GetStateSetIterator(o.namespace, ids...) if err != nil { - if logger.IsEnabledFor(zapcore.DebugLevel) { - logger.Debugf("failed getting state [%s,%s]", o.namespace, id) - } - o.cache.Delete(id) - return false + return result } - o.cache.Add(id, raw) - if logger.IsEnabledFor(zapcore.DebugLevel) { - logger.Debugf("state [%s,%s] exists [%v]", o.namespace, id, len(raw) != 0) + for v, err := it.Next(); v != nil || err != nil; v, err = it.Next() { + if err != nil { + o.cache.Delete(v.Key) + } else if len(v.Raw) > 0 { + o.cache.Add(v.Key, v.Raw) + result = append(result, v.Key) + } else { + o.cache.Add(v.Key, v.Raw) + } } - return len(raw) != 0 + return result +} + +func (o *KVS) Exists(id string) bool { + return len(o.GetExisting(id)) > 0 } func (o *KVS) Put(id string, state interface{}) error { diff --git a/platform/view/sig.go b/platform/view/sig.go index 7192f9c11..feed13287 100644 --- a/platform/view/sig.go +++ b/platform/view/sig.go @@ -89,6 +89,11 @@ func (s *SigService) IsMe(identity view.Identity) bool { return s.sigService.IsMe(identity) } +// AreMe returns the hashes of the passed identities that have a signer registered before +func (s *SigService) AreMe(identities ...view.Identity) []string { + return s.sigService.AreMe(identities...) +} + // RegisterVerifier binds the passed identity to the passed verifier func (s *SigService) RegisterVerifier(identity view.Identity, verifier Verifier) error { return s.sigRegistry.RegisterVerifier(identity, verifier) From b4b0e2a174da8487c434bff828f47642820a5b5e Mon Sep 17 00:00:00 2001 From: Alexandros Filios Date: Wed, 15 Jan 2025 07:45:18 +0100 Subject: [PATCH 3/4] Performance improvement: Increase MSP cache size Signed-off-by: Alexandros Filios --- integration/nwo/fabric/topology/core_template.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/nwo/fabric/topology/core_template.go b/integration/nwo/fabric/topology/core_template.go index e4a5c1c9e..ac869b5d0 100644 --- a/integration/nwo/fabric/topology/core_template.go +++ b/integration/nwo/fabric/topology/core_template.go @@ -249,7 +249,7 @@ fabric: {{ FabricName }}: default: {{ DefaultNetwork }} driver: {{ Driver }} - mspCacheSize: 3 + mspCacheSize: 500 defaultMSP: {{ Peer.DefaultIdentity }} msps: {{ range Peer.Identities }} - id: {{ .ID }} From b7e89145d66223d2336ad958d015b88b47aaf2ae Mon Sep 17 00:00:00 2001 From: Alexandros Filios Date: Wed, 15 Jan 2025 14:25:57 +0100 Subject: [PATCH 4/4] Moved KVS functionality behind interfaces and grouped them based on domains for decoupling Signed-off-by: Alexandros Filios --- .../core/fabricdev/channelprovider.go | 19 ++- .../core/fabricdev/driver/provider.go | 7 +- .../fabricdev/sdk/fabricdev/providers.go | 8 + platform/common/driver/kvs.go | 50 +++++++ platform/common/services/sig/service.go | 95 +++--------- .../fabric/core/generic/channelprovider.go | 19 ++- .../fabric/core/generic/driver/provider.go | 5 +- platform/fabric/core/generic/id/info_test.go | 2 +- .../core/generic/msp/idemix/provider_test.go | 14 +- .../fabric/core/generic/msp/service_test.go | 10 +- .../core/generic/transaction/services.go | 138 ++++-------------- platform/fabric/driver/kvs.go | 27 ++++ platform/fabric/sdk/dig/generic/providers.go | 13 +- platform/fabric/sdk/dig/sdk.go | 4 + platform/fabric/services/kvs/kvs.go | 29 ++++ platform/orion/core/generic/network.go | 37 +++-- .../core/generic/transaction/services.go | 122 ++++------------ platform/orion/core/provider.go | 26 +++- platform/orion/driver/kvs.go | 26 ++++ platform/orion/sdk/dig/sdk.go | 11 +- platform/orion/services/kvs/kvs.go | 28 ++++ platform/view/core/endpoint/endpoint.go | 46 +----- platform/view/core/endpoint/endpoint_test.go | 11 +- platform/view/sdk/dig/sdk.go | 7 +- platform/view/services/kvs/enhanced.go | 75 ++++++++++ platform/view/services/kvs/scope.go | 114 +++++++++++++++ 26 files changed, 571 insertions(+), 372 deletions(-) create mode 100644 platform/common/driver/kvs.go create mode 100644 platform/fabric/driver/kvs.go create mode 100644 platform/fabric/services/kvs/kvs.go create mode 100644 platform/orion/driver/kvs.go create mode 100644 platform/orion/services/kvs/kvs.go create mode 100644 platform/view/services/kvs/enhanced.go create mode 100644 platform/view/services/kvs/scope.go diff --git a/docs/fabric/fabricdev/core/fabricdev/channelprovider.go b/docs/fabric/fabricdev/core/fabricdev/channelprovider.go index 577d12e25..1e89e261f 100644 --- a/docs/fabric/fabricdev/core/fabricdev/channelprovider.go +++ b/docs/fabric/fabricdev/core/fabricdev/channelprovider.go @@ -23,7 +23,6 @@ import ( driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/events" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/hash" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/metrics" "github.com/hyperledger/fabric-protos-go/common" "github.com/pkg/errors" @@ -31,7 +30,9 @@ import ( ) type provider struct { - kvss *kvs.KVS + envelopeKVS driver.EnvelopeKVS + metadataKVS driver.MetadataKVS + endorseTxKVS driver.EndorseTxKVS publisher events.Publisher hasher hash.Hasher newVault generic.VaultConstructor @@ -45,7 +46,9 @@ type provider struct { } func NewChannelProvider( - kvss *kvs.KVS, + envelopeKVS driver.EnvelopeKVS, + metadataKVS driver.MetadataKVS, + endorseTxKVS driver.EndorseTxKVS, publisher events.Publisher, hasher hash.Hasher, tracerProvider trace.TracerProvider, @@ -58,7 +61,9 @@ func NewChannelProvider( acceptedHeaderTypes []common.HeaderType, ) *provider { return &provider{ - kvss: kvss, + envelopeKVS: envelopeKVS, + metadataKVS: metadataKVS, + endorseTxKVS: endorseTxKVS, publisher: publisher, hasher: hasher, newVault: newVault, @@ -90,9 +95,9 @@ func (p *provider) NewChannel(nw driver.FabricNetworkService, channelName string return nil, err } - envelopeService := transaction.NewEnvelopeService(p.kvss, nw.Name(), channelName) - transactionService := transaction.NewEndorseTransactionService(p.kvss, nw.Name(), channelName) - metadataService := transaction.NewMetadataService(p.kvss, nw.Name(), channelName) + envelopeService := transaction.NewEnvelopeService(p.envelopeKVS, nw.Name(), channelName) + transactionService := transaction.NewEndorseTransactionService(p.endorseTxKVS, nw.Name(), channelName) + metadataService := transaction.NewMetadataService(p.metadataKVS, nw.Name(), channelName) peerService := services.NewClientFactory(nw.ConfigService(), nw.LocalMembership().DefaultSigningIdentity()) // Fabric finality diff --git a/docs/fabric/fabricdev/core/fabricdev/driver/provider.go b/docs/fabric/fabricdev/core/fabricdev/driver/provider.go index 0b29b9a23..09aea1684 100644 --- a/docs/fabric/fabricdev/core/fabricdev/driver/provider.go +++ b/docs/fabric/fabricdev/core/fabricdev/driver/provider.go @@ -50,6 +50,9 @@ type Provider struct { } func NewProvider( + envelopeKVS fdriver.EnvelopeKVS, + metadataKVS fdriver.MetadataKVS, + endorseTxKVS fdriver.EndorseTxKVS, configProvider config.Provider, metricsProvider metrics.Provider, endpointService identity.EndpointService, @@ -65,7 +68,9 @@ func NewProvider( return &Provider{ configProvider: configProvider, channelProvider: fabricdev.NewChannelProvider( - kvss, + envelopeKVS, + metadataKVS, + endorseTxKVS, publisher, hasher, tracerProvider, diff --git a/docs/fabric/fabricdev/sdk/fabricdev/providers.go b/docs/fabric/fabricdev/sdk/fabricdev/providers.go index 6b3b37203..a29707f2d 100644 --- a/docs/fabric/fabricdev/sdk/fabricdev/providers.go +++ b/docs/fabric/fabricdev/sdk/fabricdev/providers.go @@ -12,6 +12,7 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic/driver/config" mspdriver "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic/msp/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver" vdriver "github.com/hyperledger-labs/fabric-smart-client/platform/view/driver" dbdriver "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/events" @@ -24,6 +25,10 @@ import ( func NewDriver(in struct { dig.In + + EnvelopeKVS driver.EnvelopeKVS + MetadataKVS driver.MetadataKVS + EndorseTxKVS driver.EndorseTxKVS ConfigProvider config.Provider MetricsProvider metrics.Provider EndpointService vdriver.EndpointService @@ -39,6 +44,9 @@ func NewDriver(in struct { d := core.NamedDriver{ Name: "fabricdev", Driver: fdevdriver.NewProvider( + in.EnvelopeKVS, + in.MetadataKVS, + in.EndorseTxKVS, in.ConfigProvider, in.MetricsProvider, in.EndpointService, diff --git a/platform/common/driver/kvs.go b/platform/common/driver/kvs.go new file mode 100644 index 000000000..0c1c92c2f --- /dev/null +++ b/platform/common/driver/kvs.go @@ -0,0 +1,50 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package driver + +import ( + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" +) + +type SignerEntry struct { + Signer Signer + DebugStack []byte +} + +type SignerKVS interface { + GetSigner(id view.Identity) (*SignerEntry, error) + FilterExistingSigners(ids ...view.Identity) ([]view.Identity, error) + PutSigner(id view.Identity, entry *SignerEntry) error +} + +type AuditInfoKVS interface { + GetAuditInfo(id view.Identity) ([]byte, error) + PutAuditInfo(id view.Identity, info []byte) error +} + +type BindingKVS interface { + GetBinding(ephemeral view.Identity) (view.Identity, error) + PutBinding(ephemeral, longTerm view.Identity) error +} + +type MetadataKVS[K any, M any] interface { + GetMetadata(key K) (M, error) + ExistMetadata(key K) (bool, error) + PutMetadata(key K, transientMap M) error +} + +type EnvelopeKVS[K any] interface { + GetEnvelope(key K) ([]byte, error) + ExistsEnvelope(key K) (bool, error) + PutEnvelope(key K, env []byte) error +} + +type EndorseTxKVS[K any] interface { + GetEndorseTx(key K) ([]byte, error) + ExistsEndorseTx(key K) (bool, error) + PutEndorseTx(key K, etx []byte) error +} diff --git a/platform/common/services/sig/service.go b/platform/common/services/sig/service.go index d6bce3731..46e35104e 100644 --- a/platform/common/services/sig/service.go +++ b/platform/common/services/sig/service.go @@ -12,10 +12,10 @@ import ( "runtime/debug" "sync" + driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" "github.com/hyperledger-labs/fabric-smart-client/platform/view/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" "github.com/pkg/errors" "go.uber.org/zap/zapcore" @@ -23,38 +23,30 @@ import ( var logger = logging.MustGetLogger("common-sdk.sig") -type KVS interface { - Exists(id string) bool - GetExisting(ids ...string) []string - Put(id string, state interface{}) error - Get(id string, state interface{}) error -} - type VerifierEntry struct { Verifier driver.Verifier DebugStack []byte } -type SignerEntry struct { - Signer driver.Signer - DebugStack []byte -} +type SignerEntry = driver2.SignerEntry type Service struct { deserializer Deserializer - kvs KVS + signerKVS driver2.SignerKVS + auditInfoKVS driver2.AuditInfoKVS mutex sync.RWMutex signers map[string]SignerEntry verifiers map[string]VerifierEntry } -func NewService(deserializer Deserializer, kvs KVS) *Service { +func NewService(deserializer Deserializer, auditInfoKVS driver2.AuditInfoKVS, signerKVS driver2.SignerKVS) *Service { return &Service{ + signerKVS: signerKVS, + auditInfoKVS: auditInfoKVS, signers: map[string]SignerEntry{}, verifiers: map[string]VerifierEntry{}, deserializer: deserializer, - kvs: kvs, } } @@ -91,8 +83,8 @@ func (o *Service) RegisterSigner(identity view.Identity, signer driver.Signer, v o.signers[idHash] = entry o.mutex.Unlock() - if o.kvs != nil { - if err := o.registerSigner(idHash, &entry); err != nil { + if o.signerKVS != nil { + if err := o.signerKVS.PutSigner(identity, &entry); err != nil { o.deleteSigner(idHash) return errors.Wrap(err, "failed to store entry in kvs for the passed signer") } @@ -151,34 +143,11 @@ func (o *Service) RegisterVerifier(identity view.Identity, verifier driver.Verif } func (o *Service) RegisterAuditInfo(identity view.Identity, info []byte) error { - k := kvs.CreateCompositeKeyOrPanic( - "fsc.platform.view.sig", - []string{ - identity.String(), - }, - ) - if err := o.kvs.Put(k, info); err != nil { - return err - } - return nil + return o.auditInfoKVS.PutAuditInfo(identity, info) } func (o *Service) GetAuditInfo(identity view.Identity) ([]byte, error) { - k := kvs.CreateCompositeKeyOrPanic( - "fsc.platform.view.sig", - []string{ - identity.String(), - }, - ) - - if !o.kvs.Exists(k) { - return nil, nil - } - var res []byte - if err := o.kvs.Get(k, &res); err != nil { - return nil, err - } - return res, nil + return o.auditInfoKVS.GetAuditInfo(identity) } func (o *Service) IsMe(identity view.Identity) bool { @@ -186,37 +155,31 @@ func (o *Service) IsMe(identity view.Identity) bool { } func (o *Service) AreMe(identities ...view.Identity) []string { - idHashes := make([]string, len(identities)) - for i, id := range identities { - idHashes[i] = id.UniqueID() - } result := collections.NewSet[string]() - notFound := make([]string, 0) + notFound := make([]view.Identity, 0) // check local cache o.mutex.RLock() - for _, idHash := range idHashes { - if _, ok := o.signers[idHash]; ok { - result.Add(idHash) + for _, id := range identities { + if _, ok := o.signers[id.UniqueID()]; ok { + result.Add(id.UniqueID()) } else { - notFound = append(notFound, idHash) + notFound = append(notFound, id) } } o.mutex.RUnlock() - if len(notFound) == 0 || o.kvs == nil { + if len(notFound) == 0 || o.signerKVS == nil { return result.ToSlice() } // check kvs - keys := make([]string, len(notFound)) - for i, idHash := range notFound { - key, err := kvs.CreateCompositeKey("sigService", []string{"signer", idHash}) - if err != nil { - logger.Errorf("failed creating composite key: %v", err) + + if existing, err := o.signerKVS.FilterExistingSigners(notFound...); err != nil { + logger.Errorf("failed getting existing signers: %v", err) + } else { + for _, id := range existing { + result.Add(id.UniqueID()) } - keys[i] = key } - result.Add(o.kvs.GetExisting(keys...)...) - return result.ToSlice() } @@ -341,18 +304,6 @@ func (o *Service) GetSigningIdentity(identity view.Identity) (driver.SigningIden }, nil } -func (o *Service) registerSigner(id string, signer *SignerEntry) error { - k, err := kvs.CreateCompositeKey("sigService", []string{"signer", id}) - if err != nil { - return errors.Wrap(err, "failed to create composite key to store entry in kvs") - } - err = o.kvs.Put(k, signer) - if err != nil { - return errors.Wrap(err, "failed to store entry in kvs for the passed signer") - } - return nil -} - func (o *Service) deleteSigner(id string) { o.mutex.Lock() defer o.mutex.Unlock() diff --git a/platform/fabric/core/generic/channelprovider.go b/platform/fabric/core/generic/channelprovider.go index 294ad3cc8..35f6f48be 100644 --- a/platform/fabric/core/generic/channelprovider.go +++ b/platform/fabric/core/generic/channelprovider.go @@ -21,7 +21,6 @@ import ( driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/events" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/hash" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/metrics" "github.com/hyperledger/fabric-protos-go/common" "github.com/pkg/errors" @@ -69,7 +68,9 @@ type ChannelProvider interface { } type provider struct { - kvss *kvs.KVS + envelopeKVS driver.EnvelopeKVS + metadataKVS driver.MetadataKVS + endorserTxKVS driver.EndorseTxKVS publisher events.Publisher hasher hash.Hasher newVault VaultConstructor @@ -87,7 +88,9 @@ type provider struct { } func NewChannelProvider( - kvss *kvs.KVS, + envelopeKVS driver.EnvelopeKVS, + metadataKVS driver.MetadataKVS, + endorserTxKVS driver.EndorseTxKVS, publisher events.Publisher, hasher hash.Hasher, tracerProvider trace.TracerProvider, @@ -104,7 +107,9 @@ func NewChannelProvider( acceptedHeaderTypes []common.HeaderType, ) *provider { return &provider{ - kvss: kvss, + envelopeKVS: envelopeKVS, + metadataKVS: metadataKVS, + endorserTxKVS: endorserTxKVS, publisher: publisher, hasher: hasher, newVault: newVault, @@ -141,9 +146,9 @@ func (p *provider) NewChannel(nw driver.FabricNetworkService, channelName string return nil, err } - envelopeService := transaction.NewEnvelopeService(p.kvss, nw.Name(), channelName) - transactionService := transaction.NewEndorseTransactionService(p.kvss, nw.Name(), channelName) - metadataService := transaction.NewMetadataService(p.kvss, nw.Name(), channelName) + envelopeService := transaction.NewEnvelopeService(p.envelopeKVS, nw.Name(), channelName) + transactionService := transaction.NewEndorseTransactionService(p.endorserTxKVS, nw.Name(), channelName) + metadataService := transaction.NewMetadataService(p.metadataKVS, nw.Name(), channelName) peerService := services.NewClientFactory(nw.ConfigService(), nw.LocalMembership().DefaultSigningIdentity()) // Fabric finality diff --git a/platform/fabric/core/generic/driver/provider.go b/platform/fabric/core/generic/driver/provider.go index d566520f2..9aa77b999 100644 --- a/platform/fabric/core/generic/driver/provider.go +++ b/platform/fabric/core/generic/driver/provider.go @@ -9,6 +9,7 @@ package driver import ( "fmt" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/sig" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic" @@ -39,10 +40,12 @@ func NewProvider( channelProvider generic.ChannelProvider, idProvider vdriver.IdentityProvider, identityLoaders []identity.NamedIdentityLoader, + signerKVS driver.SignerKVS, + auditInfoKVS driver.AuditInfoKVS, kvss *kvs.KVS, ) *Provider { deserializerManager := sig.NewMultiplexDeserializer() - sigService := sig.NewService(deserializerManager, kvss) + sigService := sig.NewService(deserializerManager, auditInfoKVS, signerKVS) return &Provider{ configProvider: configProvider, channelProvider: channelProvider, diff --git a/platform/fabric/core/generic/id/info_test.go b/platform/fabric/core/generic/id/info_test.go index 5acee967a..1e21aeda2 100644 --- a/platform/fabric/core/generic/id/info_test.go +++ b/platform/fabric/core/generic/id/info_test.go @@ -27,7 +27,7 @@ func TestInfoIdemix(t *testing.T) { kvss, err := kvs.NewWithConfig(&mem.Driver{}, "", &mock.ConfigProvider{}) assert.NoError(t, err) assert.NoError(t, registry.RegisterService(kvss)) - sigService := sig.NewService(sig.NewMultiplexDeserializer(), kvss) + sigService := sig.NewService(sig.NewMultiplexDeserializer(), kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) config, err := msp2.GetLocalMspConfigWithType("./testdata/idemix", nil, "idemix", "idemix") diff --git a/platform/fabric/core/generic/msp/idemix/provider_test.go b/platform/fabric/core/generic/msp/idemix/provider_test.go index 967917c31..083deb0d7 100644 --- a/platform/fabric/core/generic/msp/idemix/provider_test.go +++ b/platform/fabric/core/generic/msp/idemix/provider_test.go @@ -29,7 +29,7 @@ func TestProvider(t *testing.T) { kvss, err := kvs.NewWithConfig(&mem.Driver{}, "", &mock.ConfigProvider{}) assert.NoError(t, err) assert.NoError(t, registry.RegisterService(kvss)) - sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvss) + sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) config, err := msp2.GetLocalMspConfigWithType("./testdata/idemix", nil, "idemix", "idemix") @@ -54,7 +54,7 @@ func TestIdentityWithEidRhNymPolicy(t *testing.T) { kvss, err := kvs.NewWithConfig(&mem.Driver{}, "", &mock.ConfigProvider{}) assert.NoError(t, err) assert.NoError(t, registry.RegisterService(kvss)) - sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvss) + sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) config, err := msp2.GetLocalMspConfigWithType("./testdata/idemix", nil, "idemix", "idemix") @@ -119,7 +119,7 @@ func TestIdentityStandard(t *testing.T) { kvss, err := kvs.NewWithConfig(&mem.Driver{}, "", &mock.ConfigProvider{}) assert.NoError(t, err) assert.NoError(t, registry.RegisterService(kvss)) - sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvss) + sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) config, err := msp2.GetLocalMspConfigWithType("./testdata/idemix", nil, "idemix", "idemix") @@ -186,7 +186,7 @@ func TestAuditWithEidRhNymPolicy(t *testing.T) { kvss, err := kvs.NewWithConfig(&mem.Driver{}, "", &mock.ConfigProvider{}) assert.NoError(t, err) assert.NoError(t, registry.RegisterService(kvss)) - sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvss) + sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) config, err := msp2.GetLocalMspConfigWithType("./testdata/idemix", nil, "idemix", "idemix") @@ -228,7 +228,7 @@ func TestProvider_DeserializeSigner(t *testing.T) { kvss, err := kvs.NewWithConfig(&mem.Driver{}, "", &mock.ConfigProvider{}) assert.NoError(t, err) assert.NoError(t, registry.RegisterService(kvss)) - sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvss) + sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) config, err := msp2.GetLocalMspConfigWithType("./testdata/sameissuer/idemix", nil, "idemix", "idemix") @@ -284,7 +284,7 @@ func TestIdentityFromFabricCA(t *testing.T) { kvss, err := kvs.NewWithConfig(&mem.Driver{}, "", &mock.ConfigProvider{}) assert.NoError(t, err) assert.NoError(t, registry.RegisterService(kvss)) - sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvss) + sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) config, err := idemix2.GetLocalMspConfigWithType("./testdata/charlie.ExtraId2", "charlie.ExtraId2") @@ -351,7 +351,7 @@ func TestIdentityFromFabricCAWithEidRhNymPolicy(t *testing.T) { kvss, err := kvs.NewWithConfig(&mem.Driver{}, "", &mock.ConfigProvider{}) assert.NoError(t, err) assert.NoError(t, registry.RegisterService(kvss)) - sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvss) + sigService := sig2.NewService(sig2.NewMultiplexDeserializer(), kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) config, err := idemix2.GetLocalMspConfigWithType("./testdata/charlie.ExtraId2", "charlie.ExtraId2") diff --git a/platform/fabric/core/generic/msp/service_test.go b/platform/fabric/core/generic/msp/service_test.go index 77cdf32ea..b29f396d0 100644 --- a/platform/fabric/core/generic/msp/service_test.go +++ b/platform/fabric/core/generic/msp/service_test.go @@ -41,7 +41,7 @@ func TestRegisterIdemixLocalMSP(t *testing.T) { assert.NoError(t, err) mspService := msp2.NewLocalMSPManager(config, kvss, nil, nil, nil, des, 100) assert.NoError(t, registry.RegisterService(mspService)) - sigService := sig.NewService(des, kvss) + sigService := sig.NewService(des, kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) assert.NoError(t, mspService.RegisterIdemixMSP("apple", "./idemix/testdata/idemix", "idemix")) @@ -73,7 +73,7 @@ func TestIdemixTypeFolder(t *testing.T) { assert.NoError(t, err) mspService := msp2.NewLocalMSPManager(config, kvss, nil, nil, nil, des, 100) assert.NoError(t, registry.RegisterService(mspService)) - sigService := sig.NewService(des, kvss) + sigService := sig.NewService(des, kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) assert.NoError(t, mspService.Load()) @@ -101,7 +101,7 @@ func TestRegisterX509LocalMSP(t *testing.T) { assert.NoError(t, err) mspService := msp2.NewLocalMSPManager(config, kvss, nil, nil, nil, des, 100) assert.NoError(t, registry.RegisterService(mspService)) - sigService := sig.NewService(des, kvss) + sigService := sig.NewService(des, kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) assert.NoError(t, mspService.RegisterX509MSP("apple", "./x509/testdata/msp", "x509")) @@ -132,7 +132,7 @@ func TestX509TypeFolder(t *testing.T) { assert.NoError(t, err) mspService := msp2.NewLocalMSPManager(config, kvss, nil, nil, nil, des, 100) assert.NoError(t, registry.RegisterService(mspService)) - sigService := sig.NewService(des, kvss) + sigService := sig.NewService(des, kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) assert.NoError(t, mspService.Load()) @@ -160,7 +160,7 @@ func TestRefresh(t *testing.T) { assert.NoError(t, err) mspService := msp2.NewLocalMSPManager(config, kvss, nil, nil, nil, des, 100) assert.NoError(t, registry.RegisterService(mspService)) - sigService := sig.NewService(des, kvss) + sigService := sig.NewService(des, kvs.NewAuditInfoKVS(kvss), kvs.NewSignerKVS(kvss)) assert.NoError(t, registry.RegisterService(sigService)) assert.NoError(t, mspService.Load()) diff --git a/platform/fabric/core/generic/transaction/services.go b/platform/fabric/core/generic/transaction/services.go index 3dc756856..ad0731cdb 100644 --- a/platform/fabric/core/generic/transaction/services.go +++ b/platform/fabric/core/generic/transaction/services.go @@ -8,172 +8,94 @@ package transaction import ( "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto" + driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/hyperledger/fabric-protos-go/common" "github.com/pkg/errors" - "go.uber.org/zap/zapcore" ) var logger = logging.MustGetLogger("fabric-sdk.core") -type KVS interface { - Exists(id string) bool - Put(id string, state interface{}) error - Get(id string, state interface{}) error -} - type mds struct { - KVS KVS - network string - channel string + metadataKVS driver.MetadataKVS + key func(driver2.TxID) driver.Key } -func NewMetadataService(KVS KVS, network string, channel string) *mds { - return &mds{ - KVS: KVS, - network: network, - channel: channel, - } +func NewMetadataService(metadataKVS driver.MetadataKVS, network string, channel string) *mds { + return &mds{metadataKVS: metadataKVS, key: keyMapper(network, channel)} } func (s *mds) Exists(txid string) bool { - key, err := kvs.CreateCompositeKey("metadata", []string{s.channel, s.network, txid}) - if err != nil { - return false - } - return s.KVS.Exists(key) + ok, _ := s.metadataKVS.ExistMetadata(s.key(txid)) + return ok } func (s *mds) StoreTransient(txid string, transientMap driver.TransientMap) error { - key, err := kvs.CreateCompositeKey("metadata", []string{s.channel, s.network, txid}) - if err != nil { - return err - } - if logger.IsEnabledFor(zapcore.DebugLevel) { - logger.Debugf("store transient for [%s][%v]", txid, transientMap) - } - return s.KVS.Put(key, transientMap) + return s.metadataKVS.PutMetadata(s.key(txid), transientMap) } func (s *mds) LoadTransient(txid string) (driver.TransientMap, error) { - logger.Debugf("load transient for [%s]", txid) - - key, err := kvs.CreateCompositeKey("metadata", []string{s.channel, s.network, txid}) - if err != nil { - return nil, err - } - transientMap := driver.TransientMap{} - err = s.KVS.Get(key, &transientMap) - if err != nil { - return nil, err - } - return transientMap, nil + return s.metadataKVS.GetMetadata(s.key(txid)) } type envs struct { - KVS KVS - network string - channel string + envelopeKVS driver.EnvelopeKVS + key func(driver2.TxID) driver.Key } -func NewEnvelopeService(KVS KVS, network string, channel string) *envs { - return &envs{ - KVS: KVS, - network: network, - channel: channel, - } +func NewEnvelopeService(envelopeKVS driver.EnvelopeKVS, network string, channel string) *envs { + return &envs{envelopeKVS: envelopeKVS, key: keyMapper(network, channel)} } func (s *envs) Exists(txid string) bool { - key, err := kvs.CreateCompositeKey("envelope", []string{s.channel, s.network, txid}) - if err != nil { - return false - } - - return s.KVS.Exists(key) + ok, _ := s.envelopeKVS.ExistsEnvelope(s.key(txid)) + return ok } func (s *envs) StoreEnvelope(txID string, env interface{}) error { - key, err := kvs.CreateCompositeKey("envelope", []string{s.channel, s.network, txID}) - if err != nil { - return err - } - logger.Debugf("store env for [%s]", txID) - switch e := env.(type) { case []byte: - return s.KVS.Put(key, e) + return s.envelopeKVS.PutEnvelope(s.key(txID), e) case *common.Envelope: envBytes, err := proto.Marshal(e) if err != nil { return errors.WithMessagef(err, "failed marshalling envelop for tx [%s]", txID) } - return s.KVS.Put(key, envBytes) + return s.envelopeKVS.PutEnvelope(s.key(txID), envBytes) default: return errors.Errorf("invalid env, expected []byte or *common.Envelope, got [%T]", env) } } func (s *envs) LoadEnvelope(txid string) ([]byte, error) { - logger.Debugf("load env for [%s]", txid) - - key, err := kvs.CreateCompositeKey("envelope", []string{s.channel, s.network, txid}) - if err != nil { - return nil, err - } - env := []byte{} - err = s.KVS.Get(key, &env) - if err != nil { - return nil, err - } - return env, nil + return s.envelopeKVS.GetEnvelope(s.key(txid)) } type ets struct { - KVS KVS - network string - channel string + endorseTxKVS driver.EndorseTxKVS + key func(driver2.TxID) driver.Key } -func NewEndorseTransactionService(KVS KVS, network string, channel string) *ets { - return &ets{ - KVS: KVS, - network: network, - channel: channel, - } +func NewEndorseTransactionService(endorseTxKVS driver.EndorseTxKVS, network string, channel string) *ets { + return &ets{endorseTxKVS: endorseTxKVS, key: keyMapper(network, channel)} } func (s *ets) Exists(txid string) bool { - key, err := kvs.CreateCompositeKey("etx", []string{s.channel, s.network, txid}) - if err != nil { - return false - } - return s.KVS.Exists(key) + ok, _ := s.endorseTxKVS.ExistsEndorseTx(s.key(txid)) + return ok } func (s *ets) StoreTransaction(txid string, env []byte) error { - key, err := kvs.CreateCompositeKey("etx", []string{s.channel, s.network, txid}) - if err != nil { - return err - } - logger.Debugf("store etx for [%s]", txid) - - return s.KVS.Put(key, env) + return s.endorseTxKVS.PutEndorseTx(s.key(txid), env) } func (s *ets) LoadTransaction(txid string) ([]byte, error) { - logger.Debugf("load etx for [%s]", txid) + return s.endorseTxKVS.GetEndorseTx(s.key(txid)) +} - key, err := kvs.CreateCompositeKey("etx", []string{s.channel, s.network, txid}) - if err != nil { - return nil, err - } - env := []byte{} - err = s.KVS.Get(key, &env) - if err != nil { - return nil, err +func keyMapper(network, channel string) func(txID driver2.TxID) driver.Key { + return func(txID driver2.TxID) driver.Key { + return driver.Key{Network: network, Channel: channel, TxID: txID} } - return env, nil } diff --git a/platform/fabric/driver/kvs.go b/platform/fabric/driver/kvs.go new file mode 100644 index 000000000..2a17de750 --- /dev/null +++ b/platform/fabric/driver/kvs.go @@ -0,0 +1,27 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package driver + +import "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" + +type Key struct { + Network string + Channel string + TxID driver.TxID +} + +type MetadataKVS interface { + driver.MetadataKVS[Key, TransientMap] +} + +type EnvelopeKVS interface { + driver.EnvelopeKVS[Key] +} + +type EndorseTxKVS interface { + driver.EndorseTxKVS[Key] +} diff --git a/platform/fabric/sdk/dig/generic/providers.go b/platform/fabric/sdk/dig/generic/providers.go index 652637bc2..1419ee198 100644 --- a/platform/fabric/sdk/dig/generic/providers.go +++ b/platform/fabric/sdk/dig/generic/providers.go @@ -9,6 +9,7 @@ package generic import ( "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors" committer2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/core/generic/committer" + driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" digutils "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/dig" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic" @@ -54,6 +55,8 @@ func NewDriver(in struct { EndpointService vdriver.EndpointService IdProvider vdriver.IdentityProvider KVS *kvs.KVS + AuditInfoKVS driver2.AuditInfoKVS + SignerKVS driver2.SignerKVS ChannelProvider generic.ChannelProvider `name:"generic-channel-provider"` IdentityLoaders []identity.NamedIdentityLoader `group:"identity-loaders"` }) core.NamedDriver { @@ -66,6 +69,8 @@ func NewDriver(in struct { in.ChannelProvider, in.IdProvider, in.IdentityLoaders, + in.SignerKVS, + in.AuditInfoKVS, in.KVS, ), } @@ -75,7 +80,9 @@ func NewDriver(in struct { func NewChannelProvider(in struct { dig.In ConfigProvider config.Provider - KVS *kvs.KVS + EnvelopeKVS driver.EnvelopeKVS + MetadataKVS driver.MetadataKVS + EndorseTxKVS driver.EndorseTxKVS Publisher events.Publisher Hasher hash.Hasher TracerProvider trace.TracerProvider @@ -83,7 +90,9 @@ func NewChannelProvider(in struct { MetricsProvider metrics.Provider }) generic.ChannelProvider { return generic.NewChannelProvider( - in.KVS, + in.EnvelopeKVS, + in.MetadataKVS, + in.EndorseTxKVS, in.Publisher, in.Hasher, in.TracerProvider, diff --git a/platform/fabric/sdk/dig/sdk.go b/platform/fabric/sdk/dig/sdk.go index 7f4f32933..c16bb2a15 100644 --- a/platform/fabric/sdk/dig/sdk.go +++ b/platform/fabric/sdk/dig/sdk.go @@ -26,6 +26,7 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/sdk/dig/fns" generic2 "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/sdk/dig/generic" finality2 "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/sdk/finality" + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/state" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/state/vault" "github.com/hyperledger-labs/fabric-smart-client/platform/view/core/endpoint" @@ -71,6 +72,9 @@ func (p *SDK) Install() error { p.Container().Provide(vault.NewService, dig.As(new(state.VaultService))), p.Container().Provide(generic2.NewEndorserTransactionHandlerProvider), p.Container().Provide(committer2.NewSerialDependencyResolver, dig.As(new(committer2.DependencyResolver))), + p.Container().Provide(kvs.NewMetadataKVS, dig.As(new(driver.MetadataKVS))), + p.Container().Provide(kvs.NewEnvelopeKVS, dig.As(new(driver.EnvelopeKVS))), + p.Container().Provide(kvs.NewEndorseTxKVS, dig.As(new(driver.EndorseTxKVS))), ) if err != nil { return err diff --git a/platform/fabric/services/kvs/kvs.go b/platform/fabric/services/kvs/kvs.go new file mode 100644 index 000000000..b57c15add --- /dev/null +++ b/platform/fabric/services/kvs/kvs.go @@ -0,0 +1,29 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kvs + +import ( + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" +) + +func NewMetadataKVS(kvss *kvs.KVS) driver.MetadataKVS { + return kvs.NewMetadataKVS[driver.Key, driver.TransientMap](kvss, keyMapper("metadata")) +} + +func NewEnvelopeKVS(kvss *kvs.KVS) driver.EnvelopeKVS { + return kvs.NewEnvelopeKVS(kvss, keyMapper("envelope")) +} + +func NewEndorseTxKVS(kvss *kvs.KVS) driver.EndorseTxKVS { + return kvs.NewEndorseTxKVS[driver.Key](kvss, keyMapper("etx")) +} +func keyMapper(prefix string) kvs.KeyMapper[driver.Key] { + return func(k driver.Key) (string, error) { + return kvs.CreateCompositeKey(prefix, []string{k.Channel, k.Network, k.TxID}) + } +} diff --git a/platform/orion/core/generic/network.go b/platform/orion/core/generic/network.go index e58e0924d..2ebb46648 100644 --- a/platform/orion/core/generic/network.go +++ b/platform/orion/core/generic/network.go @@ -21,7 +21,6 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db" driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/events" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/metrics" "github.com/hyperledger-labs/orion-server/pkg/types" "github.com/pkg/errors" @@ -52,7 +51,14 @@ type network struct { deliveryService driver.DeliveryService } -func NewDB(ctx context.Context, kvss *kvs.KVS, config *config2.Config, name string) (*network, error) { +func NewDB( + ctx context.Context, + endorseTxKVS driver.EndorseTxKVS, + metadataKVS driver.MetadataKVS, + envelopeKVS driver.EnvelopeKVS, + config *config2.Config, + name string, +) (*network, error) { // Load configuration n := &network{ ctx: ctx, @@ -79,16 +85,29 @@ func NewDB(ctx context.Context, kvss *kvs.KVS, config *config2.Config, name stri config: config, identityManager: n.identityManager, } - n.metadataService = transaction.NewMetadataService(kvss, name) - n.envelopeService = transaction.NewEnvelopeService(kvss, name) + n.metadataService = transaction.NewMetadataService(metadataKVS, name) + n.envelopeService = transaction.NewEnvelopeService(envelopeKVS, name) n.transactionManager = transaction.NewManager(n.sessionManager) - n.transactionService = transaction.NewEndorseTransactionService(kvss, name) + n.transactionService = transaction.NewEndorseTransactionService(endorseTxKVS, name) n.processorManager = rwset.NewProcessorManager(n, nil) return n, nil } -func NewNetwork(ctx context.Context, kvss *kvs.KVS, eventsPublisher events.Publisher, eventsSubscriber events.Subscriber, metricsProvider metrics.Provider, tracerProvider trace.TracerProvider, config *config2.Config, name string, drivers []driver2.NamedDriver, networkConfig driver.NetworkConfig, listenerManager driver.ListenerManager) (*network, error) { +func NewNetwork( + ctx context.Context, + endorseTxKVS driver.EndorseTxKVS, + metadataKVS driver.MetadataKVS, + envelopeKVS driver.EnvelopeKVS, + eventsPublisher events.Publisher, + eventsSubscriber events.Subscriber, + metricsProvider metrics.Provider, + tracerProvider trace.TracerProvider, + config *config2.Config, + name string, drivers []driver2.NamedDriver, + networkConfig driver.NetworkConfig, + listenerManager driver.ListenerManager, +) (*network, error) { // Load configuration n := &network{ ctx: ctx, @@ -115,10 +134,10 @@ func NewNetwork(ctx context.Context, kvss *kvs.KVS, eventsPublisher events.Publi config: config, identityManager: n.identityManager, } - n.metadataService = transaction.NewMetadataService(kvss, name) - n.envelopeService = transaction.NewEnvelopeService(kvss, name) + n.metadataService = transaction.NewMetadataService(metadataKVS, name) + n.envelopeService = transaction.NewEnvelopeService(envelopeKVS, name) n.transactionManager = transaction.NewManager(n.sessionManager) - n.transactionService = transaction.NewEndorseTransactionService(kvss, name) + n.transactionService = transaction.NewEndorseTransactionService(endorseTxKVS, name) var d driver2.Driver for _, driver := range drivers { diff --git a/platform/orion/core/generic/transaction/services.go b/platform/orion/core/generic/transaction/services.go index 06e841a46..b09d332c4 100644 --- a/platform/orion/core/generic/transaction/services.go +++ b/platform/orion/core/generic/transaction/services.go @@ -7,151 +7,85 @@ SPDX-License-Identifier: Apache-2.0 package transaction import ( + driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" "github.com/hyperledger-labs/fabric-smart-client/platform/orion/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/pkg/errors" ) var logger = logging.MustGetLogger("orion-sdk.core") type mds struct { - kvss *kvs.KVS - network string + metadataKVS driver.MetadataKVS + key func(id driver2.TxID) driver.Key } -func NewMetadataService(kvss *kvs.KVS, network string) *mds { - return &mds{ - kvss: kvss, - network: network, - } +func NewMetadataService(metadataKVS driver.MetadataKVS, network string) *mds { + return &mds{metadataKVS: metadataKVS, key: keyMapper(network)} } func (s *mds) Exists(txid string) bool { - key, err := kvs.CreateCompositeKey("metadata", []string{s.network, txid}) - if err != nil { - return false - } - return s.kvss.Exists(key) + ok, _ := s.metadataKVS.ExistMetadata(s.key(txid)) + return ok } func (s *mds) StoreTransient(txid string, transientMap driver.TransientMap) error { - key, err := kvs.CreateCompositeKey("metadata", []string{s.network, txid}) - if err != nil { - return err - } - logger.Debugf("store transient for [%s]", txid) - - return s.kvss.Put(key, transientMap) + return s.metadataKVS.PutMetadata(s.key(txid), transientMap) } func (s *mds) LoadTransient(txid string) (driver.TransientMap, error) { - logger.Debugf("load transient for [%s]", txid) - - key, err := kvs.CreateCompositeKey("metadata", []string{s.network, txid}) - if err != nil { - return nil, err - } - transientMap := driver.TransientMap{} - err = s.kvss.Get(key, &transientMap) - if err != nil { - return nil, err - } - return transientMap, nil + return s.metadataKVS.GetMetadata(s.key(txid)) } type envs struct { - kvss *kvs.KVS - network string + envelopeKVS driver.EnvelopeKVS + key func(id driver2.TxID) driver.Key } -func NewEnvelopeService(kvss *kvs.KVS, network string) *envs { - return &envs{ - kvss: kvss, - network: network, - } +func NewEnvelopeService(envelopeKVS driver.EnvelopeKVS, network string) *envs { + return &envs{envelopeKVS: envelopeKVS, key: keyMapper(network)} } func (s *envs) Exists(txid string) bool { - key, err := kvs.CreateCompositeKey("envelope", []string{s.network, txid}) - if err != nil { - return false - } - - return s.kvss.Exists(key) + ok, _ := s.envelopeKVS.ExistsEnvelope(s.key(txid)) + return ok } func (s *envs) StoreEnvelope(txid string, env interface{}) error { - key, err := kvs.CreateCompositeKey("envelope", []string{s.network, txid}) - if err != nil { - return err - } - logger.Debugf("store env for [%s]", txid) - switch e := env.(type) { case []byte: - return s.kvss.Put(key, e) + return s.envelopeKVS.PutEnvelope(s.key(txid), e) default: return errors.Errorf("invalid env, expected []byte, got [%T]", env) } } func (s *envs) LoadEnvelope(txid string) ([]byte, error) { - logger.Debugf("load env for [%s]", txid) - - key, err := kvs.CreateCompositeKey("envelope", []string{s.network, txid}) - if err != nil { - return nil, err - } - env := []byte{} - err = s.kvss.Get(key, &env) - if err != nil { - return nil, err - } - return env, nil + return s.envelopeKVS.GetEnvelope(s.key(txid)) } type ets struct { - kvss *kvs.KVS - network string + endorseTxKVS driver.EndorseTxKVS + key func(id driver2.TxID) driver.Key } -func NewEndorseTransactionService(kvss *kvs.KVS, network string) *ets { - return &ets{ - kvss: kvss, - network: network, - } +func NewEndorseTransactionService(endorseTxKVS driver.EndorseTxKVS, network string) *ets { + return &ets{endorseTxKVS: endorseTxKVS, key: keyMapper(network)} } func (s *ets) Exists(txid string) bool { - key, err := kvs.CreateCompositeKey("etx", []string{s.network, txid}) - if err != nil { - return false - } - return s.kvss.Exists(key) + ok, _ := s.endorseTxKVS.ExistsEndorseTx(s.key(txid)) + return ok } func (s *ets) StoreTransaction(txid string, env []byte) error { - key, err := kvs.CreateCompositeKey("etx", []string{s.network, txid}) - if err != nil { - return err - } - logger.Debugf("store etx for [%s]", txid) - - return s.kvss.Put(key, env) + return s.endorseTxKVS.PutEndorseTx(s.key(txid), env) } func (s *ets) LoadTransaction(txid string) ([]byte, error) { - logger.Debugf("load etx for [%s]", txid) + return s.endorseTxKVS.GetEndorseTx(s.key(txid)) +} - key, err := kvs.CreateCompositeKey("etx", []string{s.network, txid}) - if err != nil { - return nil, err - } - env := []byte{} - err = s.kvss.Get(key, &env) - if err != nil { - return nil, err - } - return env, nil +func keyMapper(network string) func(txID driver2.TxID) driver.Key { + return func(txID driver2.TxID) driver.Key { return driver.Key{Network: network, TxID: txID} } } diff --git a/platform/orion/core/provider.go b/platform/orion/core/provider.go index 75a8677cc..1feb20ced 100644 --- a/platform/orion/core/provider.go +++ b/platform/orion/core/provider.go @@ -17,7 +17,6 @@ import ( driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/driver" driver3 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/events" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/metrics" "github.com/pkg/errors" "go.opentelemetry.io/otel/trace" @@ -31,7 +30,9 @@ type ONSProvider struct { configService driver2.ConfigService config *Config ctx context.Context - kvss *kvs.KVS + endorseTxKVS driver.EndorseTxKVS + metadataKVS driver.MetadataKVS + envelopeKVS driver.EnvelopeKVS publisher events.Publisher subscriber events.Subscriber @@ -44,11 +45,26 @@ type ONSProvider struct { listenerManagerProvider driver.ListenerManagerProvider } -func NewOrionNetworkServiceProvider(configService driver2.ConfigService, config *Config, kvss *kvs.KVS, publisher events.Publisher, subscriber events.Subscriber, metricsProvider metrics.Provider, tracerProvider trace.TracerProvider, drivers []driver3.NamedDriver, networkConfigProvider driver.NetworkConfigProvider, listenerManagerProvider driver.ListenerManagerProvider) (*ONSProvider, error) { +func NewOrionNetworkServiceProvider( + configService driver2.ConfigService, + config *Config, + endorseTxKVS driver.EndorseTxKVS, + metadataKVS driver.MetadataKVS, + envelopeKVS driver.EnvelopeKVS, + publisher events.Publisher, + subscriber events.Subscriber, + metricsProvider metrics.Provider, + tracerProvider trace.TracerProvider, + drivers []driver3.NamedDriver, + networkConfigProvider driver.NetworkConfigProvider, + listenerManagerProvider driver.ListenerManagerProvider, +) (*ONSProvider, error) { provider := &ONSProvider{ configService: configService, config: config, - kvss: kvss, + endorseTxKVS: endorseTxKVS, + metadataKVS: metadataKVS, + envelopeKVS: envelopeKVS, publisher: publisher, subscriber: subscriber, networks: map[string]driver.OrionNetworkService{}, @@ -129,5 +145,5 @@ func (p *ONSProvider) newONS(network string) (driver.OrionNetworkService, error) return nil, err } - return generic.NewNetwork(p.ctx, p.kvss, p.publisher, p.subscriber, p.metricsProvider, p.tracerProvider, c, network, p.drivers, networkConfig, p.listenerManagerProvider.NewManager()) + return generic.NewNetwork(p.ctx, p.endorseTxKVS, p.metadataKVS, p.envelopeKVS, p.publisher, p.subscriber, p.metricsProvider, p.tracerProvider, c, network, p.drivers, networkConfig, p.listenerManagerProvider.NewManager()) } diff --git a/platform/orion/driver/kvs.go b/platform/orion/driver/kvs.go new file mode 100644 index 000000000..3bf87357a --- /dev/null +++ b/platform/orion/driver/kvs.go @@ -0,0 +1,26 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package driver + +import "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" + +type Key struct { + Network string + TxID driver.TxID +} + +type MetadataKVS interface { + driver.MetadataKVS[Key, TransientMap] +} + +type EnvelopeKVS interface { + driver.EnvelopeKVS[Key] +} + +type EndorseTxKVS interface { + driver.EndorseTxKVS[Key] +} diff --git a/platform/orion/sdk/dig/sdk.go b/platform/orion/sdk/dig/sdk.go index 31acad279..7ab29d8e2 100644 --- a/platform/orion/sdk/dig/sdk.go +++ b/platform/orion/sdk/dig/sdk.go @@ -21,12 +21,12 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/orion/core/generic" driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/orion/driver" finality2 "github.com/hyperledger-labs/fabric-smart-client/platform/orion/sdk/finality" + "github.com/hyperledger-labs/fabric-smart-client/platform/orion/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/view/driver" viewsdk "github.com/hyperledger-labs/fabric-smart-client/platform/view/sdk/dig" "github.com/hyperledger-labs/fabric-smart-client/platform/view/sdk/finality" driver3 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/events" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/metrics" "go.opentelemetry.io/otel/trace" "go.uber.org/dig" @@ -78,6 +78,9 @@ func (p *SDK) Install() error { p.Container().Provide(orion.NewNetworkServiceProvider), p.Container().Provide(digutils.Identity[*core.ONSProvider](), dig.As(new(driver2.OrionNetworkServiceProvider))), p.Container().Provide(finality2.NewHandler, dig.Group("finality-handlers")), + p.Container().Provide(kvs.NewMetadataKVS, dig.As(new(driver2.MetadataKVS))), + p.Container().Provide(kvs.NewEndorseTxKVS, dig.As(new(driver2.EndorseTxKVS))), + p.Container().Provide(kvs.NewEnvelopeKVS, dig.As(new(driver2.EnvelopeKVS))), ) if err != nil { return err @@ -154,7 +157,9 @@ func newNetworkConfigProvider() driver2.NetworkConfigProvider { func newOrionNetworkServiceProvider(in struct { dig.In - KVSS *kvs.KVS + EndorseTxKVS driver2.EndorseTxKVS + MetadataKVS driver2.MetadataKVS + EnvelopeKVS driver2.EnvelopeKVS Publisher events.Publisher Subscriber events.Subscriber ConfigService driver.ConfigService @@ -165,5 +170,5 @@ func newOrionNetworkServiceProvider(in struct { NetworkConfigProvider driver2.NetworkConfigProvider ListenerManagerProvider driver2.ListenerManagerProvider }) (*core.ONSProvider, error) { - return core.NewOrionNetworkServiceProvider(in.ConfigService, in.Config, in.KVSS, in.Publisher, in.Subscriber, in.MetricsProvider, in.TracerProvider, in.Drivers, in.NetworkConfigProvider, in.ListenerManagerProvider) + return core.NewOrionNetworkServiceProvider(in.ConfigService, in.Config, in.EndorseTxKVS, in.MetadataKVS, in.EnvelopeKVS, in.Publisher, in.Subscriber, in.MetricsProvider, in.TracerProvider, in.Drivers, in.NetworkConfigProvider, in.ListenerManagerProvider) } diff --git a/platform/orion/services/kvs/kvs.go b/platform/orion/services/kvs/kvs.go new file mode 100644 index 000000000..f7b9bccc0 --- /dev/null +++ b/platform/orion/services/kvs/kvs.go @@ -0,0 +1,28 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kvs + +import ( + "github.com/hyperledger-labs/fabric-smart-client/platform/orion/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" +) + +func NewMetadataKVS(kvss *kvs.KVS) driver.MetadataKVS { + return kvs.NewMetadataKVS[driver.Key, driver.TransientMap](kvss, keyMapper("metadata")) +} + +func NewEnvelopeKVS(kvss *kvs.KVS) driver.EnvelopeKVS { + return kvs.NewEnvelopeKVS[driver.Key](kvss, keyMapper("envelope")) +} + +func NewEndorseTxKVS(kvss *kvs.KVS) driver.EndorseTxKVS { + return kvs.NewEndorseTxKVS[driver.Key](kvss, keyMapper("etx")) +} + +func keyMapper(prefix string) kvs.KeyMapper[driver.Key] { + return func(k driver.Key) (string, error) { return kvs.CreateCompositeKey(prefix, []string{k.Network, k.TxID}) } +} diff --git a/platform/view/core/endpoint/endpoint.go b/platform/view/core/endpoint/endpoint.go index 7176a1778..8f4f85439 100644 --- a/platform/view/core/endpoint/endpoint.go +++ b/platform/view/core/endpoint/endpoint.go @@ -13,9 +13,9 @@ import ( "strings" "sync" + driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" "github.com/hyperledger-labs/fabric-smart-client/platform/view/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs" "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" "github.com/pkg/errors" "go.uber.org/zap/zapcore" @@ -55,16 +55,10 @@ type Discovery interface { Peers() []NetworkMember } -type KVS interface { - Exists(id string) bool - Put(id string, state interface{}) error - Get(id string, state interface{}) error -} - type Service struct { resolvers []*Resolver resolversMutex sync.RWMutex - kvs KVS + bindingKVS driver2.BindingKVS pkiExtractorsLock sync.RWMutex publicKeyExtractors []driver.PublicKeyExtractor @@ -72,9 +66,9 @@ type Service struct { } // NewService returns a new instance of the view-sdk endpoint service -func NewService(kvs KVS) (*Service, error) { +func NewService(bindingKVS driver2.BindingKVS) (*Service, error) { er := &Service{ - kvs: kvs, + bindingKVS: bindingKVS, publicKeyExtractors: []driver.PublicKeyExtractor{}, publicKeyIDSynthesizer: DefaultPublicKeyIDSynthesizer{}, } @@ -104,7 +98,7 @@ func (r *Service) resolve(party view.Identity) (view.Identity, map[driver.PortNa return cursor, e, resolver, nil } logger.Debugf("resolving via binding for %s", cursor) - cursor, err = r.getBinding(cursor) + cursor, err = r.bindingKVS.GetBinding(cursor) if err != nil { return nil, nil, nil, err } @@ -120,7 +114,7 @@ func (r *Service) Bind(longTerm view.Identity, ephemeral view.Identity) error { logger.Debugf("bind [%s] to [%s]", ephemeral, longTerm) - if err := r.putBinding(ephemeral, longTerm); err != nil { + if err := r.bindingKVS.PutBinding(ephemeral, longTerm); err != nil { return errors.WithMessagef(err, "failed storing binding of [%s] to [%s]", ephemeral.UniqueID(), longTerm.UniqueID()) } @@ -132,7 +126,7 @@ func (r *Service) IsBoundTo(a view.Identity, b view.Identity) bool { if a.Equal(b) { return true } - next, err := r.getBinding(a) + next, err := r.bindingKVS.GetBinding(a) if err != nil { return false } @@ -284,32 +278,6 @@ func (r *Service) rootEndpoint(party view.Identity) (*Resolver, map[driver.PortN return nil, nil, errors.Errorf("endpoint not found for identity %s", party.UniqueID()) } -func (r *Service) putBinding(ephemeral, longTerm view.Identity) error { - k := kvs.CreateCompositeKeyOrPanic( - "platform.fsc.endpoint.binding", - []string{ephemeral.UniqueID()}, - ) - if err := r.kvs.Put(k, longTerm); err != nil { - return err - } - return nil -} - -func (r *Service) getBinding(ephemeral view.Identity) (view.Identity, error) { - k := kvs.CreateCompositeKeyOrPanic( - "platform.fsc.endpoint.binding", - []string{ephemeral.UniqueID()}, - ) - if !r.kvs.Exists(k) { - return nil, errors.Errorf("binding not found for [%s]", ephemeral.UniqueID()) - } - longTerm := view.Identity{} - if err := r.kvs.Get(k, &longTerm); err != nil { - return nil, err - } - return longTerm, nil -} - var portNameMap = map[string]driver.PortName{ strings.ToLower(string(driver.ListenPort)): driver.ListenPort, strings.ToLower(string(driver.ViewPort)): driver.ViewPort, diff --git a/platform/view/core/endpoint/endpoint_test.go b/platform/view/core/endpoint/endpoint_test.go index a31719901..eb3208f62 100644 --- a/platform/view/core/endpoint/endpoint_test.go +++ b/platform/view/core/endpoint/endpoint_test.go @@ -16,15 +16,8 @@ import ( type mockKVS struct{} -func (k mockKVS) Exists(id string) bool { - return true -} -func (k mockKVS) Put(id string, state interface{}) error { - return nil -} -func (k mockKVS) Get(id string, state interface{}) error { - return nil -} +func (k mockKVS) GetBinding(ephemeral view.Identity) (view.Identity, error) { return nil, nil } +func (k mockKVS) PutBinding(ephemeral, longTerm view.Identity) error { return nil } type mockExtractor struct{} diff --git a/platform/view/sdk/dig/sdk.go b/platform/view/sdk/dig/sdk.go index d832aa772..f0d8f40b2 100644 --- a/platform/view/sdk/dig/sdk.go +++ b/platform/view/sdk/dig/sdk.go @@ -12,6 +12,7 @@ import ( "github.com/go-kit/log" "github.com/hyperledger-labs/fabric-smart-client/pkg/node" + driver4 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" dig2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/sdk/dig" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" sig2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/sig" @@ -102,8 +103,10 @@ func (p *SDK) Install() error { p.C.Provide(sig2.NewDeserializer), p.C.Provide(sig2.NewService, dig.As(new(id.SigService), new(driver.SigService), new(driver.SigRegistry), new(driver.AuditRegistry))), p.C.Provide(view.NewSigService, dig.As(new(view3.VerifierProvider), new(view3.SignerProvider))), - p.C.Provide(digutils.Identity[*kvs.KVS](), dig.As(new(sig2.KVS))), - p.C.Provide(func(defaultKVS *kvs.KVS) (*endpoint.Service, error) { return endpoint.NewService(defaultKVS) }), + p.C.Provide(kvs.NewBindingKVS, dig.As(new(driver4.BindingKVS))), + p.C.Provide(kvs.NewSignerKVS, dig.As(new(driver4.SignerKVS))), + p.C.Provide(kvs.NewAuditInfoKVS, dig.As(new(driver4.AuditInfoKVS))), + p.C.Provide(endpoint.NewService), p.C.Provide(digutils.Identity[*endpoint.Service](), dig.As(new(driver.EndpointService))), p.C.Provide(view.NewEndpointService), p.C.Provide(digutils.Identity[*view.EndpointService](), dig.As(new(comm.EndpointService), new(id.EndpointService), new(endpoint.Backend))), diff --git a/platform/view/services/kvs/enhanced.go b/platform/view/services/kvs/enhanced.go new file mode 100644 index 000000000..70d0a0497 --- /dev/null +++ b/platform/view/services/kvs/enhanced.go @@ -0,0 +1,75 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kvs + +import "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils" + +type KeyMapper[K any] func(K) (string, error) + +func newEnhancedKVS[K any, V any](kvs *KVS, keyMapper KeyMapper[K]) *enhancedKVS[K, V] { + return &enhancedKVS[K, V]{ + kvs: kvs, + keyMapper: keyMapper, + } +} + +type enhancedKVS[K any, V any] struct { + kvs *KVS + keyMapper KeyMapper[K] +} + +func (kvs *enhancedKVS[K, V]) Get(id K) (V, error) { + k, err := kvs.keyMapper(id) + if err != nil { + return utils.Zero[V](), err + } + + if !kvs.kvs.Exists(k) { + return utils.Zero[V](), nil + } + var res V + if err := kvs.kvs.Get(k, &res); err != nil { + return utils.Zero[V](), err + } + return res, nil +} + +func (kvs *enhancedKVS[K, V]) FilterExisting(inputKeys ...K) ([]K, error) { + stringKeyMap := make(map[string]K, len(inputKeys)) + inputStrings := make([]string, len(inputKeys)) + for i, key := range inputKeys { + k, err := kvs.keyMapper(key) + if err != nil { + return nil, err + } + inputStrings[i] = k + stringKeyMap[k] = key + } + existingStrings := kvs.kvs.GetExisting(inputStrings...) + existingKeys := make([]K, len(existingStrings)) + for i, key := range existingStrings { + existingKeys[i] = stringKeyMap[key] + } + return existingKeys, nil +} + +func (kvs *enhancedKVS[K, V]) Exists(id K) (bool, error) { + k, err := kvs.keyMapper(id) + if err != nil { + return false, err + } + + return kvs.kvs.Exists(k), nil +} + +func (kvs *enhancedKVS[K, V]) Put(id K, info V) error { + k, err := kvs.keyMapper(id) + if err != nil { + return err + } + return kvs.kvs.Put(k, info) +} diff --git a/platform/view/services/kvs/scope.go b/platform/view/services/kvs/scope.go new file mode 100644 index 000000000..366a3afb4 --- /dev/null +++ b/platform/view/services/kvs/scope.go @@ -0,0 +1,114 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kvs + +import ( + "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/sig" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" +) + +// Signer + +func NewSignerKVS(kvs *KVS) *signerKVS { + return &signerKVS{e: newEnhancedKVS[view.Identity, *sig.SignerEntry](kvs, signerKey)} +} + +func signerKey(id view.Identity) (string, error) { + return CreateCompositeKey("sigService", []string{"signer", id.UniqueID()}) +} + +type signerKVS struct { + e *enhancedKVS[view.Identity, *sig.SignerEntry] +} + +func (kvs *signerKVS) GetSigner(id view.Identity) (*sig.SignerEntry, error) { return kvs.e.Get(id) } +func (kvs *signerKVS) FilterExistingSigners(ids ...view.Identity) ([]view.Identity, error) { + return kvs.e.FilterExisting(ids...) +} +func (kvs *signerKVS) PutSigner(id view.Identity, entry *sig.SignerEntry) error { + return kvs.e.Put(id, entry) +} + +// Audit info + +func NewAuditInfoKVS(kvs *KVS) *auditInfoKVS { + return &auditInfoKVS{e: newEnhancedKVS[view.Identity, []byte](kvs, auditInfoKey)} +} + +func auditInfoKey(id view.Identity) (string, error) { + return CreateCompositeKey("fsc.platform.view.sig", []string{id.UniqueID()}) +} + +type auditInfoKVS struct { + e *enhancedKVS[view.Identity, []byte] +} + +func (kvs *auditInfoKVS) GetAuditInfo(id view.Identity) ([]byte, error) { return kvs.e.Get(id) } +func (kvs *auditInfoKVS) PutAuditInfo(id view.Identity, info []byte) error { + return kvs.e.Put(id, info) +} + +// Binding + +func NewBindingKVS(kvs *KVS) *bindingKVS { + return &bindingKVS{e: newEnhancedKVS[view.Identity, view.Identity](kvs, bindingKey)} +} + +type bindingKVS struct { + e *enhancedKVS[view.Identity, view.Identity] +} + +func (kvs *bindingKVS) GetBinding(ephemeral view.Identity) (view.Identity, error) { + return kvs.e.Get(ephemeral) +} +func (kvs *bindingKVS) PutBinding(ephemeral, longTerm view.Identity) error { + return kvs.e.Put(ephemeral, longTerm) +} + +func bindingKey(ephemeral view.Identity) (string, error) { + return CreateCompositeKey("platform.fsc.endpoint.binding", []string{ephemeral.UniqueID()}) +} + +func NewMetadataKVS[K any, M any](kvss *KVS, keyMapper KeyMapper[K]) *metadataKVS[K, M] { + return &metadataKVS[K, M]{e: newEnhancedKVS[K, M](kvss, keyMapper)} +} + +type metadataKVS[K any, M any] struct { + e *enhancedKVS[K, M] +} + +func (kvs *metadataKVS[K, M]) GetMetadata(key K) (M, error) { + return kvs.e.Get(key) +} +func (kvs *metadataKVS[K, M]) ExistMetadata(key K) (bool, error) { return kvs.e.Exists(key) } +func (kvs *metadataKVS[K, M]) PutMetadata(key K, tm M) error { + return kvs.e.Put(key, tm) +} + +func NewEnvelopeKVS[K any](kvss *KVS, keyMapper KeyMapper[K]) *envelopeKVS[K] { + return &envelopeKVS[K]{e: newEnhancedKVS[K, []byte](kvss, keyMapper)} +} + +type envelopeKVS[K any] struct { + e *enhancedKVS[K, []byte] +} + +func (kvs *envelopeKVS[K]) GetEnvelope(key K) ([]byte, error) { return kvs.e.Get(key) } +func (kvs *envelopeKVS[K]) ExistsEnvelope(key K) (bool, error) { return kvs.e.Exists(key) } +func (kvs *envelopeKVS[K]) PutEnvelope(key K, env []byte) error { return kvs.e.Put(key, env) } + +func NewEndorseTxKVS[K any](kvss *KVS, keyMapper KeyMapper[K]) *endorseTxKVS[K] { + return &endorseTxKVS[K]{e: newEnhancedKVS[K, []byte](kvss, keyMapper)} +} + +type endorseTxKVS[K any] struct { + e *enhancedKVS[K, []byte] +} + +func (kvs *endorseTxKVS[K]) GetEndorseTx(key K) ([]byte, error) { return kvs.e.Get(key) } +func (kvs *endorseTxKVS[K]) ExistsEndorseTx(key K) (bool, error) { return kvs.e.Exists(key) } +func (kvs *endorseTxKVS[K]) PutEndorseTx(key K, etx []byte) error { return kvs.e.Put(key, etx) }