Skip to content

Commit 68c3677

Browse files
Fix high-throughput sample
Build failures because the startFabric.sh script specified that the chaincode required initialization, which is both legacy behavior and is unnecessary. The chaincode is updated to use the Contract API instead of the legacy / low-level chaincode API. The client application is also simplified. Signed-off-by: Mark S. Lewis <Mark.S.Lewis@outlook.com>
1 parent ad19505 commit 68c3677

12 files changed

Lines changed: 281 additions & 368 deletions

File tree

high-throughput/README.md

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Hyperledger Fabric, however, careful considerations need to be given to the data
3535
Let's look at some concrete use cases and how an organization might implement high-throughput storage. These cases will try and explore some of the
3636
advantages and disadvantages of such a system, and how to overcome them.
3737

38-
#### Example 1 (IOT): Boxer Construction Analysts
38+
### Example 1 (IOT): Boxer Construction Analysts
3939

4040
Boxer Construction Analysts is an IOT company focused on enabling real-time monitoring of large, expensive assets (machinery) on commercial
4141
construction projects. They've partnered with the only construction vehicle company in New York, Condor Machines Inc., to provide a reliable,
@@ -59,7 +59,7 @@ eventually be committed to the ledger in the order they were received. Additiona
5959
by a dashboard to provide live monitoring data. The only difference the engineers have to pay attention to in this case is to make sure the sensors can
6060
send deltas from the previous reading, rather than fixed readings.
6161

62-
#### Example 2 (Balance Transfer): Robinson Credit Co.
62+
### Example 2 (Balance Transfer): Robinson Credit Co.
6363

6464
Robinson Credit Co. provides credit and financial services to large businesses. As such, their accounts are large, complex, and accessed by many
6565
people at once at any time of the day. They want to switch to blockchain, but are having trouble keeping up with the number of deposits and
@@ -167,29 +167,19 @@ The application will query the variable after submitting the transaction. The re
167167

168168
We will now see what happens when you try to run 1000 concurrent updates using a traditional transaction. Run the following command to create a variable named `testvar2`:
169169

170-
```
171-
go run . update testvar2 100 +
172-
```
173-
174-
The variable will have a value of 100:
175-
176-
```
177-
2020/10/27 18:01:45 Value of variable testvar2 : 100
178-
```
179-
180-
Now lets try to update `testvar2` 1000 times in parallel:
181-
182170
```
183171
go run . manyUpdatesTraditional testvar2 100 +
184172
```
185173

186-
When the program ends, you may see that none of the updates succeeded.
174+
When the program ends, you should see that many of the updates failed and that the value is much lower than expected.
187175

188176
```
189-
2020/10/27 18:03:15 Final value of variable testvar2 : 100
177+
2025/09/12 10:59:30 submitting 1000 concurrent updates...
178+
2025/09/12 10:59:31 998 submit failures.
179+
2025/09/12 10:59:31 Value of variable testvar2: 200
190180
```
191181

192-
The transactions failed because multiple transactions in each block updated the same key. Because of these transactions generated read/write conflicts, the transactions included in each block were rejected in the validation stage.
182+
The transactions failed because multiple transactions in each block updated the same key concurrently. Because of this, these transactions generated read/write conflicts and the transactions included in each block were rejected in the validation stage.
193183

194184
You can can examine the peer logs to view the messages generated by the rejected blocks:
195185

high-throughput/application-go/app.go

Lines changed: 115 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ package main
99
import (
1010
"log"
1111
"os"
12+
"sync"
13+
"sync/atomic"
1214
"time"
1315

1416
"github.com/hyperledger/fabric-gateway/pkg/client"
1517
"github.com/hyperledger/fabric-gateway/pkg/hash"
16-
f "github.com/hyperledger/fabric-samples/high-throughput/application-go/functions"
18+
gatewaypb "github.com/hyperledger/fabric-protos-go-apiv2/gateway"
19+
"google.golang.org/grpc/status"
1720
)
1821

1922
func main() {
@@ -22,7 +25,7 @@ func main() {
2225

2326
if len(os.Args) <= 2 {
2427
log.Println("Usage: function variableName")
25-
log.Fatalf("functions: update manyUpdates manyUpdatesTraditional get prune delete")
28+
log.Fatalf("functions: update delete prune get manyUpdates updatestandard delstandard getstandard manyUpdatesTraditional")
2629
} else if (os.Args[1] == "update" || os.Args[1] == "manyUpdates" || os.Args[1] == "manyUpdatesTraditional") && len(os.Args) < 5 {
2730
log.Fatalf("error: provide value and operation")
2831
} else if len(os.Args) == 3 {
@@ -56,38 +59,117 @@ func main() {
5659
contract := gateway.GetNetwork("mychannel").GetContract("bigdatacc")
5760

5861
// Handle different functions
59-
if function == "update" {
60-
result, err := f.Update(contract, function, variableName, change, sign)
61-
if err != nil {
62-
log.Fatalf("error: %v", err)
63-
}
64-
log.Println("Value of variable", string(variableName), ": ", string(result))
62+
switch function {
63+
case "update":
64+
update(contract, variableName, change, sign)
65+
case "updatestandard":
66+
updateStandard(contract, variableName, change, sign)
67+
case "delete":
68+
delete(contract, variableName)
69+
case "prune":
70+
prune(contract, variableName)
71+
case "delstandard":
72+
delStandard(contract, variableName)
73+
case "get":
74+
get(contract, variableName)
75+
case "getstandard":
76+
getStandard(contract, variableName)
77+
case "manyUpdates":
78+
manyUpdates(contract, "Update", variableName, change, sign)
79+
get(contract, variableName)
80+
case "manyUpdatesTraditional":
81+
manyUpdates(contract, "UpdateStandard", variableName, change, sign)
82+
getStandard(contract, variableName)
83+
default:
84+
log.Fatalln("Unkown function:", function)
85+
}
86+
}
6587

66-
} else if function == "delete" || function == "prune" || function == "delstandard" {
67-
result, err := f.DeletePrune(contract, function, variableName)
68-
if err != nil {
69-
log.Fatalf("error: %v", err)
70-
}
71-
log.Println(string(result))
72-
} else if function == "get" || function == "getstandard" {
73-
result, err := f.Query(contract, function, variableName)
74-
if err != nil {
75-
log.Fatalf("error: %v", err)
76-
}
77-
log.Println("Value of variable", string(variableName), ": ", string(result))
78-
} else if function == "manyUpdates" {
79-
log.Println("submitting 1000 concurrent updates...")
80-
result, err := f.ManyUpdates(contract, "update", variableName, change, sign)
81-
if err != nil {
82-
log.Fatalf("error: %v", err)
83-
}
84-
log.Println("Final value of variable", string(variableName), ": ", string(result))
85-
} else if function == "manyUpdatesTraditional" {
86-
log.Println("submitting 1000 concurrent updates...")
87-
result, err := f.ManyUpdates(contract, "putstandard", variableName, change, sign)
88-
if err != nil {
89-
log.Fatalf("error: %v", err)
88+
func update(contract *client.Contract, variableName, change, sign string) {
89+
result, err := contract.SubmitTransaction("Update", variableName, change, sign)
90+
failOnError(err)
91+
log.Println(string(result))
92+
get(contract, variableName)
93+
}
94+
95+
func updateStandard(contract *client.Contract, variableName, change, sign string) {
96+
result, err := contract.SubmitTransaction("UpdateStandard", variableName, change, sign)
97+
failOnError(err)
98+
log.Printf("Value of variable %s: %s\n", variableName, result)
99+
}
100+
101+
func delete(contract *client.Contract, variableName string) {
102+
result, err := contract.SubmitTransaction("Delete", variableName)
103+
failOnError(err)
104+
log.Println(string(result))
105+
}
106+
107+
func prune(contract *client.Contract, variableName string) {
108+
result, err := contract.SubmitTransaction("Prune", variableName)
109+
failOnError(err)
110+
log.Println(string(result))
111+
}
112+
113+
func delStandard(contract *client.Contract, variableName string) {
114+
_, err := contract.SubmitTransaction("DelStandard", variableName)
115+
failOnError(err)
116+
log.Printf("Deleted %s.\n", variableName)
117+
}
118+
119+
func get(contract *client.Contract, variableName string) {
120+
result, err := contract.EvaluateTransaction("Get", variableName)
121+
failOnError(err)
122+
log.Printf("Value of variable %s: %s\n", variableName, result)
123+
}
124+
125+
func getStandard(contract *client.Contract, variableName string) {
126+
result, err := contract.EvaluateTransaction("GetStandard", variableName)
127+
failOnError(err)
128+
log.Printf("Value of variable %s: %s\n", variableName, result)
129+
}
130+
131+
func manyUpdates(contract *client.Contract, function, variableName, change, sign string) {
132+
log.Println("submitting 1000 concurrent updates...")
133+
134+
var failCount atomic.Uint32
135+
var wg sync.WaitGroup
136+
for range 1000 {
137+
wg.Add(1)
138+
go func() {
139+
defer wg.Done()
140+
_, err := contract.SubmitTransaction(function, variableName, change, sign)
141+
if err != nil {
142+
failCount.Add(1)
143+
}
144+
}()
145+
}
146+
147+
wg.Wait()
148+
149+
n := failCount.Load()
150+
if n > 0 {
151+
log.Printf("%v submit failures.", n)
152+
}
153+
}
154+
155+
func failOnError(err error) {
156+
if err == nil {
157+
return
158+
}
159+
160+
details := status.Convert(err).Details()
161+
if len(details) > 0 {
162+
log.Println("Error Details:")
163+
164+
for _, detail := range details {
165+
switch detail := detail.(type) {
166+
case *gatewaypb.ErrorDetail:
167+
log.Printf("- address: %s\n mspId: %s\n message: %s\n", detail.Address, detail.MspId, detail.Message)
168+
default:
169+
log.Printf("- %s", detail)
170+
}
90171
}
91-
log.Println("Final value of variable", string(variableName), ": ", string(result))
92172
}
173+
174+
log.Fatalf("error: %v", err)
93175
}

high-throughput/application-go/functions/deletePrune.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

high-throughput/application-go/functions/manyUpdates.go

Lines changed: 0 additions & 39 deletions
This file was deleted.

high-throughput/application-go/functions/query.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

high-throughput/application-go/functions/update.go

Lines changed: 0 additions & 27 deletions
This file was deleted.

high-throughput/application-go/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ go 1.23.0
44

55
require (
66
github.com/hyperledger/fabric-gateway v1.8.0
7+
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.7
78
google.golang.org/grpc v1.73.0
89
)
910

1011
require (
11-
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.7 // indirect
1212
github.com/miekg/pkcs11 v1.1.1 // indirect
1313
golang.org/x/crypto v0.40.0 // indirect
1414
golang.org/x/net v0.42.0 // indirect

high-throughput/chaincode-go/go.mod

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,25 @@ module github.com/hyperledger/fabric-samples/high-throughput/chaincode
22

33
go 1.23.0
44

5-
require (
6-
github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a
7-
github.com/hyperledger/fabric-protos-go v0.3.0
8-
)
5+
require github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0
96

107
require (
11-
github.com/golang/protobuf v1.5.3 // indirect
8+
github.com/go-openapi/jsonpointer v0.21.0 // indirect
9+
github.com/go-openapi/jsonreference v0.21.0 // indirect
10+
github.com/go-openapi/spec v0.21.0 // indirect
11+
github.com/go-openapi/swag v0.23.0 // indirect
12+
github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 // indirect
13+
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect
14+
github.com/josharian/intern v1.0.0 // indirect
15+
github.com/mailru/easyjson v0.7.7 // indirect
16+
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
17+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
18+
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
1219
golang.org/x/net v0.42.0 // indirect
1320
golang.org/x/sys v0.34.0 // indirect
1421
golang.org/x/text v0.27.0 // indirect
1522
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
16-
google.golang.org/grpc v1.56.3 // indirect
23+
google.golang.org/grpc v1.67.0 // indirect
1724
google.golang.org/protobuf v1.36.6 // indirect
25+
gopkg.in/yaml.v3 v3.0.1 // indirect
1826
)

0 commit comments

Comments
 (0)