Skip to content

Commit 2891d57

Browse files
committed
fix(ttx): bind before send on recipient views; remove unused isMeCache
Responder flows now call endpoint.Bind before session.Send so a local bind failure does not leave the peer with RecipientData we never wired locally. identity.Provider: drop isMeCache/no-cache bookkeeping (always a no-op in practice). AreMe uses signer cache and storage only; skipping a real cache avoids incorrect entries for single-use identities (e.g. Idemix nyms). RegisterRecipientIdentity and RollbackPartialRecipientRegistration on Provider are documented no-ops for in-memory marks; the wallet rollback hook remains for other IdentityProvider implementations. RespondExchangeRecipientIdentitiesView passes TokenMetadataAuditInfo through RegisterRecipientIdentity for the initiator RecipientData carried in the exchange request. Update TTX service diagrams to match ordering. Signed-off-by: SuyashAlphaC <suyashagrawal862@gmail.com>
1 parent 552acd8 commit 2891d57

3 files changed

Lines changed: 42 additions & 69 deletions

File tree

docs/services/ttx.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,21 +100,21 @@ sequenceDiagram
100100
end
101101
102102
rect rgba(255, 245, 238, 0.5)
103-
Note over R: Phase 2 - Responder decision
103+
Note over R: Phase 2 - Responder decision and reply
104104
alt RecipientRequest.RecipientData != nil
105105
R->>R: Verify wallet contains RecipientData.Identity
106-
R-->>I: RecipientData (echo path)
107106
else RecipientRequest.RecipientData == nil
108107
R->>R: Generate RecipientData from wallet
109-
R-->>I: RecipientData (fresh data path)
110108
end
109+
R->>R: endpoint.Bind(context.Me, RecipientData.Identity)
110+
Note over R,I: Bind before send so local resolver wiring fails before the peer receives RecipientData
111+
R-->>I: RecipientData (echo or fresh data path)
111112
end
112113
113114
rect rgba(240, 255, 240, 0.45)
114-
Note over I,R: Phase 3 - Local registration and bindings
115+
Note over I,R: Phase 3 - Initiator registration and bindings
115116
I->>I: RegisterRecipientIdentity(RecipientData)
116117
I->>I: endpoint.Bind(requested FSC identity, RecipientData.Identity)
117-
R->>R: endpoint.Bind(context.Me, RecipientData.Identity)
118118
end
119119
120120
rect rgba(245, 245, 245, 0.55)
@@ -146,14 +146,16 @@ sequenceDiagram
146146
Note over R: Phase 2 - Responder processing
147147
R->>R: RegisterRecipientIdentity(request.RecipientData)
148148
R->>R: GetRecipientData(responder wallet)
149+
R->>R: endpoint.Bind(context.Me, responder RecipientData.Identity)
150+
R->>R: endpoint.Bind(session caller, request.RecipientData.Identity)
151+
Note over R,I: Binds before send so resolver wiring fails before the initiator receives our RecipientData
149152
R-->>I: RecipientData(responder)
150153
end
151154
152155
rect rgba(240, 255, 240, 0.45)
153-
Note over I,R: Phase 3 - Local registration and bindings
156+
Note over I,R: Phase 3 - Initiator registration and bindings
154157
I->>I: RegisterRecipientIdentity(remote RecipientData)
155158
I->>I: endpoint.Bind(other FSC identity, remote RecipientData.Identity)
156-
R->>R: endpoint.Bind(session caller, request.RecipientData.Identity)
157159
end
158160
159161
Note over I,R: Full RecipientData on wire today (responder sends local wallet RecipientData)

token/services/identity/provider.go

Lines changed: 11 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@ package identity
99
import (
1010
"context"
1111
"runtime/debug"
12-
"slices"
1312

1413
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
1514
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/cache/secondcache"
1615
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections"
1716
"github.com/hyperledger-labs/fabric-token-sdk/token/driver"
1817
idriver "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/driver"
1918
"github.com/hyperledger-labs/fabric-token-sdk/token/services/logging"
20-
cache2 "github.com/hyperledger-labs/fabric-token-sdk/token/services/utils/cache"
2119
"go.uber.org/zap/zapcore"
2220
)
2321

@@ -87,8 +85,7 @@ type Provider struct {
8785
storage Storage
8886
deserializer Deserializer
8987

90-
isMeCache cache[bool]
91-
signers cache[*SignerEntry]
88+
signers cache[*SignerEntry]
9289
}
9390

9491
// NewProvider returns a new instance of Provider
@@ -105,7 +102,6 @@ func NewProvider(
105102
enrollmentIDUnmarshaler: enrollmentIDUnmarshaler,
106103
deserializer: deserializer,
107104
storage: storage,
108-
isMeCache: cache2.NewNoCache[bool](),
109105
signers: secondcache.NewTyped[*SignerEntry](50),
110106
}
111107
}
@@ -132,32 +128,13 @@ func (p *Provider) RegisterSigner(ctx context.Context, identity driver.Identity,
132128
}
133129

134130
// AreMe returns the hashes of the passed identities that have a signer registered before.
135-
// First a local cache is checked, if not found the configured storag is queried.
131+
// Each identity is resolved via the signer cache and configured storage.
132+
// There is no secondary "is me" cache: a real cache would need careful handling for
133+
// single-use identities (for example Idemix nyms) and is intentionally omitted here.
136134
func (p *Provider) AreMe(ctx context.Context, identities ...driver.Identity) []string {
137135
p.Logger.DebugfContext(ctx, "identity [%s] is me?", identities)
138136

139-
result := make([]string, 0)
140-
notFound := make([]driver.Identity, 0)
141-
142-
for _, id := range identities {
143-
uniqueID := id.UniqueID()
144-
if isMe, ok := p.isMeCache.Get(uniqueID); !ok {
145-
notFound = append(notFound, id)
146-
} else if isMe {
147-
result = append(result, uniqueID)
148-
}
149-
}
150-
if len(notFound) == 0 {
151-
return result
152-
}
153-
154-
found := p.areMe(ctx, notFound...)
155-
for _, id := range notFound {
156-
uniqueID := id.UniqueID()
157-
p.isMeCache.Add(uniqueID, slices.Contains(found, uniqueID))
158-
}
159-
160-
return append(result, found...)
137+
return p.areMe(ctx, identities...)
161138
}
162139

163140
// IsMe returns true if a signer was ever registered for the passed identity
@@ -177,16 +154,11 @@ func (p *Provider) GetAuditInfo(ctx context.Context, identity driver.Identity) (
177154
// If a signer is not found in cache,
178155
// this provider tries to construct an instance of driver.Signer that produces valid signatures under that identity.
179156
func (p *Provider) GetSigner(ctx context.Context, identity driver.Identity) (driver.Signer, error) {
180-
found := false
181157
idHash := identity.UniqueID()
182-
defer func() {
183-
p.isMeCache.Add(idHash, found)
184-
}()
185158
signer, err := p.getSigner(ctx, identity, idHash)
186159
if err != nil {
187160
return nil, errors.Wrapf(err, "failed to get signer for identity [%s], it is neither register nor deserialazable", identity.String())
188161
}
189-
found = true
190162

191163
return signer, nil
192164
}
@@ -221,19 +193,19 @@ func (p *Provider) Bind(ctx context.Context, longTerm driver.Identity, ephemeral
221193
return nil
222194
}
223195

224-
// RegisterRecipientIdentity register the passed identity as a third-party recipient identity.
196+
// RegisterRecipientIdentity registers the passed identity as a third-party recipient identity.
197+
// The wallet layer performs matching and persistence; this provider records nothing here.
225198
func (p *Provider) RegisterRecipientIdentity(ctx context.Context, id driver.Identity) error {
226199
p.Logger.DebugfContext(ctx, "Registering identity [%s]", id)
227-
p.isMeCache.Add(id.UniqueID(), false)
228200

229201
return nil
230202
}
231203

232-
// RollbackPartialRecipientRegistration clears in-memory marks written by
233-
// RegisterRecipientIdentity when RegisterRecipientData did not complete.
204+
// RollbackPartialRecipientRegistration implements RecipientRegistrationRollback.
205+
// This provider does not keep partial recipient-registration marks in memory;
206+
// the hook remains for other IdentityProvider implementations.
234207
func (p *Provider) RollbackPartialRecipientRegistration(ctx context.Context, id driver.Identity) {
235-
p.Logger.DebugfContext(ctx, "rolling back partial recipient registration for identity [%s]", id)
236-
p.isMeCache.Delete(id.UniqueID())
208+
p.Logger.DebugfContext(ctx, "rollback partial recipient registration for identity [%s] (no-op for this provider)", id)
237209
}
238210

239211
// RegisterIdentityDescriptor stores the given identity descriptor in the configured storage.
@@ -360,9 +332,6 @@ func (p *Provider) updateCaches(descriptor *idriver.IdentityDescriptor, alias dr
360332

361333
// signers
362334
if descriptor.Signer != nil {
363-
// if the signer is set, this means that id belongs to this node
364-
p.isMeCache.Add(id, true)
365-
366335
entry := &SignerEntry{Signer: descriptor.Signer}
367336
if p.Logger.IsEnabledFor(zapcore.DebugLevel) {
368337
entry.DebugStack = debug.Stack()

token/services/ttx/recipients.go

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -359,21 +359,21 @@ func (s *RespondRequestRecipientIdentityView) Call(context view.Context) (interf
359359
recipientIdentity = recipientData.Identity
360360
}
361361

362-
// Step 3: send the public key back to the invoker
363-
logger.DebugfContext(context.Context(), "Send recipient identity response to %s", session.Info().Caller)
364-
if err := session.Send(recipientData); err != nil {
365-
return nil, errors.Wrapf(err, "failed to send recipient data")
366-
}
367-
368-
// Update the Endpoint Resolver
362+
// Update the endpoint resolver before sending so a local bind failure does not
363+
// leave the peer with a RecipientData we never successfully wired locally.
369364
resolver := endpoint.GetService(context)
370365
logger.DebugfContext(context.Context(), "bind me [%s] to [%s]", context.Me(), recipientData)
371366

372-
err = resolver.Bind(context.Context(), context.Me(), recipientIdentity)
373-
if err != nil {
367+
if err := resolver.Bind(context.Context(), context.Me(), recipientIdentity); err != nil {
374368
return nil, errors.Wrapf(err, "failed to bind me to recipient identity")
375369
}
376370

371+
// Step 3: send the public key back to the invoker
372+
logger.DebugfContext(context.Context(), "Send recipient identity response to %s", session.Info().Caller)
373+
if err := session.Send(recipientData); err != nil {
374+
return nil, errors.Wrapf(err, "failed to send recipient data")
375+
}
376+
377377
if err := s.handleMultisig(context, session.Session(), tms, recipientRequest, recipientIdentity); err != nil {
378378
return nil, errors.Wrapf(err, "failed to handle multisig")
379379
}
@@ -462,7 +462,7 @@ func (s *RespondRequestRecipientIdentityView) handleMultisig(
462462
for i, node := range multisigRecipientData.Nodes {
463463
err = resolver.Bind(context.Context(), node, multisigRecipientData.Recipients[i])
464464
if err != nil {
465-
return errors.Wrapf(err, "failed to bind me to recipient identity")
465+
return errors.Wrapf(err, "failed to bind node identity to recipient identity")
466466
}
467467
}
468468

@@ -602,7 +602,10 @@ func (s *RespondExchangeRecipientIdentitiesView) Call(context view.Context) (int
602602
}
603603
other := request.RecipientData.Identity
604604
if err := ts.WalletManager().RegisterRecipientIdentity(context.Context(), &RecipientData{
605-
Identity: other, AuditInfo: request.RecipientData.AuditInfo, TokenMetadata: request.RecipientData.TokenMetadata,
605+
Identity: other,
606+
AuditInfo: request.RecipientData.AuditInfo,
607+
TokenMetadata: request.RecipientData.TokenMetadata,
608+
TokenMetadataAuditInfo: request.RecipientData.TokenMetadataAuditInfo,
606609
}); err != nil {
607610
return nil, err
608611
}
@@ -622,21 +625,20 @@ func (s *RespondExchangeRecipientIdentitiesView) Call(context view.Context) (int
622625
return nil, errors.WithMessagef(err, "failed getting recipient data, wallet [%s]", w.ID())
623626
}
624627

625-
if err := session.Send(recipientData); err != nil {
626-
return nil, errors.WithMessagef(err, "failed sending recipient data, wallet [%s]", w.ID())
627-
}
628-
629-
// Update the Endpoint Resolver
628+
// Bind locally before sending so a bind failure does not leave the initiator
629+
// with our RecipientData while this node never finished resolver wiring.
630630
resolver := endpoint.GetService(context)
631-
err = resolver.Bind(context.Context(), context.Me(), recipientData.Identity)
632-
if err != nil {
631+
if err := resolver.Bind(context.Context(), context.Me(), recipientData.Identity); err != nil {
633632
return nil, errors.WithMessagef(err, "failed binding recipient data, wallet [%s]", w.ID())
634633
}
635-
err = resolver.Bind(context.Context(), session.Info().Caller, other)
636-
if err != nil {
634+
if err := resolver.Bind(context.Context(), session.Info().Caller, other); err != nil {
637635
return nil, errors.WithMessagef(err, "failed binding recipient data, wallet [%s]", w.ID())
638636
}
639637

638+
if err := session.Send(recipientData); err != nil {
639+
return nil, errors.WithMessagef(err, "failed sending recipient data, wallet [%s]", w.ID())
640+
}
641+
640642
return []token.Identity{recipientData.Identity, other}, nil
641643
}
642644

0 commit comments

Comments
 (0)