Skip to content

Commit 095c68d

Browse files
authored
token selector: streamline filter interfaces (#637)
Signed-off-by: Angelo De Caro <[email protected]>
1 parent a4be7c0 commit 095c68d

File tree

2 files changed

+3
-185
lines changed

2 files changed

+3
-185
lines changed

token/selector.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ var (
2929
type OwnerFilter interface {
3030
// ID is the wallet identifier of the owner
3131
ID() string
32-
// ContainsToken returns true if the passed token is recognized, false otherwise.
33-
ContainsToken(token *token2.UnspentToken) bool
3432
}
3533

3634
// Selector is the interface of token selectors

token/services/selector/simple/selector.go

Lines changed: 3 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111

1212
"github.com/hashicorp/go-uuid"
1313
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/tracing"
14-
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
1514
"github.com/hyperledger-labs/fabric-token-sdk/token"
1615
"github.com/hyperledger-labs/fabric-token-sdk/token/driver"
1716
token2 "github.com/hyperledger-labs/fabric-token-sdk/token/token"
@@ -51,15 +50,10 @@ type selector struct {
5150

5251
// Select selects tokens to be spent based on ownership, quantity, and type
5352
func (s *selector) Select(ownerFilter token.OwnerFilter, q, tokenType string) ([]*token2.ID, token2.Quantity, error) {
54-
if ownerFilter == nil {
55-
ownerFilter = &allOwners{}
53+
if ownerFilter == nil || len(ownerFilter.ID()) == 0 {
54+
return nil, nil, errors.Errorf("no owner filter specified")
5655
}
57-
58-
if len(ownerFilter.ID()) != 0 {
59-
return s.selectByID(ownerFilter, q, tokenType)
60-
}
61-
62-
return s.selectByOwner(ownerFilter, q, tokenType)
56+
return s.selectByID(ownerFilter, q, tokenType)
6357
}
6458

6559
func (s *selector) concurrencyCheck(ids []*token2.ID) error {
@@ -78,7 +72,6 @@ func (s *selector) selectByID(ownerFilter token.OwnerFilter, q string, tokenType
7872
var toBeSpent []*token2.ID
7973
var sum token2.Quantity
8074
var potentialSumWithLocked token2.Quantity
81-
var potentialSumWithNonCertified token2.Quantity
8275
target, err := token2.ToQuantity(q, s.precision)
8376
if err != nil {
8477
return nil, nil, errors.Wrap(err, "failed to convert quantity")
@@ -106,7 +99,6 @@ func (s *selector) selectByID(ownerFilter token.OwnerFilter, q string, tokenType
10699
// First select only certified
107100
sum = token2.NewZeroQuantity(s.precision)
108101
potentialSumWithLocked = token2.NewZeroQuantity(s.precision)
109-
potentialSumWithNonCertified = token2.NewZeroQuantity(s.precision)
110102
toBeSpent = nil
111103
var toBeCertified []*token2.ID
112104

@@ -144,155 +136,6 @@ func (s *selector) selectByID(ownerFilter token.OwnerFilter, q string, tokenType
144136
toBeSpent = append(toBeSpent, t.Id)
145137
sum = sum.Add(q)
146138
potentialSumWithLocked = potentialSumWithLocked.Add(q)
147-
potentialSumWithNonCertified = potentialSumWithNonCertified.Add(q)
148-
149-
if target.Cmp(sum) <= 0 {
150-
break
151-
}
152-
}
153-
154-
concurrencyIssue := false
155-
if target.Cmp(sum) <= 0 {
156-
err := s.concurrencyCheck(toBeSpent)
157-
if err == nil {
158-
return toBeSpent, sum, nil
159-
}
160-
concurrencyIssue = true
161-
logger.Errorf("concurrency issue, some of the tokens might not exist anymore [%s]", err)
162-
}
163-
164-
// Unlock and check the conditions for a retry
165-
s.locker.UnlockIDs(toBeSpent...)
166-
s.locker.UnlockIDs(toBeCertified...)
167-
168-
if target.Cmp(potentialSumWithLocked) <= 0 && potentialSumWithLocked.Cmp(sum) != 0 {
169-
// funds are potentially enough but they are locked
170-
logger.Debugf("token selection: sufficient funds but partially locked")
171-
}
172-
if target.Cmp(potentialSumWithNonCertified) <= 0 && potentialSumWithNonCertified.Cmp(sum) != 0 {
173-
// funds are potentially enough but they are locked
174-
logger.Debugf("token selection: sufficient funds but partially not certified")
175-
}
176-
177-
i++
178-
if i >= s.numRetry {
179-
// it is time to fail but how?
180-
if concurrencyIssue {
181-
logger.Debugf("concurrency issue, some of the tokens might not exist anymore")
182-
return nil, nil, errors.WithMessagef(
183-
token.SelectorSufficientFundsButConcurrencyIssue,
184-
"token selection failed: sufficient funs but concurrency issue, potential [%s] tokens of type [%s] were available", potentialSumWithLocked, tokenType,
185-
)
186-
}
187-
188-
if target.Cmp(potentialSumWithLocked) <= 0 && potentialSumWithLocked.Cmp(sum) != 0 {
189-
// funds are potentially enough but they are locked
190-
logger.Debugf("token selection: it is time to fail but how, sufficient funds but locked")
191-
return nil, nil, errors.WithMessagef(
192-
token.SelectorSufficientButLockedFunds,
193-
"token selection failed: sufficient but partially locked funds, potential [%s] tokens of type [%s] are available", potentialSumWithLocked.Decimal(), tokenType,
194-
)
195-
}
196-
197-
if target.Cmp(potentialSumWithNonCertified) <= 0 && potentialSumWithNonCertified.Cmp(sum) != 0 {
198-
// funds are potentially enough but they are locked
199-
logger.Debugf("token selection: it is time to fail but how, sufficient funds but locked")
200-
return nil, nil, errors.WithMessagef(
201-
token.SelectorSufficientButNotCertifiedFunds,
202-
"token selection failed: sufficient but partially not certified, potential [%s] tokens of type [%s] are available", potentialSumWithNonCertified, tokenType,
203-
)
204-
}
205-
206-
// funds are insufficient
207-
logger.Debugf("token selection: it is time to fail but how, insufficient funds")
208-
return nil, nil, errors.WithMessagef(
209-
token.SelectorInsufficientFunds,
210-
"token selection failed: insufficient funds, only [%s] tokens of type [%s] are available", sum.Decimal(), tokenType,
211-
)
212-
}
213-
214-
logger.Debugf("token selection: let's wait [%v] before retry...", s.timeout)
215-
time.Sleep(s.timeout)
216-
}
217-
}
218-
219-
func (s *selector) selectByOwner(ownerFilter token.OwnerFilter, q string, tokenType string) ([]*token2.ID, token2.Quantity, error) {
220-
var toBeSpent []*token2.ID
221-
var sum token2.Quantity
222-
var potentialSumWithLocked token2.Quantity
223-
var potentialSumWithNonCertified token2.Quantity
224-
target, err := token2.ToQuantity(q, s.precision)
225-
if err != nil {
226-
return nil, nil, errors.Wrap(err, "failed to convert quantity")
227-
}
228-
229-
i := 0
230-
for {
231-
logger.Debugf("start token selection, iteration [%d/%d]", i, s.numRetry)
232-
unspentTokens, err := s.queryService.UnspentTokensIterator()
233-
if err != nil {
234-
return nil, nil, errors.Wrap(err, "token selection failed")
235-
}
236-
defer unspentTokens.Close()
237-
logger.Debugf("select token for a quantity of [%s] of type [%s]", q, tokenType)
238-
239-
// First select only certified
240-
sum = token2.NewZeroQuantity(s.precision)
241-
potentialSumWithLocked = token2.NewZeroQuantity(s.precision)
242-
potentialSumWithNonCertified = token2.NewZeroQuantity(s.precision)
243-
toBeSpent = nil
244-
var toBeCertified []*token2.ID
245-
246-
reclaim := s.numRetry == 1 || i > 0
247-
for {
248-
t, err := unspentTokens.Next()
249-
if err != nil {
250-
return nil, nil, errors.Wrap(err, "token selection failed")
251-
}
252-
if t == nil {
253-
break
254-
}
255-
256-
q, err := token2.ToQuantity(t.Quantity, s.precision)
257-
if err != nil {
258-
s.locker.UnlockIDs(toBeSpent...)
259-
s.locker.UnlockIDs(toBeCertified...)
260-
return nil, nil, errors.Wrap(err, "failed to convert quantity")
261-
}
262-
263-
// check type and ownership
264-
if t.Type != tokenType {
265-
if logger.IsEnabledFor(zapcore.DebugLevel) {
266-
logger.Debugf("token [%s,%s] type does not match", q, tokenType)
267-
}
268-
continue
269-
}
270-
271-
rightOwner := ownerFilter.ContainsToken(t)
272-
273-
if !rightOwner {
274-
if logger.IsEnabledFor(zapcore.DebugLevel) {
275-
logger.Debugf("token [%s,%s,%s,%v] owner does not belong to the passed wallet", view.Identity(t.Owner.Raw), q, tokenType, rightOwner)
276-
}
277-
continue
278-
}
279-
280-
// lock the token
281-
if _, err := s.locker.Lock(t.Id, s.txID, reclaim); err != nil {
282-
potentialSumWithLocked = potentialSumWithLocked.Add(q)
283-
284-
if logger.IsEnabledFor(zapcore.DebugLevel) {
285-
logger.Debugf("token [%s,%s,%v] cannot be locked [%s]", q, tokenType, rightOwner, err)
286-
}
287-
continue
288-
}
289-
290-
// Append token
291-
logger.Debugf("adding quantity [%s]", q.Decimal())
292-
toBeSpent = append(toBeSpent, t.Id)
293-
sum = sum.Add(q)
294-
potentialSumWithLocked = potentialSumWithLocked.Add(q)
295-
potentialSumWithNonCertified = potentialSumWithNonCertified.Add(q)
296139

297140
if target.Cmp(sum) <= 0 {
298141
break
@@ -317,10 +160,6 @@ func (s *selector) selectByOwner(ownerFilter token.OwnerFilter, q string, tokenT
317160
// funds are potentially enough but they are locked
318161
logger.Debugf("token selection: sufficient funds but partially locked")
319162
}
320-
if target.Cmp(potentialSumWithNonCertified) <= 0 && potentialSumWithNonCertified.Cmp(sum) != 0 {
321-
// funds are potentially enough but they are locked
322-
logger.Debugf("token selection: sufficient funds but partially not certified")
323-
}
324163

325164
i++
326165
if i >= s.numRetry {
@@ -342,15 +181,6 @@ func (s *selector) selectByOwner(ownerFilter token.OwnerFilter, q string, tokenT
342181
)
343182
}
344183

345-
if target.Cmp(potentialSumWithNonCertified) <= 0 && potentialSumWithNonCertified.Cmp(sum) != 0 {
346-
// funds are potentially enough but they are locked
347-
logger.Debugf("token selection: it is time to fail but how, sufficient funds but locked")
348-
return nil, nil, errors.WithMessagef(
349-
token.SelectorSufficientButNotCertifiedFunds,
350-
"token selection failed: sufficient but partially not certified, potential [%s] tokens of type [%s] are available", potentialSumWithNonCertified, tokenType,
351-
)
352-
}
353-
354184
// funds are insufficient
355185
logger.Debugf("token selection: it is time to fail but how, insufficient funds")
356186
return nil, nil, errors.WithMessagef(
@@ -363,13 +193,3 @@ func (s *selector) selectByOwner(ownerFilter token.OwnerFilter, q string, tokenT
363193
time.Sleep(s.timeout)
364194
}
365195
}
366-
367-
type allOwners struct{}
368-
369-
func (a *allOwners) ID() string {
370-
return ""
371-
}
372-
373-
func (a *allOwners) ContainsToken(token *token2.UnspentToken) bool {
374-
return true
375-
}

0 commit comments

Comments
 (0)