Balance transfer를 활용한 블록체인 기반 투표 시스템
by 박지수, 정유나, 하유진, 유소영
1. 프로그램 구조
node.js 서버에 클라이언트를 위한 투표 웹 페이지를 올리고 클라이언트를 REST API와 EXPRESS.js를 이용하여 블록체인 네트워크와 연결시키고 클라이언트가 웹 어플리케이션을 통해 보내는 명령에 해당하는 체인코드를 실행할 수 있도록 하였다. 투표자 검증을 위해서는 mysql 데이터 베이스를 사용하였다.
사용자는 관리자와 투표자 두 종류로 나뉘며 투표자는 후보 중 한명을 선택하여 투표를 할 수 있고 운영자는 투표 결과를 확인할 수 있으며, 블록이 쌓이는 것을 모니터링할 수 있다.
2. 데이터 베이스
투표자 검증을 위해 사용한다. 블록체인 외에 별도의 데이터베이스를 사용한 이유는 블록에 누가 누구에게 투표했는지에 대한 정보를 넣지 않음으로써 투표의 비밀성을 보장하기 위함이다. 사용자는 회원가입이 되어있는 상태라고 가정하였으며, 사용자의 아이디와 비밀번호를 저장한 데이터베이스를 구성하였다. 테이블은 투표자 테이블, 관리자 테이블 두개로 비밀번호는 해시화하여 저장되며 투표자 테이블은 운영자 테이블과 다르게 단과대, 학과 정보와 투표 여부를 표시하는 column이 존재한다. 투표 여부를 표시하는 column은 투표자가 투표를 한번만 할 수 있도록 하기 위함이다.
3. 블록체인 네트워크 구조
balance transfer의 블록체인 네트워크의 구조는 organization 2개와 각 organization 당 peer 2개로 구성되어있다. 본 투표 시스템에서는 organization 1을 투표자 organization으로 사용하였으며, organizaiton 2를 운영자 organization으로 사용하였다. org1의 peer0, peer1은 공과대, 이과대를 나타낸다. 투표자가 로그인을 하면 해당 투표자의 단과대에 해당하는 peer에 대한 권한을 부여하는 방식으로 운영된다.
Balance transfer Github address
https://github.com/hyperledger/fabric-samples/tree/release-1.4/balance-transfer
Balance transfer
A sample Node.js app to demonstrate fabric-client & fabric-ca-client Node.js SDK APIs
Prerequisites and setup:
- Docker - v1.12 or higher
- Docker Compose - v1.8 or higher
- Git client - needed for clone commands
- Node.js v8.4.0 or higher
- Download Docker images
cd fabric-samples/balance-transfer/
Once you have completed the above setup, you will have provisioned a local network with the following docker container configuration:
- 2 CAs
- A SOLO orderer
- 4 peers (2 peers per Org)
Artifacts
- Crypto material has been generated using the cryptogen tool from Hyperledger Fabric and mounted to all peers, the orderering node and CA containers. More details regarding the cryptogen tool are available here.
- An Orderer genesis block (genesis.block) and channel configuration transaction (mychannel.tx) has been pre generated using the configtxgen tool from Hyperledger Fabric and placed within the artifacts folder. More details regarding the configtxgen tool are available here.
Running the sample program
There are two options available for running the balance-transfer sample For each of these options, you may choose to run with chaincode written in golang or in node.js.
Option 1:
Terminal Window 1
- Launch the network using docker-compose
docker-compose -f artifacts/docker-compose.yaml up
Terminal Window 2
- Install the fabric-client and fabric-ca-client node modules
npm install
- Start the node app on PORT 4000
PORT=4000 node app
Terminal Window 3
- Execute the REST APIs from the section Sample REST APIs Requests
Option 2:
Terminal Window 1
cd fabric-samples/balance-transfer
./runApp.sh
- This lauches the required network on your local machine
- Installs the fabric-client and fabric-ca-client node modules
- And, starts the node app on PORT 4000
Terminal Window 2
In order for the following shell script to properly parse the JSON, you must install jq
:
instructions https://stedolan.github.io/jq/
With the application started in terminal 1, next, test the APIs by executing the script - testAPIs.sh:
cd fabric-samples/balance-transfer
## To use golang chaincode execute the following command
./testAPIs.sh -l golang
## OR use node.js chaincode
./testAPIs.sh -l node
Sample REST APIs Requests
Login Request
- Register and enroll new users in Organization - Org1:
curl -s -X POST http://localhost:4000/users -H "content-type: application/x-www-form-urlencoded" -d 'username=Jim&orgName=Org1'
OUTPUT:
{
"success": true,
"secret": "RaxhMgevgJcm",
"message": "Jim enrolled Successfully",
"token": "<put JSON Web Token here>"
}
The response contains the success/failure status, an enrollment Secret and a JSON Web Token (JWT) that is a required string in the Request Headers for subsequent requests.
Create Channel request
curl -s -X POST \
http://localhost:4000/channels \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json" \
-d '{
"channelName":"mychannel",
"channelConfigPath":"../artifacts/channel/mychannel.tx"
}'
Please note that the Header authorization must contain the JWT returned from the POST /users
call
Join Channel request
curl -s -X POST \
http://localhost:4000/channels/mychannel/peers \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json" \
-d '{
"peers": ["peer0.org1.example.com","peer1.org1.example.com"]
}'
Install chaincode
curl -s -X POST \
http://localhost:4000/chaincodes \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json" \
-d '{
"peers": ["peer0.org1.example.com","peer1.org1.example.com"],
"chaincodeName":"mycc",
"chaincodePath":"github.com/example_cc/go",
"chaincodeType": "golang",
"chaincodeVersion":"v0"
}'
NOTE: chaincodeType must be set to node when node.js chaincode is used and chaincodePath must be set to the location of the node.js chaincode. Also put in the $PWD
ex:
curl -s -X POST \
http://localhost:4000/chaincodes \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json" \
-d '{
"peers": ["peer0.org1.example.com","peer1.org1.example.com"],
"chaincodeName":"mycc",
"chaincodePath":"$PWD/artifacts/src/github.com/example_cc/node",
"chaincodeType": "node",
"chaincodeVersion":"v0"
}'
Instantiate chaincode
curl -s -X POST \
http://localhost:4000/channels/mychannel/chaincodes \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json" \
-d '{
"peers": ["peer0.org1.example.com","peer1.org1.example.com"],
"chaincodeName":"mycc",
"chaincodeVersion":"v0",
"chaincodeType": "golang",
"args":["a","100","b","200"]
}'
NOTE: chaincodeType must be set to node when node.js chaincode is used
Invoke request
curl -s -X POST \
http://localhost:4000/channels/mychannel/chaincodes/mycc \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json" \
-d '{
"peers": ["peer0.org1.example.com","peer1.org1.example.com"],
"fcn":"move",
"args":["a","b","10"]
}'
NOTE: Ensure that you save the Transaction ID from the response in order to pass this string in the subsequent query transactions.
Chaincode Query
curl -s -X GET \
"http://localhost:4000/channels/mychannel/chaincodes/mycc?peer=peer0.org1.example.com&fcn=query&args=%5B%22a%22%5D" \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json"
Query Block by BlockNumber
curl -s -X GET \
"http://localhost:4000/channels/mychannel/blocks/1?peer=peer0.org1.example.com" \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json"
Query Transaction by TransactionID
curl -s -X GET http://localhost:4000/channels/mychannel/transactions/<put transaction id here>?peer=peer0.org1.example.com \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json"
NOTE: The transaction id can be from any previous invoke transaction, see results of the invoke request, will look something like 8a95b1794cb17e7772164c3f1292f8410fcfdc1943955a35c9764a21fcd1d1b3
.
Query ChainInfo
curl -s -X GET \
"http://localhost:4000/channels/mychannel?peer=peer0.org1.example.com" \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json"
Query Installed chaincodes
curl -s -X GET \
"http://localhost:4000/chaincodes?peer=peer0.org1.example.com&type=installed" \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json"
Query Instantiated chaincodes
curl -s -X GET \
"http://localhost:4000/chaincodes?peer=peer0.org1.example.com&type=instantiated" \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json"
Query Channels
curl -s -X GET \
"http://localhost:4000/channels?peer=peer0.org1.example.com" \
-H "authorization: Bearer <put JSON Web Token here>" \
-H "content-type: application/json"
Clean the network
The network will still be running at this point. Before starting the network manually again, here are the commands which cleans the containers and artifacts.
docker rm -f $(docker ps -aq)
docker rmi -f $(docker images | grep dev | awk '{print $3}')
rm -rf fabric-client-kv-org[1-2]
Network configuration considerations
You have the ability to change configuration parameters by either directly editing the network-config.yaml file or provide an additional file for an alternative target network. The app uses an optional environment variable "TARGET_NETWORK" to control the configuration files to use. For example, if you deployed the target network on Amazon Web Services EC2, you can add a file "network-config-aws.yaml", and set the "TARGET_NETWORK" environment to 'aws'. The app will pick up the settings inside the "network-config-aws.yaml" file.
IP Address** and PORT information
If you choose to customize your docker-compose yaml file by hardcoding IP Addresses and PORT information for your peers and orderer, then you MUST also add the identical values into the network-config.yaml file. The url and eventUrl settings will need to be adjusted to match your docker-compose yaml file.
peer1.org1.example.com:
url: grpcs://x.x.x.x:7056
eventUrl: grpcs://x.x.x.x:7058
Discover IP Address
To retrieve the IP Address for one of your network entities, issue the following command:
# this will return the IP Address for peer0
docker inspect peer0 | grep IPAddress
This work is licensed under a Creative Commons Attribution 4.0 International License.