Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor iterators to re-use consistent iterator interface #853

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/gin-gonic/gin v1.10.0
github.com/gobuffalo/packr/v2 v2.7.1
github.com/hashicorp/go-uuid v1.0.3
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250210153725-90e0fbb00133
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250214122853-be2854b10fed
github.com/hyperledger-labs/orion-sdk-go v0.2.10
github.com/hyperledger-labs/orion-server v0.2.10
github.com/hyperledger/fabric v1.4.0-rc1.0.20230405174026-695dd57e01c2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1057,8 +1057,8 @@ github.com/hidal-go/hidalgo v0.0.0-20201109092204-05749a6d73df/go.mod h1:bPkrxDl
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250210153725-90e0fbb00133 h1:UTyfnN+H+K9kK6TZw8ccal0+viXlf/RBHc7YiEY0XiU=
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250210153725-90e0fbb00133/go.mod h1:EdiA1cY2eOOZjqPlutIlFPkueUMMJOxLoiRH5KwOW1c=
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250214122853-be2854b10fed h1:KKKk7H9wKeCnJP6FR3G1X3rGOP6/PzK/rOeGvl6MAXk=
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250214122853-be2854b10fed/go.mod h1:EdiA1cY2eOOZjqPlutIlFPkueUMMJOxLoiRH5KwOW1c=
github.com/hyperledger-labs/orion-sdk-go v0.2.10 h1:lFgWgxyvngIhWnIqymYGBmtmq9D6uC5d0uLG9cbyh5s=
github.com/hyperledger-labs/orion-sdk-go v0.2.10/go.mod h1:iN2xZB964AqwVJwL+EnwPOs8z1EkMEbbIg/qYeC7gDY=
github.com/hyperledger-labs/orion-server v0.2.10 h1:G4zbQEL5Egk0Oj+TwHCZWdTOLDBHOjaAEvYOT4G7ozw=
Expand Down
19 changes: 2 additions & 17 deletions integration/token/fungible/views/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (p *ListAuditedTransactionsView) Call(context view.Context) (interface{}, e
if err != nil {
return nil, errors.Wrapf(err, "failed querying transactions")
}
return ToSlice(it)
return collections.ToSlice(it)
}

type ListAuditedTransactionsViewFactory struct{}
Expand Down Expand Up @@ -123,7 +123,7 @@ func (p *ListAcceptedTransactionsView) Call(context view.Context) (interface{},
return nil, errors.Wrapf(err, "failed querying transactions")
}

return ToSlice(it)
return collections.ToSlice(it)
}

type ListAcceptedTransactionsViewFactory struct{}
Expand Down Expand Up @@ -165,18 +165,3 @@ func (p *TransactionInfoViewFactory) NewView(in []byte) (view.View, error) {
}
return f, nil
}

func ToSlice[T any](it collections.Iterator[*T]) ([]*T, error) {
defer it.Close()
var items []*T
for {
if tx, err := it.Next(); err != nil {
return nil, errors.Wrapf(err, "failed iterating over transactions")
} else if tx == nil {
break
} else {
items = append(items, tx)
}
}
return items, nil
}
20 changes: 6 additions & 14 deletions token/driver/vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package driver
import (
"context"

"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections"
"github.com/hyperledger-labs/fabric-token-sdk/token/token"
)

Expand All @@ -32,20 +33,11 @@ const (

//go:generate counterfeiter -o mock/uti.go -fake-name UnspentTokensIterator . UnspentTokensIterator

type UnspentTokensIterator interface {
Close()
Next() (*token.UnspentToken, error)
}

type SpendableTokensIterator interface {
Close()
Next() (*token.UnspentTokenInWallet, error)
}

type UnsupportedTokensIterator interface {
Close()
Next() (*token.LedgerToken, error)
}
type (
UnspentTokensIterator = collections.Iterator[*token.UnspentToken]
SpendableTokensIterator = collections.Iterator[*token.UnspentTokenInWallet]
UnsupportedTokensIterator = collections.Iterator[*token.LedgerToken]
)

type Vault interface {
QueryEngine() QueryEngine
Expand Down
23 changes: 0 additions & 23 deletions token/services/auditdb/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,29 +96,6 @@ type MovementRecord = driver.MovementRecord
// in that action.
type TransactionRecord = driver.TransactionRecord

// TransactionIterator is an iterator over transaction records
type TransactionIterator struct {
it driver.TransactionIterator
}

// Close closes the iterator. It must be called when done with the iterator.
func (t *TransactionIterator) Close() {
t.it.Close()
}

// Next returns the next transaction record, if any.
// It returns nil, nil if there are no more records.
func (t *TransactionIterator) Next() (*TransactionRecord, error) {
next, err := t.it.Next()
if err != nil {
return nil, err
}
if next == nil {
return nil, nil
}
return next, nil
}

// QueryTransactionsParams defines the parameters for querying movements
type QueryTransactionsParams = driver.QueryTransactionsParams

Expand Down
19 changes: 9 additions & 10 deletions token/services/certifier/interactive/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"context"
"time"

"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections"
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/functions"
"github.com/hyperledger-labs/fabric-smart-client/platform/view"
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/events"
view2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
Expand Down Expand Up @@ -143,23 +145,20 @@ func (cc *CertificationClient) Scan() error {
if err != nil {
return errors.WithMessagef(err, "failed to get an iterator over unspent tokens")
}
tokenIds := collections.Map[*token.UnspentToken, *token.ID](tokens, func(t *token.UnspentToken) (*token.ID, error) { return t.Id, nil })
uncertifiedTokenIds := collections.Filter(tokenIds, functions.Not(cc.certificationStorage.Exists))

defer tokens.Close()

var toBeCertified []*token.ID
for {
token, err := tokens.Next()
if err != nil {
if tokenId, err := uncertifiedTokenIds.Next(); err != nil {
logger.Errorf("failed to get next unspent tokens, stop here [%s]", err)
break
}
if token == nil {
} else if tokenId == nil {
break
}

// does token have a certification?
if !cc.certificationStorage.Exists(token.Id) {
// if no, batch it
toBeCertified = append(toBeCertified, token.Id)
} else {
toBeCertified = append(toBeCertified, tokenId)
}
}

Expand Down
29 changes: 18 additions & 11 deletions token/services/db/common/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ import (
"fmt"

"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections"
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/hash"
"github.com/hyperledger-labs/fabric-token-sdk/token"
"github.com/hyperledger-labs/fabric-token-sdk/token/services/db/driver"
"github.com/hyperledger-labs/fabric-token-sdk/token/services/logging"
"github.com/hyperledger-labs/fabric-token-sdk/token/services/network"
"github.com/hyperledger-labs/fabric-token-sdk/token/services/tokens"
token2 "github.com/hyperledger-labs/fabric-token-sdk/token/token"
)

var logger = logging.MustGetLogger("tokensdk.common-checks")

type TokenTransactionDB interface {
GetTokenRequest(txID string) ([]byte, error)
Transactions(params driver.QueryTransactionsParams) (driver.TransactionIterator, error)
Expand Down Expand Up @@ -168,24 +172,27 @@ func (a *DefaultCheckers) checkUnspentTokens(context context.Context) ([]string,
if err != nil {
return nil, errors.WithMessagef(err, "failed querying utxo engine")
}
defer uit.Close()
var unspentTokenIDs []*token2.ID
for {
tok, err := uit.Next()
if err != nil {
return nil, errors.WithMessagef(err, "failed querying next unspent token")
}
if tok == nil {
break
unspentTokenIDs, err := collections.ToSlice(collections.Map(uit, func(t *token2.UnspentToken) (*token2.ID, error) {
if t == nil {
return nil, nil
}
unspentTokenIDs = append(unspentTokenIDs, tok.Id)
return t.Id, nil
}))

if err != nil {
return nil, errors.WithMessagef(err, "failed querying next unspent token")
}
ledgerTokenContent, err := net.QueryTokens(context, tms.Namespace(), unspentTokenIDs)
if err != nil {
errorMessages = append(errorMessages, fmt.Sprintf("failed to query tokens: [%s]", err))
} else {
if len(unspentTokenIDs) != len(ledgerTokenContent) {
return nil, errors.Errorf("length diffrence")
for _, id := range unspentTokenIDs {
if id != nil {
logger.Infof("unspent token id: [%s]", *id)
}
}
return nil, errors.Errorf("length difference: %d:%d", len(unspentTokenIDs), len(ledgerTokenContent))
}
index := 0
if err := tv.QueryEngine().GetTokenOutputs(unspentTokenIDs, func(id *token2.ID, tokenRaw []byte) error {
Expand Down
90 changes: 27 additions & 63 deletions token/services/db/dbtest/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import (
"testing"
"time"

"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections"
"github.com/hyperledger-labs/fabric-token-sdk/token"
driver2 "github.com/hyperledger-labs/fabric-token-sdk/token/driver"
"github.com/hyperledger-labs/fabric-token-sdk/token/services/db/driver"
"github.com/hyperledger-labs/fabric-token-sdk/token/services/utils/slices"
"github.com/test-go/testify/assert"
)

Expand Down Expand Up @@ -389,86 +391,62 @@ func TTokenRequest(t *testing.T, db driver.TokenTransactionDB) {
// iterate over all
it, err := db.QueryTokenRequests(driver.QueryTokenRequestsParams{})
assert.NoError(t, err)
counter := 0
for {
record, err := it.Next()
assert.NoError(t, err)
if record == nil {
break
}
records, err := collections.ToSlice(it)
assert.NoError(t, err)

for _, record := range records {
if record.TxID == "id1" {
assert.Equal(t, tr1, record.TokenRequest)
assert.Equal(t, driver.Pending, record.Status)
counter++
continue
}
if record.TxID == "id2" {
} else if record.TxID == "id2" {
assert.Equal(t, tr2, record.TokenRequest)
assert.Equal(t, driver.Confirmed, record.Status)
counter++
continue
}
}
assert.Equal(t, 2, counter)
it.Close()
assert.Len(t, records, 2)

// iterate over pending and confirmed
it, err = db.QueryTokenRequests(driver.QueryTokenRequestsParams{Statuses: []driver.TxStatus{driver.Confirmed, driver.Pending}})
assert.NoError(t, err)
counter = 0
for {
record, err := it.Next()
assert.NoError(t, err)
if record == nil {
break
}
records, err = collections.ToSlice(it)
assert.NoError(t, err)
for _, record := range records {
if record.TxID == "id1" {
assert.Equal(t, tr1, record.TokenRequest)
assert.Equal(t, driver.Pending, record.Status)
counter++
continue
}
if record.TxID == "id2" {
} else if record.TxID == "id2" {
assert.Equal(t, tr2, record.TokenRequest)
assert.Equal(t, driver.Confirmed, record.Status)
counter++
continue
}
}
assert.Equal(t, 2, counter)
it.Close()
assert.Len(t, records, 2)

// iterator over confirmed
it, err = db.QueryTokenRequests(driver.QueryTokenRequestsParams{Statuses: []driver.TxStatus{driver.Confirmed}})
assert.NoError(t, err)
record, err := it.Next()
records, err = collections.ToSlice(it)
assert.NoError(t, err)
assert.Len(t, records, 1)
record := slices.GetUnique(records)
assert.Equal(t, tr2, record.TokenRequest)
assert.Equal(t, driver.Confirmed, record.Status)
record, err = it.Next()
assert.NoError(t, err)
assert.Nil(t, record)
it.Close()

// iterator over pending
it, err = db.QueryTokenRequests(driver.QueryTokenRequestsParams{Statuses: []driver.TxStatus{driver.Pending}})
assert.NoError(t, err)
record, err = it.Next()
records, err = collections.ToSlice(it)
assert.NoError(t, err)
assert.Len(t, records, 1)
record = slices.GetUnique(records)
assert.Equal(t, tr1, record.TokenRequest)
assert.Equal(t, driver.Pending, record.Status)
record, err = it.Next()
assert.NoError(t, err)
assert.Nil(t, record)
it.Close()

// iterator over deleted
it, err = db.QueryTokenRequests(driver.QueryTokenRequestsParams{Statuses: []driver.TxStatus{driver.Deleted}})
assert.NoError(t, err)
record, err = it.Next()
records, err = collections.ToSlice(it)
assert.NoError(t, err)
assert.Nil(t, record)
it.Close()
assert.Empty(t, records)
}

func TAllowsSameTxID(t *testing.T, db driver.TokenTransactionDB) {
Expand Down Expand Up @@ -778,16 +756,9 @@ func TTransactionQueries(t *testing.T, db driver.TokenTransactionDB) {
func getTransactions(t *testing.T, db driver.TokenTransactionDB, params driver.QueryTransactionsParams) []*driver.TransactionRecord {
records, err := db.QueryTransactions(params)
assert.NoError(t, err)
defer records.Close()
var txs []*driver.TransactionRecord
for {
r, err := records.Next()
assert.NoError(t, err)
if r == nil {
return txs
}
txs = append(txs, r)
}
txs, err := collections.ToSlice(records)
assert.NoError(t, err)
return txs
}

func TValidationRecordQueries(t *testing.T, db driver.TokenTransactionDB) {
Expand Down Expand Up @@ -873,16 +844,9 @@ func TValidationRecordQueries(t *testing.T, db driver.TokenTransactionDB) {
func getValidationRecords(t *testing.T, db driver.TokenTransactionDB, params driver.QueryValidationRecordsParams) []*driver.ValidationRecord {
records, err := db.QueryValidations(params)
assert.NoError(t, err)
defer records.Close()
var txs []*driver.ValidationRecord
for {
r, err := records.Next()
assert.NoError(t, err)
if r == nil {
return txs
}
txs = append(txs, r)
}
txs, err := collections.ToSlice(records)
assert.NoError(t, err)
return txs
}

func TEndorserAcks(t *testing.T, db driver.TokenTransactionDB) {
Expand Down
2 changes: 1 addition & 1 deletion token/services/db/driver/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type IdentityDB interface {
// ConfigurationExists returns true if a configuration with the given id and type exists.
ConfigurationExists(id, typ, url string) (bool, error)
// IteratorConfigurations returns an iterator to all configurations stored
IteratorConfigurations(configurationType string) (Iterator[IdentityConfiguration], error)
IteratorConfigurations(configurationType string) (Iterator[driver.IdentityConfiguration], error)
// StoreIdentityData stores the passed identity and token information
StoreIdentityData(id []byte, identityAudit []byte, tokenMetadata []byte, tokenMetadataAudit []byte) error
// GetAuditInfo retrieves the audit info bounded to the given identity
Expand Down
Loading
Loading