Skip to content

Commit d42cc27

Browse files
committed
implemented the client in go
Signed-off-by: nXtCyberNet <rohantech2005@gmail.com>
1 parent da2240f commit d42cc27

File tree

9 files changed

+773
-0
lines changed

9 files changed

+773
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package main
2+
3+
import "github.com/hyperledger/fabric-gateway/pkg/client"
4+
5+
type Command func(gw *client.Gateway, args []string) error
6+
7+
var commands = map[string]Command{
8+
"create": cmdCreate,
9+
"delete": cmdDelete,
10+
"getAllAssets": cmdGetAllAssets,
11+
"listen": cmdListen,
12+
"read": cmdRead,
13+
"transact": cmdTransact,
14+
"transfer": cmdTransfer,
15+
}
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"crypto/rand"
6+
"encoding/hex"
7+
"encoding/json"
8+
"fmt"
9+
"math/big"
10+
"os"
11+
"strconv"
12+
"strings"
13+
"sync"
14+
15+
"github.com/hyperledger/fabric-gateway/pkg/client"
16+
)
17+
18+
// cmdCreate creates a new asset on the ledger.
19+
// Arguments: <assetId> <ownerName> <color>
20+
func cmdCreate(gw *client.Gateway, args []string) error {
21+
if len(args) < 3 {
22+
return fmt.Errorf("arguments: <assetId> <ownerName> <color>")
23+
}
24+
25+
network := gw.GetNetwork(channelName())
26+
contract := network.GetContract(chaincodeName())
27+
28+
smartContract := NewAssetTransfer(contract)
29+
return smartContract.CreateAsset(Asset{
30+
ID: args[0],
31+
Owner: args[1],
32+
Color: args[2],
33+
Size: 1,
34+
AppraisedValue: 1,
35+
})
36+
}
37+
38+
// cmdDelete deletes an asset from the ledger.
39+
// Arguments: <assetId>
40+
func cmdDelete(gw *client.Gateway, args []string) error {
41+
if len(args) < 1 {
42+
return fmt.Errorf("arguments: <assetId>")
43+
}
44+
45+
network := gw.GetNetwork(channelName())
46+
contract := network.GetContract(chaincodeName())
47+
48+
smartContract := NewAssetTransfer(contract)
49+
return smartContract.DeleteAsset(args[0])
50+
}
51+
52+
// cmdGetAllAssets queries and prints all assets currently on the ledger.
53+
func cmdGetAllAssets(gw *client.Gateway, _ []string) error {
54+
network := gw.GetNetwork(channelName())
55+
contract := network.GetContract(chaincodeName())
56+
57+
smartContract := NewAssetTransfer(contract)
58+
assets, err := smartContract.GetAllAssets()
59+
if err != nil {
60+
return err
61+
}
62+
63+
data, err := json.MarshalIndent(assets, "", " ")
64+
if err != nil {
65+
return fmt.Errorf("failed to marshal assets: %w", err)
66+
}
67+
68+
for _, line := range strings.Split(string(data), "\n") {
69+
fmt.Println(line)
70+
}
71+
return nil
72+
}
73+
74+
const startBlock = uint64(0)
75+
76+
func cmdListen(gw *client.Gateway, _ []string) error {
77+
network := gw.GetNetwork(channelName())
78+
79+
checkpointFile := os.Getenv("CHECKPOINT_FILE")
80+
if checkpointFile == "" {
81+
checkpointFile = "checkpoint.json"
82+
}
83+
84+
simulatedFailureCount, err := getSimulatedFailureCount()
85+
if err != nil {
86+
return err
87+
}
88+
89+
checkpointer, err := client.NewFileCheckpointer(checkpointFile)
90+
if err != nil {
91+
return fmt.Errorf("failed to create checkpointer: %w", err)
92+
}
93+
defer checkpointer.Close()
94+
95+
displayBlock := checkpointer.BlockNumber()
96+
if displayBlock == 0 {
97+
displayBlock = startBlock
98+
}
99+
100+
fmt.Println("Starting event listening from block", displayBlock)
101+
fmt.Println("Last processed transaction ID within block:", checkpointer.TransactionID())
102+
if simulatedFailureCount > 0 {
103+
fmt.Println("Simulating a write failure every", simulatedFailureCount, "transactions")
104+
}
105+
106+
ctx, cancel := context.WithCancel(context.Background())
107+
defer cancel()
108+
109+
events, err := network.ChaincodeEvents(ctx, chaincodeName(),
110+
client.WithStartBlock(startBlock),
111+
client.WithCheckpoint(checkpointer),
112+
)
113+
if err != nil {
114+
return fmt.Errorf("failed to start chaincode event subscription: %w", err)
115+
}
116+
117+
eventCount := 0
118+
for event := range events {
119+
if simulatedFailureCount > 0 {
120+
eventCount++
121+
if eventCount >= simulatedFailureCount {
122+
eventCount = 0
123+
return &ExpectedError{Message: "Simulated write failure"}
124+
}
125+
}
126+
fmt.Printf("Chaincode event: BlockNumber=%d TxID=%s Name=%s Payload=%s\n",
127+
event.BlockNumber, event.TransactionID, event.EventName, string(event.Payload))
128+
}
129+
130+
return nil
131+
}
132+
133+
func getSimulatedFailureCount() (int, error) {
134+
value := os.Getenv("SIMULATED_FAILURE_COUNT")
135+
if value == "" {
136+
return 0, nil
137+
}
138+
count, err := strconv.Atoi(value)
139+
if err != nil || count < 0 {
140+
return 0, fmt.Errorf("invalid SIMULATED_FAILURE_COUNT value: %s", value)
141+
}
142+
return count, nil
143+
}
144+
145+
// cmdRead reads and prints a single asset from the ledger.
146+
// Arguments: <assetId>
147+
func cmdRead(gw *client.Gateway, args []string) error {
148+
if len(args) < 1 {
149+
return fmt.Errorf("arguments: <assetId>")
150+
}
151+
152+
network := gw.GetNetwork(channelName())
153+
contract := network.GetContract(chaincodeName())
154+
155+
smartContract := NewAssetTransfer(contract)
156+
asset, err := smartContract.ReadAsset(args[0])
157+
if err != nil {
158+
return err
159+
}
160+
161+
data, err := json.MarshalIndent(asset, "", " ")
162+
if err != nil {
163+
return fmt.Errorf("failed to marshal asset: %w", err)
164+
}
165+
166+
fmt.Println(string(data))
167+
return nil
168+
}
169+
170+
var (
171+
colors = []string{"red", "green", "blue"}
172+
maxInitialSize = 10
173+
maxInitialVal = 1000
174+
)
175+
176+
// cmdTransact runs a batch of concurrent create/update/delete transactions to demonstrate
177+
func cmdTransact(gw *client.Gateway, _ []string) error {
178+
network := gw.GetNetwork(channelName())
179+
contract := network.GetContract(chaincodeName())
180+
181+
smartContract := NewAssetTransfer(contract)
182+
app := &transactApp{smartContract: smartContract, batchSize: 6}
183+
return app.run()
184+
}
185+
186+
type transactApp struct {
187+
smartContract *AssetTransfer
188+
batchSize int
189+
}
190+
191+
func (a *transactApp) run() error {
192+
var wg sync.WaitGroup
193+
errCh := make(chan error, a.batchSize)
194+
195+
for i := 0; i < a.batchSize; i++ {
196+
wg.Add(1)
197+
go func() {
198+
defer wg.Done()
199+
if err := a.transact(); err != nil {
200+
errCh <- err
201+
}
202+
}()
203+
}
204+
205+
wg.Wait()
206+
close(errCh)
207+
208+
var failures []string
209+
for err := range errCh {
210+
failures = append(failures, err.Error())
211+
}
212+
if len(failures) > 0 {
213+
return fmt.Errorf("%d failures:\n- %s", len(failures), strings.Join(failures, "\n- "))
214+
}
215+
return nil
216+
}
217+
218+
func (a *transactApp) transact() error {
219+
asset := a.newAsset()
220+
221+
if err := a.smartContract.CreateAsset(asset); err != nil {
222+
return err
223+
}
224+
fmt.Printf("Created asset %s\n", asset.ID)
225+
226+
if randomInt(2) == 0 {
227+
oldColor := asset.Color
228+
asset.Color = differentElement(colors, oldColor)
229+
if err := a.smartContract.UpdateAsset(asset); err != nil {
230+
return err
231+
}
232+
fmt.Printf("Updated color of asset %s from %s to %s\n", asset.ID, oldColor, asset.Color)
233+
}
234+
235+
if randomInt(4) == 0 {
236+
if err := a.smartContract.DeleteAsset(asset.ID); err != nil {
237+
return err
238+
}
239+
fmt.Printf("Deleted asset %s\n", asset.ID)
240+
}
241+
242+
return nil
243+
}
244+
245+
func (a *transactApp) newAsset() Asset {
246+
return Asset{
247+
ID: randomHexString(8),
248+
Color: randomElement(colors),
249+
Size: randomInt(maxInitialSize) + 1,
250+
AppraisedValue: float64(randomInt(maxInitialVal) + 1),
251+
}
252+
}
253+
254+
func randomHexString(length int) string {
255+
b := make([]byte, (length+1)/2)
256+
if _, err := rand.Read(b); err != nil {
257+
panic(fmt.Sprintf("failed to generate random bytes: %v", err))
258+
}
259+
return hex.EncodeToString(b)[:length]
260+
}
261+
262+
func randomInt(max int) int {
263+
n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
264+
if err != nil {
265+
panic(fmt.Sprintf("failed to generate random int: %v", err))
266+
}
267+
return int(n.Int64())
268+
}
269+
270+
func randomElement(values []string) string {
271+
return values[randomInt(len(values))]
272+
}
273+
274+
func differentElement(values []string, currentValue string) string {
275+
var candidates []string
276+
for _, v := range values {
277+
if v != currentValue {
278+
candidates = append(candidates, v)
279+
}
280+
}
281+
return randomElement(candidates)
282+
}
283+
284+
// cmdTransfer transfers ownership of an asset to a new owner in a different organisation.
285+
// Arguments: <assetId> <ownerName> <ownerMspId>
286+
func cmdTransfer(gw *client.Gateway, args []string) error {
287+
if len(args) < 3 {
288+
return fmt.Errorf("arguments: <assetId> <ownerName> <ownerMspId>")
289+
}
290+
291+
network := gw.GetNetwork(channelName())
292+
contract := network.GetContract(chaincodeName())
293+
294+
smartContract := NewAssetTransfer(contract)
295+
return smartContract.TransferAsset(args[0], args[1], args[2])
296+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
)
7+
8+
func gatewayEndpoint() (string, error) {
9+
return requireEnv("ENDPOINT")
10+
}
11+
12+
func mspID() (string, error) {
13+
return requireEnv("MSP_ID")
14+
}
15+
16+
func clientCertPath() (string, error) {
17+
return requireEnv("CERTIFICATE")
18+
}
19+
20+
func privateKeyPath() (string, error) {
21+
return requireEnv("PRIVATE_KEY")
22+
}
23+
24+
func tlsCertPath() string {
25+
return os.Getenv("TLS_CERT")
26+
}
27+
28+
func channelName() string {
29+
if v := os.Getenv("CHANNEL_NAME"); v != "" {
30+
return v
31+
}
32+
return "mychannel"
33+
}
34+
35+
func chaincodeName() string {
36+
if v := os.Getenv("CHAINCODE_NAME"); v != "" {
37+
return v
38+
}
39+
return "asset-transfer"
40+
}
41+
42+
func hostAlias() string {
43+
return os.Getenv("HOST_ALIAS")
44+
}
45+
46+
func requireEnv(name string) (string, error) {
47+
v := os.Getenv(name)
48+
if v == "" {
49+
printEnvUsage()
50+
return "", fmt.Errorf("environment variable %s not set", name)
51+
}
52+
return v, nil
53+
}
54+
55+
func printEnvUsage() {
56+
fmt.Fprintln(os.Stderr, "The following environment variables must be set:")
57+
fmt.Fprintln(os.Stderr, " ENDPOINT - Endpoint address of the gateway service")
58+
fmt.Fprintln(os.Stderr, " MSP_ID - User's organization Member Services Provider ID")
59+
fmt.Fprintln(os.Stderr, " CERTIFICATE - User's certificate file")
60+
fmt.Fprintln(os.Stderr, " PRIVATE_KEY - User's private key file")
61+
fmt.Fprintln(os.Stderr, "")
62+
fmt.Fprintln(os.Stderr, "The following environment variables are optional:")
63+
fmt.Fprintln(os.Stderr, " CHANNEL_NAME - Channel to which the chaincode is deployed")
64+
fmt.Fprintln(os.Stderr, " CHAINCODE_NAME - Chaincode deployed to the channel")
65+
fmt.Fprintln(os.Stderr, " TLS_CERT - TLS CA root certificate (only if using TLS and private CA)")
66+
fmt.Fprintln(os.Stderr, " HOST_ALIAS - TLS hostname override (only if TLS cert does not match endpoint)")
67+
}

0 commit comments

Comments
 (0)