Skip to content

Commit ba777f3

Browse files
nickgaskichristo4ferris
authored andcommitted
[FAB-4371] - Chaincode Dev Mode
Adds a docker environment for running peer in dev mode pre-baked crypto and orderer/channel artifacts README still needs an updated curl command to bundle these scripts. simplified some of the paths add sacc from write your first chaincode remove binary Change-Id: Ic1537987c819f0350ae6dbf740fd00e1571045e5 Signed-off-by: Nick Gaski <ngaski@us.ibm.com> Signed-off-by: Christopher Ferris <chrisfer@us.ibm.com>
1 parent ec254d9 commit ba777f3

File tree

14 files changed

+724
-0
lines changed

14 files changed

+724
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ first-network/channel-artifacts/*.tx
1111
first-network/channel-artifacts/*.block
1212
first-network/crypto-config/*
1313

14+
chaincode-docker-devmode/myc.block
15+
chaincode-docker-devmode/chaincode/sacc/sacc
16+
chaincode-docker-devmode/chaincode/chaincode_example02/chaincode_example02

chaincode-docker-devmode/README.rst

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
Using dev mode
2+
==============
3+
4+
Normally chaincodes are started and maintained by peer. However in “dev
5+
mode", chaincode is built and started by the user. This mode is useful
6+
during chaincode development phase for rapid code/build/run/debug cycle
7+
turnaround.
8+
9+
We start "dev mode" by leveraging pre-generated orderer and channel artifacts for
10+
a sample dev network. As such, the user can immediately jump into the process
11+
of compiling chaincode and driving calls.
12+
13+
Install Fabric Samples
14+
----------------------
15+
16+
If you haven't already done so, please install the :doc:`samples`.
17+
18+
Navigate to the ``chaincode-docker-devmode`` directory of the ``fabric-samples``
19+
clone:
20+
21+
.. code:: bash
22+
23+
cd chaincode-docker-devmode
24+
25+
Download docker images
26+
^^^^^^^^^^^^^^^^^^^^^^
27+
28+
We need four docker images in order for "dev mode" to run against the supplied
29+
docker compose script. If you installed the ``fabric-samples`` repo clone and
30+
followed the instructions to :ref:`download-platform-specific-binaries`, then
31+
you should have the necessary Docker images installed locally.
32+
33+
.. note:: If you choose to manually pull the images then you must retag them as
34+
``latest``.
35+
36+
Issue a ``docker images`` command to reveal your local Docker Registry. You
37+
should see something similar to following:
38+
39+
.. code:: bash
40+
41+
docker images
42+
REPOSITORY TAG IMAGE ID CREATED SIZE
43+
hyperledger/fabric-tools latest e09f38f8928d 4 hours ago 1.32 GB
44+
hyperledger/fabric-tools x86_64-1.0.0-rc1-snapshot-f20846c6 e09f38f8928d 4 hours ago 1.32 GB
45+
hyperledger/fabric-orderer latest 0df93ba35a25 4 hours ago 179 MB
46+
hyperledger/fabric-orderer x86_64-1.0.0-rc1-snapshot-f20846c6 0df93ba35a25 4 hours ago 179 MB
47+
hyperledger/fabric-peer latest 533aec3f5a01 4 hours ago 182 MB
48+
hyperledger/fabric-peer x86_64-1.0.0-rc1-snapshot-f20846c6 533aec3f5a01 4 hours ago 182 MB
49+
hyperledger/fabric-ccenv latest 4b70698a71d3 4 hours ago 1.29 GB
50+
hyperledger/fabric-ccenv x86_64-1.0.0-rc1-snapshot-f20846c6 4b70698a71d3 4 hours ago 1.29 GB
51+
52+
.. note:: If you retrieved the images through the :ref:`download-platform-specific-binaries`,
53+
then you will see additional images listed. However, we are only concerned with
54+
these four.
55+
56+
Now open three terminals and navigate to your ``chaincode-docker-devmode``
57+
directory in each.
58+
59+
Terminal 1 - Start the network
60+
------------------------------
61+
62+
.. code:: bash
63+
64+
docker-compose -f docker-compose-simple.yaml up
65+
66+
The above starts the network with the ``SingleSampleMSPSolo`` orderer profile and
67+
launches the peer in "dev mode". It also launches two additional containers -
68+
one for the chaincode environment and a CLI to interact with the chaincode. The
69+
commands for create and join channel are embedded in the CLI container, so we
70+
can jump immediately to the chaincode calls.
71+
72+
Terminal 2 - Build & start the chaincode
73+
----------------------------------------
74+
75+
.. code:: bash
76+
77+
docker exec -it chaincode bash
78+
79+
You should see the following:
80+
81+
.. code:: bash
82+
83+
root@d2629980e76b:/opt/gopath/src/chaincode#
84+
85+
Now, compile your chaincode:
86+
87+
.. code:: bash
88+
89+
cd chaincode_example02
90+
go build
91+
92+
Now run the chaincode:
93+
94+
.. code:: bash
95+
96+
CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=mycc:0 ./chaincode_example02
97+
98+
The chaincode is started with peer and chaincode logs indicating successful registration with the peer.
99+
Note that at this stage the chaincode is not associated with any channel. This is done in subsequent steps
100+
using the ``instantiate`` command.
101+
102+
Terminal 3 - Use the chaincode
103+
------------------------------
104+
105+
Even though you are in ``--peer-chaincodedev`` mode, you still have to install the
106+
chaincode so the life-cycle system chaincode can go through its checks normally.
107+
This requirement may be removed in future when in ``--peer-chaincodedev`` mode.
108+
109+
We'll leverage the CLI container to drive these calls.
110+
111+
.. code:: bash
112+
113+
docker exec -it cli bash
114+
115+
.. code:: bash
116+
117+
peer chaincode install -p chaincodedev/chaincode/chaincode_example02 -n mycc -v 0
118+
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["init","a","100","b","200"]}' -C myc
119+
120+
Now issue an invoke to move ``10`` from ``a`` to ``b``.
121+
122+
.. code:: bash
123+
124+
peer chaincode invoke -n mycc -c '{"Args":["invoke","a","b","10"]}' -C myc
125+
126+
Finally, query ``a``. We should see a value of ``90``.
127+
128+
.. code:: bash
129+
130+
peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc
131+
132+
Testing new chaincode
133+
---------------------
134+
135+
By default, we mount only ``chaincode_example02``. However, you can easily test different
136+
chaincodes by adding them to the ``chaincode`` subdirectory and relaunching
137+
your network. At this point they will be accessible in your ``chaincode`` container.
138+
139+
.. Licensed under Creative Commons Attribution 4.0 International License
140+
https://creativecommons.org/licenses/by/4.0/
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
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+
//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
20+
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
21+
//to be modified as well with the new ID of chaincode_example02.
22+
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
23+
//hard-coding.
24+
25+
import (
26+
"fmt"
27+
"strconv"
28+
29+
"github.com/hyperledger/fabric/core/chaincode/shim"
30+
pb "github.com/hyperledger/fabric/protos/peer"
31+
)
32+
33+
// SimpleChaincode example simple Chaincode implementation
34+
type SimpleChaincode struct {
35+
}
36+
37+
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
38+
fmt.Println("ex02 Init")
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+
fmt.Printf("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+
return shim.Success(nil)
73+
}
74+
75+
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
76+
fmt.Println("ex02 Invoke")
77+
function, args := stub.GetFunctionAndParameters()
78+
if function == "invoke" {
79+
// Make payment of X units from A to B
80+
return t.invoke(stub, args)
81+
} else if function == "delete" {
82+
// Deletes an entity from its state
83+
return t.delete(stub, args)
84+
} else if function == "query" {
85+
// the old "Query" is now implemtned in invoke
86+
return t.query(stub, args)
87+
}
88+
89+
return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
90+
}
91+
92+
// Transaction makes payment of X units from A to B
93+
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
94+
var A, B string // Entities
95+
var Aval, Bval int // Asset holdings
96+
var X int // Transaction value
97+
var err error
98+
99+
if len(args) != 3 {
100+
return shim.Error("Incorrect number of arguments. Expecting 3")
101+
}
102+
103+
A = args[0]
104+
B = args[1]
105+
106+
// Get the state from the ledger
107+
// TODO: will be nice to have a GetAllState call to ledger
108+
Avalbytes, err := stub.GetState(A)
109+
if err != nil {
110+
return shim.Error("Failed to get state")
111+
}
112+
if Avalbytes == nil {
113+
return shim.Error("Entity not found")
114+
}
115+
Aval, _ = strconv.Atoi(string(Avalbytes))
116+
117+
Bvalbytes, err := stub.GetState(B)
118+
if err != nil {
119+
return shim.Error("Failed to get state")
120+
}
121+
if Bvalbytes == nil {
122+
return shim.Error("Entity not found")
123+
}
124+
Bval, _ = strconv.Atoi(string(Bvalbytes))
125+
126+
// Perform the execution
127+
X, err = strconv.Atoi(args[2])
128+
if err != nil {
129+
return shim.Error("Invalid transaction amount, expecting a integer value")
130+
}
131+
Aval = Aval - X
132+
Bval = Bval + X
133+
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
134+
135+
// Write the state back to the ledger
136+
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
137+
if err != nil {
138+
return shim.Error(err.Error())
139+
}
140+
141+
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
142+
if err != nil {
143+
return shim.Error(err.Error())
144+
}
145+
146+
return shim.Success(nil)
147+
}
148+
149+
// Deletes an entity from state
150+
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
151+
if len(args) != 1 {
152+
return shim.Error("Incorrect number of arguments. Expecting 1")
153+
}
154+
155+
A := args[0]
156+
157+
// Delete the key from the state in ledger
158+
err := stub.DelState(A)
159+
if err != nil {
160+
return shim.Error("Failed to delete state")
161+
}
162+
163+
return shim.Success(nil)
164+
}
165+
166+
// query callback representing the query of a chaincode
167+
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
168+
var A string // Entities
169+
var err error
170+
171+
if len(args) != 1 {
172+
return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
173+
}
174+
175+
A = args[0]
176+
177+
// Get the state from the ledger
178+
Avalbytes, err := stub.GetState(A)
179+
if err != nil {
180+
jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
181+
return shim.Error(jsonResp)
182+
}
183+
184+
if Avalbytes == nil {
185+
jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
186+
return shim.Error(jsonResp)
187+
}
188+
189+
jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
190+
fmt.Printf("Query Response:%s\n", jsonResp)
191+
return shim.Success(Avalbytes)
192+
}
193+
194+
func main() {
195+
err := shim.Start(new(SimpleChaincode))
196+
if err != nil {
197+
fmt.Printf("Error starting Simple chaincode: %s", err)
198+
}
199+
}

0 commit comments

Comments
 (0)