Skip to content

Commit 83744d4

Browse files
adecaroalexandrosfilios
authored andcommitted
clearly separate selection of tokens owned sololy by a single wallet from
selection of tokens whose ownership might be shared Signed-off-by: Angelo De Caro <[email protected]>
1 parent 48eea97 commit 83744d4

File tree

12 files changed

+125
-75
lines changed

12 files changed

+125
-75
lines changed

token/core/common/authrorization.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
type Authorization interface {
1717
// IsMine returns true if the passed token is owned by an owner wallet.
1818
// It returns the ID of the owner wallet and any additional owner identifier, if supported.
19-
// It is possible that the wallet ID is empty an the additional owner identifier list is not.
19+
// It is possible that the wallet ID is empty and the additional owner identifier list is not.
2020
IsMine(tok *token2.Token) (string, []string, bool)
2121
// AmIAnAuditor return true if the passed TMS contains an auditor wallet for any of the auditor identities
2222
// defined in the public parameters of the passed TMS.
@@ -44,7 +44,7 @@ func NewTMSAuthorization(publicParameters driver.PublicParameters, walletService
4444
}
4545

4646
// IsMine returns true if the passed token is owned by an owner wallet.
47-
// It returns the ID of the owner wallet and no additional owner identifiers
47+
// It returns the ID of the owner wallet and no additional owner identifiers.
4848
func (w *WalletBasedAuthorization) IsMine(tok *token2.Token) (string, []string, bool) {
4949
wallet, err := w.WalletService.OwnerWallet(tok.Owner.Raw)
5050
if err != nil {

token/driver/vault.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ type UnspentTokensIterator interface {
3737
Next() (*token.UnspentToken, error)
3838
}
3939

40-
type MinTokenInfoIterator interface {
40+
type SpendableTokensIterator interface {
4141
Close()
42-
Next() (*token.MinTokenInfo, error)
42+
Next() (*token.UnspentTokenInWallet, error)
4343
}
4444

4545
type Vault interface {
@@ -67,7 +67,7 @@ type QueryEngine interface {
6767
UnspentTokensIterator() (UnspentTokensIterator, error)
6868
// UnspentTokensIteratorBy returns an iterator of unspent tokens owned by the passed id and whose type is the passed on.
6969
// The token type can be empty. In that case, tokens of any type are returned.
70-
UnspentTokensIteratorBy(ctx context.Context, id, tokenType string) (UnspentTokensIterator, error)
70+
UnspentTokensIteratorBy(ctx context.Context, walletID, tokenType string) (UnspentTokensIterator, error)
7171
// ListUnspentTokens returns the list of unspent tokens
7272
ListUnspentTokens() (*token.UnspentTokens, error)
7373
// ListAuditTokens returns the audited tokens associated to the passed ids

token/driver/wallet.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,11 @@ type WalletLookupID = any
133133
// and wallets (owner, auditor, etc.)
134134
type Authorization interface {
135135
// IsMine returns true if the passed token is owned by an owner wallet.
136-
// It returns the ID of the owner wallet and any additional owner identifier, if supported.
137-
// It is possible that the wallet ID is empty an the additional owner identifier list is not.
138-
IsMine(tok *token.Token) (string, []string, bool)
136+
// It returns the ID of the owner wallet (walletID) and any additional owner identifier (additionalOwners), if supported.
137+
// It is possible that walletID is empty additionalOwners is not.
138+
// If walletID is not empty, this means that the corresponding wallet can spend the token directly.
139+
// If walletID is empty, then additionalOwners must cooperate in some way in order to spend the token.
140+
IsMine(tok *token.Token) (walletID string, additionalOwners []string, mine bool)
139141
// AmIAnAuditor return true if the passed TMS contains an auditor wallet for any of the auditor identities
140142
// defined in the public parameters of the passed TMS.
141143
AmIAnAuditor() bool

token/services/db/driver/token.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,12 @@ type TokenDB interface {
130130
IsMine(txID string, index uint64) (bool, error)
131131
// UnspentTokensIterator returns an iterator over all owned tokens
132132
UnspentTokensIterator() (driver.UnspentTokensIterator, error)
133-
// UnspentTokensIteratorBy returns an iterator over all tokens owned by the passed identifier of a given type
134-
UnspentTokensIteratorBy(ctx context.Context, id, tokenType string) (driver.UnspentTokensIterator, error)
135-
// MinTokenInfoIteratorBy returns the minimum information about the tokens needed for the selector
136-
MinTokenInfoIteratorBy(ctx context.Context, ownerEID string, typ string) (driver.MinTokenInfoIterator, error)
133+
// UnspentTokensIteratorBy returns an iterator over all tokens owned by the passed wallet identifier and of a given type
134+
UnspentTokensIteratorBy(ctx context.Context, walletID, tokenType string) (driver.UnspentTokensIterator, error)
135+
// SpendableTokensIteratorBy returns an iterator over all tokens owned solely by the passed wallet identifier and of a given type
136+
SpendableTokensIteratorBy(ctx context.Context, walletID string, typ string) (driver.SpendableTokensIterator, error)
137137
// ListUnspentTokensBy returns the list of all tokens owned by the passed identifier of a given type
138-
ListUnspentTokensBy(ownerEID, typ string) (*token.UnspentTokens, error)
138+
ListUnspentTokensBy(walletID, typ string) (*token.UnspentTokens, error)
139139
// ListUnspentTokens returns the list of all owned tokens
140140
ListUnspentTokens() (*token.UnspentTokens, error)
141141
// ListAuditTokens returns the audited tokens for the passed ids

token/services/db/sql/common/querybuilder.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ func tokenQuerySql(params driver.QueryTokenDetailsParams, tokenTable, ownerTable
154154
}
155155
if params.WalletID != "" {
156156
args = append(args, params.WalletID)
157-
and = append(and, fmt.Sprintf("wallet_id = $%d", len(args)))
157+
and = append(and, fmt.Sprintf("(wallet_id = $%d OR owner_wallet_id = $%d)", len(args), len(args)+1))
158+
args = append(args, params.WalletID)
158159
}
159160

160161
if params.TokenType != "" {
@@ -200,8 +201,7 @@ func tokenQuerySqlNoJoin(params driver.QueryTokenDetailsParams) (where string, a
200201
}
201202

202203
if len(params.TransactionIDs) > 0 {
203-
colTxID := "tx_id"
204-
and = append(and, in(&args, colTxID, params.TransactionIDs))
204+
and = append(and, in(&args, "tx_id", params.TransactionIDs))
205205
}
206206
if ids := whereTokenIDs(&args, params.IDs); ids != "" {
207207
and = append(and, ids)

token/services/db/sql/common/querybuilder_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -255,17 +255,17 @@ func TestTokenSql(t *testing.T) {
255255
{
256256
name: "owner unspent",
257257
params: driver.QueryTokenDetailsParams{WalletID: "me"},
258-
expectedSql: "WHERE owner = true AND wallet_id = $1 AND is_deleted = false",
259-
expectedArgs: []interface{}{"me"},
258+
expectedSql: "WHERE owner = true AND (wallet_id = $1 OR owner_wallet_id = $2) AND is_deleted = false",
259+
expectedArgs: []interface{}{"me", "me"},
260260
},
261261
{
262262
name: "owner with deleted",
263263
params: driver.QueryTokenDetailsParams{
264264
WalletID: "me",
265265
IncludeDeleted: true,
266266
},
267-
expectedSql: "WHERE owner = true AND wallet_id = $1",
268-
expectedArgs: []interface{}{"me"},
267+
expectedSql: "WHERE owner = true AND (wallet_id = $1 OR owner_wallet_id = $2)",
268+
expectedArgs: []interface{}{"me", "me"},
269269
},
270270
{
271271
name: "owner and htlc with deleted",
@@ -274,14 +274,14 @@ func TestTokenSql(t *testing.T) {
274274
OwnerType: "htlc",
275275
IncludeDeleted: true,
276276
},
277-
expectedSql: "WHERE owner = true AND owner_type = $1 AND wallet_id = $2",
278-
expectedArgs: []interface{}{"htlc", "me"},
277+
expectedSql: "WHERE owner = true AND owner_type = $1 AND (wallet_id = $2 OR owner_wallet_id = $3)",
278+
expectedArgs: []interface{}{"htlc", "me", "me"},
279279
},
280280
{
281281
name: "owner and type",
282282
params: driver.QueryTokenDetailsParams{TokenType: "tok", WalletID: "me"},
283-
expectedSql: "WHERE owner = true AND wallet_id = $1 AND token_type = $2 AND is_deleted = false",
284-
expectedArgs: []interface{}{"me", "tok"},
283+
expectedSql: "WHERE owner = true AND (wallet_id = $1 OR owner_wallet_id = $2) AND token_type = $3 AND is_deleted = false",
284+
expectedArgs: []interface{}{"me", "me", "tok"},
285285
},
286286
{
287287
name: "owner and type and id",
@@ -290,8 +290,8 @@ func TestTokenSql(t *testing.T) {
290290
WalletID: "me",
291291
IDs: []*token.ID{{TxId: "a", Index: 1}},
292292
},
293-
expectedSql: "WHERE owner = true AND wallet_id = $1 AND token_type = $2 AND (tx_id, idx) IN ( ($3, $4) ) AND is_deleted = false",
294-
expectedArgs: []interface{}{"me", "tok", "a", 1},
293+
expectedSql: "WHERE owner = true AND (wallet_id = $1 OR owner_wallet_id = $2) AND token_type = $3 AND (tx_id, idx) IN ( ($4, $5) ) AND is_deleted = false",
294+
expectedArgs: []interface{}{"me", "me", "tok", "a", 1},
295295
},
296296
{
297297
name: "type and ids",
@@ -316,9 +316,9 @@ func TestTokenSql(t *testing.T) {
316316
IDs: []*token.ID{{TxId: "a", Index: 1}},
317317
WalletID: "me",
318318
}, "A", "B")
319-
assert.Equal(t, "WHERE owner = true AND wallet_id = $1 AND (A.tx_id, A.idx) IN ( ($2, $3) ) AND is_deleted = false", where, "join")
319+
assert.Equal(t, "WHERE owner = true AND (wallet_id = $1 OR owner_wallet_id = $2) AND (A.tx_id, A.idx) IN ( ($3, $4) ) AND is_deleted = false", where, "join")
320320
assert.Equal(t, "LEFT JOIN B ON A.tx_id = B.tx_id AND A.idx = B.idx", join, "join")
321-
assert.Len(t, args, 3)
321+
assert.Len(t, args, 4)
322322
}
323323

324324
func TestTokenSqlNoJoin(t *testing.T) {

token/services/db/sql/common/test_cases.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,34 @@ func TSaveAndGetToken(t *testing.T, db *TokenDB) {
284284
assert.Len(t, unsp, 1)
285285
assert.Equal(t, "0x02", unsp[0].Quantity)
286286
assert.Equal(t, "ABC", unsp[0].Type)
287+
288+
tr = driver.TokenRecord{
289+
TxID: fmt.Sprintf("tx%d", 2000),
290+
Index: 0,
291+
IssuerRaw: []byte{},
292+
OwnerRaw: []byte{1, 2, 3},
293+
OwnerType: "idemix",
294+
OwnerIdentity: []byte{},
295+
OwnerWalletID: "pineapple",
296+
Ledger: []byte("ledger"),
297+
LedgerMetadata: []byte{},
298+
Quantity: "0x02",
299+
Type: "ABC",
300+
Amount: 2,
301+
Owner: true,
302+
Auditor: false,
303+
Issuer: false,
304+
}
305+
assert.NoError(t, db.StoreToken(tr, nil))
306+
_, err = db.GetTokens(&token.ID{TxId: fmt.Sprintf("tx%d", 2000), Index: 0})
307+
assert.NoError(t, err)
308+
309+
tx, err := db.NewTokenDBTransaction(context.TODO())
310+
assert.NoError(t, err)
311+
_, owners, err := tx.GetToken(context.TODO(), fmt.Sprintf("tx%d", 2000), 0, true)
312+
assert.NoError(t, err)
313+
assert.Len(t, owners, 1)
314+
assert.NoError(t, tx.Rollback())
287315
}
288316

289317
func getTokensBy(t *testing.T, db *TokenDB, ownerEID, typ string) []*token.UnspentToken {
@@ -391,6 +419,7 @@ func TListAuditTokens(t *testing.T, db *TokenDB) {
391419
OwnerRaw: []byte{1, 2},
392420
OwnerType: "idemix",
393421
OwnerIdentity: []byte{},
422+
OwnerWalletID: "idemix",
394423
Ledger: []byte("ledger"),
395424
LedgerMetadata: []byte{},
396425
Quantity: "0x01",
@@ -407,6 +436,7 @@ func TListAuditTokens(t *testing.T, db *TokenDB) {
407436
OwnerRaw: []byte{3, 4},
408437
OwnerType: "idemix",
409438
OwnerIdentity: []byte{},
439+
OwnerWalletID: "idemix",
410440
Ledger: []byte("ledger"),
411441
LedgerMetadata: []byte{},
412442
Quantity: "0x02",
@@ -423,6 +453,7 @@ func TListAuditTokens(t *testing.T, db *TokenDB) {
423453
OwnerRaw: []byte{5, 6},
424454
OwnerType: "idemix",
425455
OwnerIdentity: []byte{},
456+
OwnerWalletID: "idemix",
426457
Ledger: []byte("ledger"),
427458
LedgerMetadata: []byte{},
428459
Quantity: "0x03",
@@ -460,6 +491,7 @@ func TListIssuedTokens(t *testing.T, db *TokenDB) {
460491
OwnerRaw: []byte{1, 2},
461492
OwnerType: "idemix",
462493
OwnerIdentity: []byte{},
494+
OwnerWalletID: "idemix",
463495
IssuerRaw: []byte{11, 12},
464496
Ledger: []byte("ledger"),
465497
LedgerMetadata: []byte{},
@@ -477,6 +509,7 @@ func TListIssuedTokens(t *testing.T, db *TokenDB) {
477509
OwnerRaw: []byte{3, 4},
478510
OwnerType: "idemix",
479511
OwnerIdentity: []byte{},
512+
OwnerWalletID: "idemix",
480513
IssuerRaw: []byte{13, 14},
481514
Ledger: []byte("ledger"),
482515
LedgerMetadata: []byte{},
@@ -494,6 +527,7 @@ func TListIssuedTokens(t *testing.T, db *TokenDB) {
494527
OwnerRaw: []byte{5, 6},
495528
OwnerType: "idemix",
496529
OwnerIdentity: []byte{},
530+
OwnerWalletID: "idemix",
497531
IssuerRaw: []byte{15, 16},
498532
Ledger: []byte("ledger"),
499533
LedgerMetadata: []byte{},

token/services/db/sql/common/tokens.go

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ func (db *TokenDB) UnspentTokensIteratorBy(ctx context.Context, walletID, tokenT
136136
return &UnspentTokensIterator{txs: rows}, err
137137
}
138138

139-
// MinTokenInfoIteratorBy returns the minimum information about the tokens needed for the selector
140-
func (db *TokenDB) MinTokenInfoIteratorBy(ctx context.Context, walletID string, typ string) (tdriver.MinTokenInfoIterator, error) {
139+
// UnspentTokensInWalletIterator returns the minimum information about the tokens needed for the selector
140+
func (db *TokenDB) SpendableTokensIteratorBy(ctx context.Context, walletID string, typ string) (tdriver.SpendableTokensIterator, error) {
141141
span := trace.SpanFromContext(ctx)
142142
where, args := tokenQuerySqlNoJoin(driver.QueryTokenDetailsParams{
143143
WalletID: walletID,
@@ -155,7 +155,7 @@ func (db *TokenDB) MinTokenInfoIteratorBy(ctx context.Context, walletID string,
155155
if err != nil {
156156
return nil, errors.Wrapf(err, "error querying db")
157157
}
158-
return &MinTokenInfoIterator{txs: rows}, nil
158+
return &UnspentTokensInWalletIterator{txs: rows}, nil
159159
}
160160

161161
// Balance returns the sun of the amounts, with 64 bits of precision, of the tokens with type and EID equal to those passed as arguments.
@@ -182,9 +182,9 @@ func (db *TokenDB) Balance(walletID, typ string) (uint64, error) {
182182
}
183183

184184
// ListUnspentTokensBy returns the list of unspent tokens, filtered by owner and token type
185-
func (db *TokenDB) ListUnspentTokensBy(ownerEID, typ string) (*token.UnspentTokens, error) {
186-
logger.Debugf("list unspent token by [%s,%s]", ownerEID, typ)
187-
it, err := db.UnspentTokensIteratorBy(context.TODO(), ownerEID, typ)
185+
func (db *TokenDB) ListUnspentTokensBy(walletID, typ string) (*token.UnspentTokens, error) {
186+
logger.Debugf("list unspent token by [%s,%s]", walletID, typ)
187+
it, err := db.UnspentTokensIteratorBy(context.TODO(), walletID, typ)
188188
if err != nil {
189189
return nil, err
190190
}
@@ -855,7 +855,7 @@ func (t *TokenTransaction) GetToken(ctx context.Context, txID string, index uint
855855
IncludeDeleted: includeDeleted,
856856
}, t.db.table.Tokens, t.db.table.Ownership)
857857

858-
query := fmt.Sprintf("SELECT owner_raw, token_type, quantity, wallet_id FROM %s %s %s", t.db.table.Tokens, join, where)
858+
query := fmt.Sprintf("SELECT owner_raw, token_type, quantity, %s.wallet_id, owner_wallet_id FROM %s %s %s", t.db.table.Ownership, t.db.table.Tokens, join, where)
859859
span.AddEvent("query", tracing.WithAttributes(tracing.String(QueryLabel, query)))
860860
logger.Debug(query, args)
861861
rows, err := t.tx.Query(query, args...)
@@ -869,18 +869,26 @@ func (t *TokenTransaction) GetToken(ctx context.Context, txID string, index uint
869869
var tokenType string
870870
var quantity string
871871
owners := []string{}
872+
var walletID *string
872873
for rows.Next() {
873-
var owner string
874-
if err := rows.Scan(&raw, &tokenType, &quantity, &owner); err != nil {
874+
var tempOwner *string
875+
if err := rows.Scan(&raw, &tokenType, &quantity, &tempOwner, &walletID); err != nil {
875876
return nil, owners, err
876877
}
878+
var owner string
879+
if tempOwner != nil {
880+
owner = *tempOwner
881+
}
877882
if len(owner) > 0 {
878883
owners = append(owners, owner)
879884
}
880885
}
881886
if rows.Err() != nil {
882887
return nil, nil, rows.Err()
883888
}
889+
if walletID != nil && len(*walletID) != 0 {
890+
owners = append(owners, *walletID)
891+
}
884892
span.AddEvent("end_scan_rows", tracing.WithAttributes(tracing.Int(ResultRowsLabel, len(owners))))
885893
if len(raw) == 0 {
886894
return nil, owners, nil
@@ -911,6 +919,10 @@ func (t *TokenTransaction) Delete(ctx context.Context, txID string, index uint64
911919
}
912920

913921
func (t *TokenTransaction) StoreToken(ctx context.Context, tr driver.TokenRecord, owners []string) error {
922+
if len(tr.OwnerWalletID) == 0 && len(owners) == 0 && tr.Owner {
923+
return errors.Errorf("no owners specified [%s]", string(debug.Stack()))
924+
}
925+
914926
span := trace.SpanFromContext(ctx)
915927
//logger.Debugf("store record [%s:%d,%v] in table [%s]", tr.TxID, tr.Index, owners, t.db.table.Tokens)
916928

@@ -958,9 +970,6 @@ func (t *TokenTransaction) StoreToken(ctx context.Context, tr driver.TokenRecord
958970

959971
// Store ownership
960972
span.AddEvent("store_ownerships")
961-
if len(tr.OwnerWalletID) != 0 {
962-
owners = append(owners, tr.OwnerWalletID)
963-
}
964973
for _, eid := range owners {
965974
query = fmt.Sprintf("INSERT INTO %s (tx_id, idx, wallet_id) VALUES ($1, $2, $3)", t.db.table.Ownership)
966975
logger.Debug(query, tr.TxID, tr.Index, eid)
@@ -981,26 +990,26 @@ func (t *TokenTransaction) Rollback() error {
981990
return t.tx.Rollback()
982991
}
983992

984-
type MinTokenInfoIterator struct {
993+
type UnspentTokensInWalletIterator struct {
985994
txs *sql.Rows
986995
}
987996

988-
func (u *MinTokenInfoIterator) Close() {
997+
func (u *UnspentTokensInWalletIterator) Close() {
989998
u.txs.Close()
990999
}
9911000

992-
func (u *MinTokenInfoIterator) Next() (*token.MinTokenInfo, error) {
1001+
func (u *UnspentTokensInWalletIterator) Next() (*token.UnspentTokenInWallet, error) {
9931002
if !u.txs.Next() {
9941003
return nil, nil
9951004
}
9961005

997-
tok := &token.MinTokenInfo{
1006+
tok := &token.UnspentTokenInWallet{
9981007
Id: &token.ID{},
999-
Owner: "",
1008+
WalletID: "",
10001009
Type: "",
10011010
Quantity: "",
10021011
}
1003-
if err := u.txs.Scan(&tok.Id.TxId, &tok.Id.Index, &tok.Type, &tok.Quantity, &tok.Owner); err != nil {
1012+
if err := u.txs.Scan(&tok.Id.TxId, &tok.Id.Index, &tok.Type, &tok.Quantity, &tok.WalletID); err != nil {
10041013
return nil, err
10051014
}
10061015
return tok, nil

0 commit comments

Comments
 (0)