Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.

Commit e4a9313

Browse files
author
Saad Karim
committed
[FAB-12058] Idemix attributes in chaincode
Chaincode that is used in the integration tests updated to serve as a example of how to get attributes in chaincode using the cid library for transactions that use idemix credentials. Change-Id: I3f468c0eade664f1fd1201cc8a015b8e3c0655a2 Signed-off-by: Saad Karim <skarim@us.ibm.com>
1 parent 6c6666b commit e4a9313

File tree

6 files changed

+252
-9
lines changed

6 files changed

+252
-9
lines changed
0 Bytes
Binary file not shown.

src/test/fixture/sdkintegration/e2e-2Orgs/v1.3/configtx.yaml

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Organizations:
6767
- host: peer0.org2.example.com
6868
port: 8051
6969

70-
- &Org3
70+
- &Org1Idemix
7171
# defaultorg defines the organization which is used in the sampleconfig
7272
# of the fabric.git development environment
7373
name: idemixMSP1
@@ -85,7 +85,7 @@ Organizations:
8585
- host: peer0.org3.example.com
8686
port: 7051
8787

88-
- &Org4
88+
- &Org2Idemix
8989
# defaultorg defines the organization which is used in the sampleconfig
9090
# of the fabric.git development environment
9191
name: idemixMSP2
@@ -271,7 +271,7 @@ Capabilities:
271271
# determined to be desired for all peers running v1.0.x, but the
272272
# modification of which would cause incompatibilities. Users should
273273
# leave this flag set to true.
274-
V1_2: true
274+
V1_3: true
275275
# V1_1_PVTDATA_EXPERIMENTAL is an Application capability to enable the
276276
# private data capability. It is only supported when using peers built
277277
# with experimental build tag. When set to true, private data
@@ -310,7 +310,6 @@ Profiles:
310310
Organizations:
311311
- *Org1
312312
- *Org2
313-
- *Org3
314313

315314
TwoOrgsChannel:
316315
Consortium: SampleConsortium
@@ -319,7 +318,6 @@ Profiles:
319318
Organizations:
320319
- *Org1
321320
- *Org2
322-
- *Org3
323321

324322
################################################################################
325323
#
@@ -419,8 +417,8 @@ Profiles:
419417
Organizations:
420418
- *Org1
421419
- *Org2
422-
- *Org3
423-
- *Org4
420+
- *Org1Idemix
421+
- *Org2Idemix
424422
Application:
425423
<<: *ApplicationDefaults
426424
Organizations:
@@ -435,8 +433,8 @@ Profiles:
435433
Organizations:
436434
- *Org1
437435
- *Org2
438-
- *Org3
439-
- *Org4
436+
- *Org1Idemix
437+
- *Org2Idemix
440438
Capabilities:
441439
<<: *ApplicationCapabilities1_3
442440

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package main
18+
19+
import (
20+
"fmt"
21+
"strconv"
22+
"strings"
23+
24+
"github.com/hyperledger/fabric/core/chaincode/shim"
25+
"github.com/hyperledger/fabric/core/chaincode/shim/ext/cid"
26+
pb "github.com/hyperledger/fabric/protos/peer"
27+
)
28+
29+
var logger = shim.NewLogger("example_cc0")
30+
31+
// SimpleChaincode example simple Chaincode implementation
32+
type SimpleChaincode struct {
33+
}
34+
35+
// Init initializes the chaincode state
36+
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
37+
logger.Info("########### example_cc Init ###########")
38+
39+
_, args := stub.GetFunctionAndParameters()
40+
var A, B string // Entities
41+
var Aval, Bval int // Asset holdings
42+
var err error
43+
44+
if len(args) != 4 {
45+
return shim.Error("Incorrect number of arguments. Expecting 4")
46+
}
47+
48+
// Initialize the chaincode
49+
A = args[0]
50+
Aval, err = strconv.Atoi(args[1])
51+
if err != nil {
52+
return shim.Error("Expecting integer value for asset holding")
53+
}
54+
B = args[2]
55+
Bval, err = strconv.Atoi(args[3])
56+
if err != nil {
57+
return shim.Error("Expecting integer value for asset holding")
58+
}
59+
logger.Infof("Aval = %d, Bval = %d\n", Aval, Bval)
60+
61+
// Write the state to the ledger
62+
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
63+
if err != nil {
64+
return shim.Error(err.Error())
65+
}
66+
67+
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
68+
if err != nil {
69+
return shim.Error(err.Error())
70+
}
71+
72+
if transientMap, err := stub.GetTransient(); err == nil {
73+
if transientData, ok := transientMap["result"]; ok {
74+
return shim.Success(transientData)
75+
}
76+
}
77+
return shim.Success(nil)
78+
79+
}
80+
81+
// Invoke makes payment of X units from A to B
82+
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
83+
logger.Info("########### example_cc Invoke ###########")
84+
85+
function, args := stub.GetFunctionAndParameters()
86+
87+
// Getting attributes from an idemix credential
88+
ou, found, err := cid.GetAttributeValue(stub, "ou");
89+
if err != nil {
90+
return shim.Error("Failed to get attribute 'ou'")
91+
}
92+
if !found {
93+
return shim.Error("attribute 'ou' not found")
94+
}
95+
if !strings.HasSuffix(ou, "department1") {
96+
return shim.Error(fmt.Sprintf("Incorrect 'ou' returned, got '%s' expecting to end with 'department1'", ou))
97+
}
98+
role, found, err := cid.GetAttributeValue(stub, "role");
99+
if err != nil {
100+
return shim.Error("Failed to get attribute 'role'")
101+
}
102+
if !found {
103+
return shim.Error("attribute 'role' not found")
104+
}
105+
if role != "member" {
106+
return shim.Error(fmt.Sprintf("Incorrect 'role' returned, got '%s' expecting 'member'", role))
107+
}
108+
109+
if function == "delete" {
110+
// Deletes an entity from its state
111+
return t.delete(stub, args)
112+
}
113+
114+
if function == "query" {
115+
// queries an entity state
116+
return t.query(stub, args)
117+
}
118+
119+
if function == "move" {
120+
// Deletes an entity from its state
121+
return t.move(stub, args)
122+
}
123+
124+
logger.Errorf("Unknown action, check the first argument, must be one of 'delete', 'query', or 'move'. But got: %v", args[0])
125+
return shim.Error(fmt.Sprintf("Unknown action, check the first argument, must be one of 'delete', 'query', or 'move'. But got: %v", args[0]))
126+
}
127+
128+
func (t *SimpleChaincode) move(stub shim.ChaincodeStubInterface, args []string) pb.Response {
129+
// must be an invoke
130+
var A, B string // Entities
131+
var Aval, Bval int // Asset holdings
132+
var X int // Transaction value
133+
var err error
134+
135+
if len(args) != 3 {
136+
return shim.Error("Incorrect number of arguments. Expecting 3, function followed by 2 names and 1 value")
137+
}
138+
139+
A = args[0]
140+
B = args[1]
141+
142+
// Get the state from the ledger
143+
// TODO: will be nice to have a GetAllState call to ledger
144+
Avalbytes, err := stub.GetState(A)
145+
if err != nil {
146+
return shim.Error("Failed to get state")
147+
}
148+
if Avalbytes == nil {
149+
return shim.Error("Entity not found")
150+
}
151+
Aval, _ = strconv.Atoi(string(Avalbytes))
152+
153+
Bvalbytes, err := stub.GetState(B)
154+
if err != nil {
155+
return shim.Error("Failed to get state")
156+
}
157+
if Bvalbytes == nil {
158+
return shim.Error("Entity not found")
159+
}
160+
Bval, _ = strconv.Atoi(string(Bvalbytes))
161+
162+
// Perform the execution
163+
X, err = strconv.Atoi(args[2])
164+
if err != nil {
165+
return shim.Error("Invalid transaction amount, expecting a integer value")
166+
}
167+
Aval = Aval - X
168+
Bval = Bval + X
169+
logger.Infof("Aval = %d, Bval = %d\n", Aval, Bval)
170+
171+
// Write the state back to the ledger
172+
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
173+
if err != nil {
174+
return shim.Error(err.Error())
175+
}
176+
177+
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
178+
if err != nil {
179+
return shim.Error(err.Error())
180+
}
181+
182+
if transientMap, err := stub.GetTransient(); err == nil {
183+
if transientData, ok := transientMap["event"]; ok {
184+
stub.SetEvent("event", transientData)
185+
}
186+
if transientData, ok := transientMap["result"]; ok {
187+
return shim.Success(transientData)
188+
}
189+
}
190+
return shim.Success(nil)
191+
}
192+
193+
// Deletes an entity from state
194+
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
195+
if len(args) != 1 {
196+
return shim.Error("Incorrect number of arguments. Expecting 1")
197+
}
198+
199+
A := args[0]
200+
201+
// Delete the key from the state in ledger
202+
err := stub.DelState(A)
203+
if err != nil {
204+
return shim.Error("Failed to delete state")
205+
}
206+
207+
return shim.Success(nil)
208+
}
209+
210+
// Query callback representing the query of a chaincode
211+
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
212+
213+
var A string // Entities
214+
var err error
215+
216+
if len(args) != 1 {
217+
return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
218+
}
219+
220+
A = args[0]
221+
222+
// Get the state from the ledger
223+
Avalbytes, err := stub.GetState(A)
224+
if err != nil {
225+
jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
226+
return shim.Error(jsonResp)
227+
}
228+
229+
if Avalbytes == nil {
230+
jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
231+
return shim.Error(jsonResp)
232+
}
233+
234+
jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
235+
logger.Infof("Query Response:%s\n", jsonResp)
236+
return shim.Success(Avalbytes)
237+
}
238+
239+
func main() {
240+
err := shim.Start(new(SimpleChaincode))
241+
if err != nil {
242+
logger.Errorf("Error starting Simple chaincode: %s", err)
243+
}
244+
}

src/test/java/org/hyperledger/fabric/sdkintegration/End2endIdemixIT.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
public class End2endIdemixIT extends End2endIT {
3636

3737
{
38+
CHAIN_CODE_FILEPATH = "sdkintegration/gocc/sampleIdemix";
3839
testName = "End2endIdemixIT"; //Just print out what test is really running.
3940
CHAIN_CODE_NAME = "idemix_example_go";
4041
testUser1 = "idemixUser";

0 commit comments

Comments
 (0)