Skip to content

Commit 8c60dcd

Browse files
Merge branch 'main' of https://github.com/hyperledger-labs/fabric-token-sdk into issue915
2 parents f9ac466 + 8b310cf commit 8c60dcd

File tree

58 files changed

+1172
-1185
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1172
-1185
lines changed

.github/workflows/codeql-analysis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ jobs:
3333
shell: bash
3434
run: |
3535
go build -o tokengen ./cmd/tokengen
36-
make unit-tests
3736
3837
- name: Perform CodeQL Analysis
3938
uses: github/codeql-action/analyze@v3

.github/workflows/tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ jobs:
6666
- name: Set up tools
6767
run: make install-tools
6868

69+
- name: Install Testing Docker Images
70+
run: make testing-docker-images
71+
6972
- name: Run ${{ matrix.tests }}
7073
run: make ${{ matrix.tests }}
7174

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ docker-images: fabric-docker-images orion-server-images monitoring-docker-images
5454
testing-docker-images:
5555
docker pull postgres:16.2-alpine
5656
docker tag postgres:16.2-alpine postgres:latest
57+
docker pull hashicorp/vault
5758

5859
.PHONY: fabric-docker-images
5960
fabric-docker-images:

docs/services/identity.md

Lines changed: 55 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -51,88 +51,82 @@ The identity service is locate under [`token/services/identity`](./../../token/s
5151
Building on the concept of long-term identities, we'll now explore how they are grouped into roles within the identity service.
5252

5353
Each role acts as a container for long-term identities, which are then used to create wallets.
54-
Here's the interface that defines a role:
55-
56-
```go
57-
// Role is a container of long-term identities.
58-
// A long-term identity is then used to construct a wallet.
59-
type Role interface {
60-
// ID returns the identifier of this role
61-
ID() IdentityRoleType
62-
// MapToIdentity returns the long-term identity and its identifier for the given index.
63-
// The index can be an identity or a label (string).
64-
MapToIdentity(v WalletLookupID) (Identity, string, error)
65-
// GetIdentityInfo returns the long-term identity info associated to the passed id
66-
GetIdentityInfo(id string) (IdentityInfo, error)
67-
// RegisterIdentity registers the given identity
68-
RegisterIdentity(config IdentityConfiguration) error
69-
// IdentityIDs returns the identifiers contained in this role
70-
IdentityIDs() ([]string, error)
71-
}
72-
```
73-
54+
The role is defined by the [`Role`](./../../token/services/identity/roles.go) interface.
7455
This interface offers functions for managing identities within the role.
7556
You, as the developer, have the flexibility to implement a role using any identity representation that best fits your application's needs.
7657

7758
A default implementation is provided under [`token/services/identity/role`](./../../token/services/identity/role).
7859

7960
## Understanding Wallets in More Detail
8061

81-
The Token-SDK abstracts the wallet management via a service called `WalletService`.
82-
Here is the interface that defines such a service:
62+
The Token-SDK abstracts the wallet management via an interface called [`WalletService`](./../../token/driver/wallet.go) that is part of the `Driver API`.
63+
The `WalletService` interface gives access to the available wallets.
64+
You, as the developer, have the flexibility to implement a `WalletService` that best fits your application's needs.
8365

84-
```go
85-
// WalletService models the wallet service that handles issuer, recipient, auditor and certifier wallets
86-
type WalletService interface {
87-
// RegisterRecipientIdentity registers the passed recipient identity together with the associated audit information
88-
RegisterRecipientIdentity(data *RecipientData) error
66+
A default implementation is provided under [`token/services/identity/wallet`](./../../token/services/identity/wallet).
8967

90-
// GetAuditInfo retrieves the audit information for the passed identity
91-
GetAuditInfo(id Identity) ([]byte, error)
68+
## Storage
9269

93-
// GetEnrollmentID extracts the enrollment id from the passed audit information
94-
GetEnrollmentID(identity Identity, auditInfo []byte) (string, error)
70+
The identity service uses 3 data storage defined by the following interfaces:
71+
- `IdentityDB`: It is used to store identity configuration, signer related information, audit information, and so on.
72+
- `WalletDB`: It is used to track the mapping between identities, wallet identifier, and enrollment IDs.
73+
- `Keystore`: It is used for the key storage.
9574

96-
// GetRevocationHandle extracts the revocation handler from the passed audit information
97-
GetRevocationHandle(identity Identity, auditInfo []byte) (string, error)
75+
### Implementation
9876

99-
// GetEIDAndRH returns both enrollment ID and revocation handle
100-
GetEIDAndRH(identity Identity, auditInfo []byte) (string, string, error)
77+
We support the following implementations:
78+
- `IdentityDB`, can be either based on the `identitydb` service or the Fabric-Smart-Client's KVS.
79+
- `WalletDB`, same as the `IdentityDB`.
80+
- `Keystore` is based on the Fabric-Smart-Client's KVS.
81+
By default, the `identitydb` is used to provide both an implementation to both the `IdentityDB` and `WalletDB`.
10182

102-
// Wallet returns the wallet bound to the passed identity, if any is available
103-
Wallet(identity Identity) Wallet
83+
To retrieve the implementation of these interfaces, we have the `identity.StorageProvider` interface.
84+
An implementation for this interface can be found under [`token/sdk/identity`](./../../token/sdk/identity).
85+
It uses the `identitydb` service for the `IdentityDB` and the `WalletDB`, and the Fabric-Smart-Client's KVS for the `Keystore`.
10486

105-
// RegisterOwnerIdentity registers an owner long-term identity
106-
RegisterOwnerIdentity(config IdentityConfiguration) error
87+
### HashiCorp Vault Secrets Engine Support
10788

108-
// RegisterIssuerIdentity registers an issuer long-term wallet
109-
RegisterIssuerIdentity(config IdentityConfiguration) error
89+
The HashiCorp Vault Secrets Engine is a modular component of Vault designed to securely manage, store, or generate sensitive data such as API keys, passwords, certificates, and encryption keys.
90+
The identity service provides an implementation for both the `IdentityDB` and `Keystore` based on the `HashiCorp Vault Secrets Engine`.
91+
This implementation can be found under [`hashicorp`](./../../token/services/identity/storage/kvs/hashicorp).
92+
This implementation requires to configure the `HashiCorp Vault Secrets Engine` to run in non-versioned mode (i.e., stores the most recently written value for a key).
93+
For more information about non-versioned secrets engine mode, refer to the (https://developer.hashicorp.com/vault/docs/secrets/kv/kv-v1).
11094

111-
// OwnerWalletIDs returns the list of owner wallet identifiers
112-
OwnerWalletIDs() ([]string, error)
95+
In order to use this integration, the developer must do the following:
96+
1. Implement the `identity.StorageProvider` interface.
97+
2. Register this implementation in [`Dig`](https://github.com/hyperledger-labs/fabric-smart-client/blob/main/docs/sdk.md) via decoration like this:
98+
```go
99+
p.Container().Decorate(NewMixedStorageProvider)
100+
```
101+
This can be added in the Application Dig SDK that links that token-sdk Dig SDK.
113102

114-
// OwnerWallet returns an instance of the OwnerWallet interface bound to the passed id.
115-
// The id can be: the wallet identifier or a unique id of a view identity belonging to the wallet.
116-
OwnerWallet(id WalletLookupID) (OwnerWallet, error)
103+
Here is an example of the implementation of the `identity.StorageProvider` interface implementing bullet `1`:
117104

118-
// IssuerWallet returns an instance of the IssuerWallet interface bound to the passed id.
119-
// The id can be: the wallet identifier or a unique id of a view identity belonging to the wallet.
120-
IssuerWallet(id WalletLookupID) (IssuerWallet, error)
105+
```go
106+
type MixedStorageProvider struct {
107+
kvs kvs.KVS
108+
manager *identitydb.Manager
109+
}
121110

122-
// AuditorWallet returns an instance of the AuditorWallet interface bound to the passed id.
123-
// The id can be: the wallet identifier or a unique id of a view identity belonging to the wallet.
124-
AuditorWallet(id WalletLookupID) (AuditorWallet, error)
111+
func NewMixedStorageProvider(client *vault.Client, prefix string, manager *identitydb.Manager) (*MixedStorageProvider, error) {
112+
kvs, err := hashicorp.NewWithClient(client, prefix)
113+
if err != nil {
114+
return nil, errors.Wrapf(err, "failed instantiating hashicorp.NewWithClient")
115+
}
116+
return &MixedStorageProvider{kvs: kvs, manager: manager}, nil
117+
}
125118

126-
// CertifierWallet returns an instance of the CertifierWallet interface bound to the passed id.
127-
// The id can be: the wallet identifier or a unique id of a view identity belonging to the wallet.
128-
CertifierWallet(id WalletLookupID) (CertifierWallet, error)
119+
func (s *MixedStorageProvider) WalletDB(tmsID token.TMSID) (identity.WalletDB, error) {
120+
return s.manager.WalletDBByTMSId(tmsID)
121+
}
129122

130-
// SpendIDs returns the spend ids for the passed token ids
131-
SpendIDs(ids ...*token.ID) ([]string, error)
123+
func (s *MixedStorageProvider) IdentityDB(tmsID token.TMSID) (identity.IdentityDB, error) {
124+
return kvs.NewIdentityDB(s.kvs, tmsID), nil
132125
}
133-
```
134126

135-
The `WalletService` gives access to the available wallets.
136-
You, as the developer, have the flexibility to implement a `WalletService` that best fits your application's needs.
127+
func (s *MixedStorageProvider) Keystore() (identity.Keystore, error) {
128+
return s.kvs, nil
129+
}
130+
```
137131

138-
A default implementation is provided under [`token/services/identity/wallet`](./../../token/services/identity/wallet).
132+

docs/services/snippets/msp.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Copyright IBM Corp All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package snippets
8+
9+
import (
10+
vault "github.com/hashicorp/vault/api"
11+
"github.com/hyperledger-labs/fabric-token-sdk/token"
12+
"github.com/hyperledger-labs/fabric-token-sdk/token/services/identity"
13+
"github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/storage/kvs"
14+
"github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/storage/kvs/hashicorp"
15+
"github.com/hyperledger-labs/fabric-token-sdk/token/services/identitydb"
16+
"github.com/pkg/errors"
17+
)
18+
19+
type MixedStorageProvider struct {
20+
kvs kvs.KVS
21+
manager *identitydb.Manager
22+
}
23+
24+
func NewMixedStorageProvider(client *vault.Client, prefix string, manager *identitydb.Manager) (*MixedStorageProvider, error) {
25+
kvs, err := hashicorp.NewWithClient(client, prefix)
26+
if err != nil {
27+
return nil, errors.Wrapf(err, "failed instantiating hashicorp.NewWithClient")
28+
}
29+
return &MixedStorageProvider{kvs: kvs, manager: manager}, nil
30+
}
31+
32+
func (s *MixedStorageProvider) WalletDB(tmsID token.TMSID) (identity.WalletDB, error) {
33+
return s.manager.WalletDBByTMSId(tmsID)
34+
}
35+
36+
func (s *MixedStorageProvider) IdentityDB(tmsID token.TMSID) (identity.IdentityDB, error) {
37+
return kvs.NewIdentityDB(s.kvs, tmsID), nil
38+
}
39+
40+
func (s *MixedStorageProvider) Keystore() (identity.Keystore, error) {
41+
return s.kvs, nil
42+
}

docs/services/storage.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,26 @@ This system leverages several databases, each with a specific purpose:
66
* **Transaction Database (`ttxdb`)**:
77
This critical database serves as the central repository for all transaction records.
88
It captures every token issuance, transfer, or redemption, providing a complete historical record of token activity within the network.
9-
The `ttxdb` service is locate under [`token/services/ttxdb`](./../../token/services/ttxdb).
9+
The `ttxdb` service is locate under [`token/services/ttxdb`](./../../token/services/ttxdb). It is accessible via the `ttx` service.
1010

1111
* **Token Database (`tokendb`)**:
1212
The `tokendb` acts as the registry for all tokens within the system.
1313
It stores detailed information about each token, including its unique identifier, denomination type (think currency or unique identifier), current ownership, and total quantity in circulation.
1414
By referencing the `tokendb`, developers and network participants can obtain a clear picture of the token landscape.
1515
The `tokendb` is used by the `Token Selector`, to select the tokens to use in each transaction, and by the `Token Vault Service` to provide its services.
16-
The `tokendb` service is locate under [`token/services/tokendb`](./../../token/services/tokendb).
16+
The `tokendb` service is locate under [`token/services/tokendb`](./../../token/services/tokendb). It is accessible via the `tokens` service.
1717

1818
* **Audit Database (`auditdb`)** (if applicable):
1919
For applications requiring enhanced auditability, the `auditdb` provides an additional layer of transparency.
2020
It meticulously stores audit records for transactions that have undergone the auditing process.
2121
This functionality is particularly valuable for scenarios where regulatory compliance or tamper-proof records are essential.
22-
The `auditdb` service is locate under [`token/services/auditdb`](./../../token/services/auditdb).
22+
The `auditdb` service is locate under [`token/services/auditdb`](./../../token/services/auditdb). It is accessible via the `auditor` service.
2323

2424
* **Identity Database (`identitydb`)**:
2525
The `identitydb` plays a crucial role in managing user identities and wallets within the network.
2626
It securely stores wallet configurations, identity-related audit information, and so on, enabling secure interactions with the token system.
27-
The `identitydb` service is locate under [`token/services/identitydb`](./../../token/services/identitydb).
27+
The `identitydb` service is locate under [`token/services/identitydb`](./../../token/services/identitydb).
28+
It is used by the `identity` service via its interfaces. Please, refer to the [`identity service`](identity.md) for more information about the storage part.
2829

2930
## Configuration
3031

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ require (
1212
github.com/gobuffalo/packr/v2 v2.7.1
1313
github.com/hashicorp/go-uuid v1.0.3
1414
github.com/hashicorp/vault/api v1.16.0
15-
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250314124232-4cd027590cfb
15+
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250319152028-b53f202e2b62
1616
github.com/hyperledger-labs/orion-sdk-go v0.2.10
1717
github.com/hyperledger-labs/orion-server v0.2.10
1818
github.com/hyperledger/fabric v1.4.0-rc1.0.20230405174026-695dd57e01c2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,8 +1084,8 @@ github.com/hidal-go/hidalgo v0.0.0-20201109092204-05749a6d73df/go.mod h1:bPkrxDl
10841084
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
10851085
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
10861086
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
1087-
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250314124232-4cd027590cfb h1:tXjdCuJdbLmf+oPb9CluSOuwnYPnQKJn8gwySYBy3to=
1088-
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250314124232-4cd027590cfb/go.mod h1:EdiA1cY2eOOZjqPlutIlFPkueUMMJOxLoiRH5KwOW1c=
1087+
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250319152028-b53f202e2b62 h1:fUK1AxK//9bF8si5AYE6kptAErzn+oWbINndOTfTQTM=
1088+
github.com/hyperledger-labs/fabric-smart-client v0.4.1-0.20250319152028-b53f202e2b62/go.mod h1:EdiA1cY2eOOZjqPlutIlFPkueUMMJOxLoiRH5KwOW1c=
10891089
github.com/hyperledger-labs/orion-sdk-go v0.2.10 h1:lFgWgxyvngIhWnIqymYGBmtmq9D6uC5d0uLG9cbyh5s=
10901090
github.com/hyperledger-labs/orion-sdk-go v0.2.10/go.mod h1:iN2xZB964AqwVJwL+EnwPOs8z1EkMEbbIg/qYeC7gDY=
10911091
github.com/hyperledger-labs/orion-server v0.2.10 h1:G4zbQEL5Egk0Oj+TwHCZWdTOLDBHOjaAEvYOT4G7ozw=

integration/token/common/sdk/identity/provider.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package identity
88

99
import (
1010
"github.com/hyperledger-labs/fabric-token-sdk/token"
11-
"github.com/hyperledger-labs/fabric-token-sdk/token/services/db/driver"
1211
"github.com/hyperledger-labs/fabric-token-sdk/token/services/identity"
1312
"github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/storage/kvs"
1413
)
@@ -21,11 +20,11 @@ func NewKVSStorageProvider(kvs kvs.KVS) *KVSStorageProvider {
2120
return &KVSStorageProvider{kvs: kvs}
2221
}
2322

24-
func (s *KVSStorageProvider) WalletDB(tmsID token.TMSID) (driver.WalletDB, error) {
23+
func (s *KVSStorageProvider) WalletDB(tmsID token.TMSID) (identity.WalletDB, error) {
2524
return kvs.NewWalletDB(s.kvs, tmsID), nil
2625
}
2726

28-
func (s *KVSStorageProvider) IdentityDB(tmsID token.TMSID) (driver.IdentityDB, error) {
27+
func (s *KVSStorageProvider) IdentityDB(tmsID token.TMSID) (identity.IdentityDB, error) {
2928
return kvs.NewIdentityDB(s.kvs, tmsID), nil
3029
}
3130

integration/token/fungible/views/checks.go

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
"github.com/hyperledger-labs/fabric-token-sdk/token"
1515
"github.com/hyperledger-labs/fabric-token-sdk/token/services/db/driver"
1616
"github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/htlc"
17-
"github.com/hyperledger-labs/fabric-token-sdk/token/services/network"
17+
"github.com/hyperledger-labs/fabric-token-sdk/token/services/tokens"
1818
"github.com/hyperledger-labs/fabric-token-sdk/token/services/ttx"
1919
token2 "github.com/hyperledger-labs/fabric-token-sdk/token/token"
2020
"github.com/pkg/errors"
@@ -80,12 +80,14 @@ type PruneInvalidUnspentTokensView struct {
8080
}
8181

8282
func (p *PruneInvalidUnspentTokensView) Call(context view.Context) (interface{}, error) {
83-
net := network.GetInstance(context, p.TMSID.Network, p.TMSID.Channel)
84-
assert.NotNil(net, "cannot find network [%s:%s]", p.TMSID.Network, p.TMSID.Channel)
85-
vault, err := net.TokenVault(p.TMSID.Namespace)
86-
assert.NoError(err, "failed to get vault for [%s:%s:%s]", p.TMSID.Network, p.TMSID.Channel, p.TMSID.Namespace)
83+
tms := token.GetManagementService(context, token.WithTMSID(p.TMSID))
84+
assert.NotNil(tms, "cannot find tms [%s]", p.TMSID)
85+
tokensProvider, err := tokens.GetProvider(context)
86+
assert.NoError(err, "failed to get tokens provider")
87+
tokens, err := tokensProvider.Tokens(tms.ID())
88+
assert.NoError(err, "failed to get tokens for [%s]", p.TMSID)
8789

88-
return vault.PruneInvalidUnspentTokens(context)
90+
return tokens.PruneInvalidUnspentTokens(context.Context())
8991
}
9092

9193
type PruneInvalidUnspentTokensViewFactory struct{}
@@ -107,12 +109,9 @@ type ListVaultUnspentTokensView struct {
107109
}
108110

109111
func (l *ListVaultUnspentTokensView) Call(context view.Context) (interface{}, error) {
110-
net := network.GetInstance(context, l.TMSID.Network, l.TMSID.Channel)
111-
assert.NotNil(net, "cannot find network [%s:%s]", l.TMSID.Network, l.TMSID.Channel)
112-
vault, err := net.TokenVault(l.TMSID.Namespace)
113-
assert.NoError(err, "failed to get vault for [%s:%s:%s]", l.TMSID.Network, l.TMSID.Channel, l.TMSID.Namespace)
114-
115-
return vault.QueryEngine().ListUnspentTokens()
112+
net := token.GetManagementService(context, token.WithTMSID(l.TMSID))
113+
assert.NotNil(net, "cannot find tms [%s]", l.TMSID)
114+
return net.Vault().NewQueryEngine().ListUnspentTokens()
116115
}
117116

118117
type ListVaultUnspentTokensViewFactory struct{}
@@ -135,11 +134,9 @@ type CheckIfExistsInVaultView struct {
135134
}
136135

137136
func (c *CheckIfExistsInVaultView) Call(context view.Context) (interface{}, error) {
138-
net := network.GetInstance(context, c.TMSID.Network, c.TMSID.Channel)
139-
assert.NotNil(net, "cannot find network [%s:%s]", c.TMSID.Network, c.TMSID.Channel)
140-
vault, err := net.TokenVault(c.TMSID.Namespace)
141-
assert.NoError(err, "failed to get vault for [%s:%s:%s]", c.TMSID.Network, c.TMSID.Channel, c.TMSID.Namespace)
142-
qe := vault.QueryEngine()
137+
tms := token.GetManagementService(context, token.WithTMSID(c.TMSID))
138+
assert.NotNil(tms, "cannot find tms [%s]", c.TMSID)
139+
qe := tms.Vault().NewQueryEngine()
143140
var IDs []*token2.ID
144141
count := 0
145142
assert.NoError(qe.GetTokenOutputs(c.IDs, func(id *token2.ID, tokenRaw []byte) error {
@@ -151,7 +148,7 @@ func (c *CheckIfExistsInVaultView) Call(context view.Context) (interface{}, erro
151148
return nil
152149
}), "failed to match tokens")
153150
assert.Equal(len(c.IDs), count, "got a mismatch; count is [%d] while there are [%d] ids", count, len(c.IDs))
154-
return IDs, err
151+
return IDs, nil
155152
}
156153

157154
type CheckIfExistsInVaultViewFactory struct {

0 commit comments

Comments
 (0)