Hyperledger fabricチェーンコード配置
82569 ワード
文書ディレクトリ一、書き込みチェーンコード 二、パッケージチェーンコード 三、配置チェーンコード 3.0環境変数 3.1取付チェーンコード 3.2インスタンス化チェーンコード 3.3クエリー 3.4実行 3.5アップグレードチェーンコード 3.6デバッグ 四、閲覧記録 4.1コンテナログ 4.2チェーン情報 4.3ブロックデータ 4.4取引情報 五、テスト 8、付録 九、付録 チェーンコード呼び出しチェーンコード チェーンコード照会チェーンコード チェーンコードの概念と使用
一、チェーンコードを書く
各chaincodeプログラムは実装する必要があります chiancodeインタフェース ,インタフェース内のメソッドは、送信されたトランザクションに応答するときに呼び出されます.特に、
各chaincodeについて、予め定義されたchaincodeインタフェース、特に
(1)Chaincodeの初期化
チェーンコードに必要な2つの方法
chaincodeのアップグレードも同様にこの関数を呼び出すことに注意してください.作成したchaincodeが既存のchaincodeをアップグレードする場合は、Init関数を適切に修正する必要があります.特に、「移行」操作やアップグレードで初期化する必要がある他のものがなければ、空の「Init」メソッドが提供されます.
二、パッケージチェーンコード
(1)スマート契約パッケージとは:スマート契約は、スマート契約導入仕様(ChaincodeDeploymentSpec)またはCDSによって定義される.CDSは、トークンおよびその他の属性(名前およびバージョンなど)に基づいて定義されるスマート契約パッケージ である.オプションのインスタンス化ポリシー. インテリジェント契約を「所有」するエンティティの一連の署名 (2)署名の目的インテリジェント和の所有権を確立するために パケットのコンテンツの検証を許可する .は、パケットが改ざんするか否かを検出することを可能にする .
(3)パッケージの作成方法
パッケージ契約には2つの方法があります.は、1つのスマート契約に複数の所有者を所有したい場合に、複数のアイデンティティフラグが契約に署名する必要がある.まず、署名されたスマート契約(署名されたCDS)を作成し、その後、シーケンスによって他の所有者に渡して署名します. もう1つは、インストールトランザクションを発行しているノードのアイデンティティ署名を発行するときに、自分が署名したCDS を配備することである.
次はスマート契約のパッケージです
パラメータの説明: を作成する. に署名することはできません. をインスタンス化する.
(4)署名パッケージ
署名されたスマート契約パッケージは、作成時に他の所有者と確認して署名することができ、このワークフローはスマート契約パッケージの帯域外署名をサポートします.
出力パッケージはSignedCDSとも呼ばれ、 CDSには、スマート契約のソースコード、名前、バージョン情報 が含まれています.インテリジェント契約のインスタンス化ポリシー、すなわちバックグラウンドポリシー. インテリジェント契約の所有者リストは、 を裏書的に定義する.
三、配置チェーンコード
配備チェーンコードはcliコンテナで行います.次のコマンドを実行してcliコンテナの内部に入る必要があります.
3.0環境変数
一時的な環境変数を設定して、次のコマンドを便利にし、繰り返し実行するとき、修正するのが面倒です. CHANNEL_NAMEチャネル名 CC_NAMEインテリジェント契約の名称 CC_VERSION契約のバージョン ORDERER_CA Ordererサービスの証明書 3.1チェーンコードの取り付け
インストール取引は、スマート契約のソースコードを である.
インストール取引は実質的に:ライフサイクルシステムインテリジェント契約(Lifecycle System chaincode,LSCC)に署名された提案を送信します.
注意:スマート契約を正常に実行するには、channelの各バックグラウンドノードにスマート契約をインストールする必要があります.
3.2インスタンス化チェーンコード
EXPRはAND ORを式として使用し、1つかEXPRのネスト構造を使用します.(l) を認めなければならない.(2) を承認する.(3) .
3.3クエリー
インテリジェント契約は、自身のステータスに直接アクセスできます.
通常、異なるスマート契約では直接アクセスできません.同じネットワークにある場合、適切な権限を与えることで、契約間アクセスの目的を達成することができ、異なるチャネルは直接、ステータスのみをクエリーすることができます.
3.4実行
実行後、クエリーを実行します.結果は9000で、
次は、2つのノードのバックグラウンドが必要なチェーンコードdemoです.
3.5アップグレードチェーンコード
アップグレードする前に、スマート契約の新しいバージョンを必要な裏書Peerにインストールする必要があります.インテリジェント契約の新しいバージョンをChannelにバインドするインスタンス化された取引のようなものをアップグレードします.契約には影響しません.旧バージョンのスマート契約は自動的に削除されません.古いバージョンの契約を自分で管理してください.
アップグレード契約は、新しいポリシーではなく、現在のスマート契約のインスタンス化で指定されたポリシーに基づいてチェックされます.アップグレード契約のこの取引は、古い契約の裏書き戦略に従って行われたことを意味します.
アップグレード・アクティビティでは、chaincode Init関数を呼び出してデータに関連する更新またはその他の操作を実行するため、スマート契約のアップグレード時にステータスの再設定を避けることに注意する必要があります.
3.6デバッグ
デバッグの開始
四、記録の表示
4.1コンテナログ
各独立したチェーンコードサービスコンテナをチェックして、各コンテナ内の分割取引を表示します.次に、各チェーン・サービス・コンテナのログの組合せを示します.
取得したのは、チェーンコードでカスタマイズされたprint文が出力した結果です.
4.2チェーン情報
印刷結果
4.3ブロックデータ
対応するブロックデータをそれぞれクエリーし、現在の作業ディレクトリにファイルとして保存します.
4.4取引情報
五、テスト
例:
チェーンコードの開発が完了した後、デバッグのためにブロックチェーン環境にチェーンコードを配置する必要はありません.セルテストコードは、shim.MockStubを使用して作成し、ネットワークのない環境で直接debugすることができます.
八、付録は、計算の入力として不確実性の難聴を使用することができない、例えば乱数を採用できない、あるいはシステムの現在時間を取得できないなどのチェーンコードは異なるノード上で複数回実行されるが、実行時間は厳密に一致せず、環境のクエリは異なるノード上で実行される結果が一致せず、最終的に共通認識 を達成できない.外部データインタフェースを呼び出すことによる繰返し計算を避ける:例えば、複数のノードが外部書き込みデータを複数回呼び出すインタフェースは、ブロックチェーンの外部繰返し計算を招く可能性があるこの場合、複数のチェーンコードの実行結果が一致する可能性があり、共通認識の失敗を招くことはないが、外部の一致性に影響を与える可能性がある.これは論理エラー である.
九、付録
チェーンコード呼び出しチェーンコード
チェーンコード照会チェーンコード
一、チェーンコードを書く
各chaincodeプログラムは実装する必要があります chiancodeインタフェース ,インタフェース内のメソッドは、送信されたトランザクションに応答するときに呼び出されます.特に、
Init
(初期化)方法は、chaincodeがinstantiate
(インスタンス化)またはupgrade
(アップグレード)の取引を受信したときに呼び出され、さらにchaincodeが初期化アプリケーションの状態を含む必要な初期化操作を円滑に実行する.Invoke
(呼び出し)メソッドは、invoke
(呼び出し)トランザクションに応答するときに、トランザクションを実行するために呼び出される.各chaincodeについて、予め定義されたchaincodeインタフェース、特に
Init
およびInvoke
関数インタフェースが実装される.だから私たちはまず私たちのchaincodeのために必要な依存を導入します.ここではchaincode shim packageとpeer protobuf packageを導入します.package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
)
(1)Chaincodeの初期化
チェーンコードに必要な2つの方法
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
// do something
return shim.Success(nil)
}
func (t TokenChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
if function == "" {
return shim.Error("no function err")
} else if function == "balance" {
return t.Balance(stub, args)
} else if function == "allowance" {
return t.Allowance(stub, args)
}
log.Errorf("%s was not found", function)
return shim.Error(fmt.Sprintf("%s was not found", function))
}
chaincodeのアップグレードも同様にこの関数を呼び出すことに注意してください.作成したchaincodeが既存のchaincodeをアップグレードする場合は、Init関数を適切に修正する必要があります.特に、「移行」操作やアップグレードで初期化する必要がある他のものがなければ、空の「Init」メソッドが提供されます.
二、パッケージチェーンコード
(1)スマート契約パッケージとは:
(3)パッケージの作成方法
パッケージ契約には2つの方法があります.
次はスマート契約のパッケージです
peer chaincode package -n $CC_NAME -p github.com/chaincode/justincc/demo1 -v $CC_VERSION -s -S -i "AND('Org1MSP.admin')" ccpack.out
パラメータの説明:
-s
パラメータとは、修飾されていないCDSを単純に作成するのではなく、複数の所有者によって署名されたパッケージを作成できることを意味する.-sが指定されている場合、他の所有者が署名する必要がある場合は、-sパラメータも指定する必要があります.そうでなければ、このプロセスは、CDSインスタンス化ポリシー以外の署名済みCDS -S
パラメータcore.yamlにLocakMspid属性値フラグがあるMSPを使用してプログラムの署名を指示します.このパラメータはオプションです.パッケージに署名がない場合に作成されます.他の所有者がsignpackageコマンドを使用して-i
パラメータはオプションで、スマート契約インスタンス化ポリシーを指定します.インスタンス化ポリシーとバックグラウンドポリシーは同じフォーマットです.インスタンス化チェーンコードのセクションで説明します.ポリシーが提供されていない場合、デフォルトポリシーが使用され、これにより、channelのMSPのadminアイデンティティをデフォルトで許可してスマート契約(4)署名パッケージ
署名されたスマート契約パッケージは、作成時に他の所有者と確認して署名することができ、このワークフローはスマート契約パッケージの帯域外署名をサポートします.
peer chaincode signpackage ccpack.out signedccpack.out
ccpack.out
とsignedccpack.out
はそれぞれ入力パケットと出力パケットであり、出力パケットにはローカルMSP署名を用いたパケットの付加署名が含まれている.出力パッケージはSignedCDSとも呼ばれ、
三、配置チェーンコード
配備チェーンコードはcliコンテナで行います.次のコマンドを実行してcliコンテナの内部に入る必要があります.
sudo docker exec -it cli bash
3.0環境変数
一時的な環境変数を設定して、次のコマンドを便利にし、繰り返し実行するとき、修正するのが面倒です.
export CHANNEL_NAME="mychannel"
export CC_NAME="demo1"
export CC_VERSION="1.0"
export ORDERER_CA="/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
インストール取引は、スマート契約のソースコードを
ChaincodeDeploymentSpec
(スマート契約導入仕様またはCDS)と呼ばれる指定されたフォーマットにパッケージ化し、スマート契約を実行するPeerノードにインストールします.peer chaincode install -n $CC_NAME -v $CC_VERSION -p github.com/chaincode/justincc/demo1
-p
パラメータはチェーンコードのソースコード経路であり、$GOPATH/src
に従ってアドレスされるインストール取引は実質的に:ライフサイクルシステムインテリジェント契約(Lifecycle System chaincode,LSCC)に署名された提案を送信します.
注意:スマート契約を正常に実行するには、channelの各バックグラウンドノードにスマート契約をインストールする必要があります.
3.2インスタンス化チェーンコード
peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_NAME -v $CC_VERSION -c '{"Args":["init","0x4e9ce36e442e55ecd9025b9a6e0d88485d628a67", "10000"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"
-P
オプションに注意して、裏書ポリシーを設定します.EXPR(E[, E ... ])
EXPRはAND ORを式として使用し、1つかEXPRのネスト構造を使用します.
AND(’Org1.member,’Org2.member’,’Org3.member’)
の3つの主体は同時に暗記し、署名OR(’Org1.member,'Org1.member')
の2つの本体のいずれかの裏書であり、署名OR(’Orgl.member', AND('Org2.member','Org3.member’))
主体1裏書承認署名または主2と主体3が同時に裏書し承認署名3.3クエリー
インテリジェント契約は、自身のステータスに直接アクセスできます.
peer chaincode query -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["balanceOf","0x4e9ce36e442e55ecd9025b9a6e0d88485d628a67"]}'
通常、異なるスマート契約では直接アクセスできません.同じネットワークにある場合、適切な権限を与えることで、契約間アクセスの目的を達成することができ、異なるチャネルは直接、ステータスのみをクエリーすることができます.
3.4実行
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_NAME --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -c '{"Args":["transfer","0x4e9ce36e442e55ecd9025b9a6e0d88485d628a67","0x742d35cc6634c0532925a3b844bc454e4438f44e","1000"]}'
実行後、クエリーを実行します.結果は9000で、
次は、2つのノードのバックグラウンドが必要なチェーンコードdemoです.
export CHANNEL_NAME="mychannel"
export CC_NAME="demo1"
export CC_VERSION="1.0"
export CC_PATH="github.com/chaincode/justincc/demo1"
export ORDERER_CA="/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
# peer0.org1
peer chaincode install -n $CC_NAME -v $CC_VERSION -p $CC_PATH
#
peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_NAME -v $CC_VERSION -c '{"Args":["init","0x4e9ce36e442e55ecd9025b9a6e0d88485d628a67", "10000"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')"
#
peer chaincode query -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["balanceOf","0x4e9ce36e442e55ecd9025b9a6e0d88485d628a67"]}'
# peer0.org2
CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_ADDRESS=peer0.org2.example.com:7051
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
# peer0.org2
peer chaincode install -n $CC_NAME -v $CC_VERSION -p $CC_PATH
# , 2 , 。
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_NAME --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["transfer","0x4e9ce36e442e55ecd9025b9a6e0d88485d628a67","0x742d35cc6634c0532925a3b844bc454e4438f44e","1000"]}'
#
peer chaincode query -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["balanceOf","0x742d35cc6634c0532925a3b844bc454e4438f44e"]}'
3.5アップグレードチェーンコード
アップグレードする前に、スマート契約の新しいバージョンを必要な裏書Peerにインストールする必要があります.インテリジェント契約の新しいバージョンをChannelにバインドするインスタンス化された取引のようなものをアップグレードします.契約には影響しません.旧バージョンのスマート契約は自動的に削除されません.古いバージョンの契約を自分で管理してください.
アップグレード契約は、新しいポリシーではなく、現在のスマート契約のインスタンス化で指定されたポリシーに基づいてチェックされます.アップグレード契約のこの取引は、古い契約の裏書き戦略に従って行われたことを意味します.
アップグレード・アクティビティでは、chaincode Init関数を呼び出してデータに関連する更新またはその他の操作を実行するため、スマート契約のアップグレード時にステータスの再設定を避けることに注意する必要があります.
3.6デバッグ
export FABRIC_CFG_PATH="/home/justin/go/src/github.com/hyperledger/fabric/sampleconfig"
デバッグの開始
peer node start --peer-chaincodedev
四、記録の表示
4.1コンテナログ
各独立したチェーンコードサービスコンテナをチェックして、各コンテナ内の分割取引を表示します.次に、各チェーン・サービス・コンテナのログの組合せを示します.
sudo docker logs dev-peer0.org1.example.com-demo1-1.0
取得したのは、チェーンコードでカスタマイズされたprint文が出力した結果です.
4.2チェーン情報
peer channel getinfo -c mychannel
印刷結果
Blockchain info: {"height":6,"currentBlockHash":"3WXFNm1NazzMlT4eSUfZGFrxuZKb8/TK/VtDg6yhz8U=","previousBlockHash":"KP20sPqasvkejG1PcJk9qzcL2vDAXIeS2BtJaoeOPv0="}
4.3ブロックデータ
対応するブロックデータをそれぞれクエリーし、現在の作業ディレクトリにファイルとして保存します.
peer channel fetch newest -c mychannel
peer channel fetch oldest -c mychannel
peer channel fetch config -c mychannel
peer channel fetch number -c mychannel
4.4取引情報
五、テスト
例:
チェーンコードの開発が完了した後、デバッグのためにブロックチェーン環境にチェーンコードを配置する必要はありません.セルテストコードは、shim.MockStubを使用して作成し、ネットワークのない環境で直接debugすることができます.
package main
import (
"fmt"
"testing"
"github.com/hyperledger/fabric/core/chaincode/shim"
)
//
func mockInit(t *testing.T, stub *shim.MockStub, args [][]byte) {
res := stub.MockInit("1", args)
if res.Status != shim.OK {
fmt.Println("Init failed", string(res.Message))
t.FailNow()
}
}
//
func initSchool(t *testing.T, stub *shim.MockStub, args []string) {
res := stub.MockInvoke("1", [][]byte{
[]byte("initSchool"), []byte(args[0]), []byte(args[1])
})
if res.Status != shim.OK {
fmt.Println("InitSchool failed:", args[0], string(res.Message))
t.FailNow()
}
}
//
func TestInitSchool(t *testing.T) {
scc := new(StudentChaincode)
stub := shim.NewMockStub("StudentChaincode", scc)
mockInit(t, stub, nil)
initSchool(t, stub, []string{"schoolId_A", " 1"})
initSchool(t, stub, []string{"schoolId_B", " 2"})
}
八、付録
九、付録
チェーンコード呼び出しチェーンコード
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package example04
import (
"fmt"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// This chaincode is a test for chaincode invoking another chaincode - invokes chaincode_example02
// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct{}
func toChaincodeArgs(args ...string) [][]byte {
bargs := make([][]byte, len(args))
for i, arg := range args {
bargs[i] = []byte(arg)
}
return bargs
}
// Init takes two arguments, a string and int. These are stored in the key/value pair in the state
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
var event string // Indicates whether event has happened. Initially 0
var eventVal int // State of event
var err error
_, args := stub.GetFunctionAndParameters()
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
// Initialize the chaincode
event = args[0]
eventVal, err = strconv.Atoi(args[1])
if err != nil {
return shim.Error("Expecting integer value for event status")
}
fmt.Printf("eventVal = %d
", eventVal)
err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
// Invoke invokes another chaincode - chaincode_example02, upon receipt of an event and changes event state
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var event string // Event entity
var eventVal int // State of event
var err error
if len(args) != 3 && len(args) != 4 {
return shim.Error("Incorrect number of arguments. Expecting 3 or 4")
}
chainCodeToCall := args[0]
event = args[1]
eventVal, err = strconv.Atoi(args[2])
if err != nil {
return shim.Error("Expected integer value for event state change")
}
channelID := ""
if len(args) == 4 {
channelID = args[3]
}
if eventVal != 1 {
fmt.Printf("Unexpected event. Doing nothing
")
return shim.Success(nil)
}
f := "invoke"
invokeArgs := toChaincodeArgs(f, "a", "b", "10")
response := stub.InvokeChaincode(chainCodeToCall, invokeArgs, channelID)
if response.Status != shim.OK {
errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", string(response.Payload))
fmt.Printf(errStr)
return shim.Error(errStr)
}
fmt.Printf("Invoke chaincode successful. Got response %s", string(response.Payload))
// Write the event state back to the ledger
err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
if err != nil {
return shim.Error(err.Error())
}
return response
}
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var event string // Event entity
var err error
if len(args) < 1 {
return shim.Error("Incorrect number of arguments. Expecting entity to query")
}
event = args[0]
var jsonResp string
// Get the state from the ledger
eventValbytes, err := stub.GetState(event)
if err != nil {
jsonResp = "{\"Error\":\"Failed to get state for " + event + "\"}"
return shim.Error(jsonResp)
}
if eventValbytes == nil {
jsonResp = "{\"Error\":\"Nil value for " + event + "\"}"
return shim.Error(jsonResp)
}
if len(args) > 3 {
chainCodeToCall := args[1]
queryKey := args[2]
channel := args[3]
f := "query"
invokeArgs := toChaincodeArgs(f, queryKey)
response := stub.InvokeChaincode(chainCodeToCall, invokeArgs, channel)
if response.Status != shim.OK {
errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error())
fmt.Printf(errStr)
return shim.Error(errStr)
}
jsonResp = string(response.Payload)
} else {
jsonResp = "{\"Name\":\"" + event + "\",\"Amount\":\"" + string(eventValbytes) + "\"}"
}
fmt.Printf("Query Response: %s
", jsonResp)
return shim.Success([]byte(jsonResp))
}
// Invoke is called by fabric to execute a transaction
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
if function == "invoke" {
return t.invoke(stub, args)
} else if function == "query" {
return t.query(stub, args)
}
return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"query\"")
}
チェーンコード照会チェーンコード
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package example05
import (
"fmt"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// This chaincode is a test for chaincode querying another chaincode - invokes chaincode_example02 and computes the sum of a and b and stores it as state
// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct{}
func toChaincodeArgs(args ...string) [][]byte {
bargs := make([][]byte, len(args))
for i, arg := range args {
bargs[i] = []byte(arg)
}
return bargs
}
// Init takes two arguments, a string and int. The string will be a key with
// the int as a value.
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
var sum string // Sum of asset holdings across accounts. Initially 0
var sumVal int // Sum of holdings
var err error
_, args := stub.GetFunctionAndParameters()
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
// Initialize the chaincode
sum = args[0]
sumVal, err = strconv.Atoi(args[1])
if err != nil {
return shim.Error("Expecting integer value for sum")
}
fmt.Printf("sumVal = %d
", sumVal)
// Write the state to the ledger
err = stub.PutState(sum, []byte(strconv.Itoa(sumVal)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
// Invoke queries another chaincode and updates its own state
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var sum, channelName string // Sum entity
var Aval, Bval, sumVal int // value of sum entity - to be computed
var err error
if len(args) < 2 {
return shim.Error("Incorrect number of arguments. Expecting atleast 2")
}
chaincodeName := args[0] // Expecting name of the chaincode you would like to call, this name would be given during chaincode install time
sum = args[1]
if len(args) > 2 {
channelName = args[2]
} else {
channelName = ""
}
// Query chaincode_example02
f := "query"
queryArgs := toChaincodeArgs(f, "a")
// if chaincode being invoked is on the same channel,
// then channel defaults to the current channel and args[2] can be "".
// If the chaincode being called is on a different channel,
// then you must specify the channel name in args[2]
response := stub.InvokeChaincode(chaincodeName, queryArgs, channelName)
if response.Status != shim.OK {
errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", response.Payload)
fmt.Printf(errStr)
return shim.Error(errStr)
}
Aval, err = strconv.Atoi(string(response.Payload))
if err != nil {
errStr := fmt.Sprintf("Error retrieving state from ledger for queried chaincode: %s", err.Error())
fmt.Printf(errStr)
return shim.Error(errStr)
}
queryArgs = toChaincodeArgs(f, "b")
response = stub.InvokeChaincode(chaincodeName, queryArgs, channelName)
if response.Status != shim.OK {
errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", response.Payload)
fmt.Printf(errStr)
return shim.Error(errStr)
}
Bval, err = strconv.Atoi(string(response.Payload))
if err != nil {
errStr := fmt.Sprintf("Error retrieving state from ledger for queried chaincode: %s", err.Error())
fmt.Printf(errStr)
return shim.Error(errStr)
}
// Compute sum
sumVal = Aval + Bval
// Write sumVal back to the ledger
err = stub.PutState(sum, []byte(strconv.Itoa(sumVal)))
if err != nil {
return shim.Error(err.Error())
}
fmt.Printf("Invoke chaincode successful. Got sum %d
", sumVal)
return shim.Success([]byte(strconv.Itoa(sumVal)))
}
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var sum, channelName string // Sum entity
var Aval, Bval, sumVal int // value of sum entity - to be computed
var err error
if len(args) < 2 {
return shim.Error("Incorrect number of arguments. Expecting atleast 2")
}
chaincodeName := args[0] // Expecting name of the chaincode you would like to call, this name would be given during chaincode install time
sum = args[1]
if len(args) > 2 {
channelName = args[2]
} else {
channelName = ""
}
// Query chaincode_example02
f := "query"
queryArgs := toChaincodeArgs(f, "a")
// if chaincode being invoked is on the same channel,
// then channel defaults to the current channel and args[2] can be "".
// If the chaincode being called is on a different channel,
// then you must specify the channel name in args[2]
response := stub.InvokeChaincode(chaincodeName, queryArgs, channelName)
if response.Status != shim.OK {
errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", response.Payload)
fmt.Printf(errStr)
return shim.Error(errStr)
}
Aval, err = strconv.Atoi(string(response.Payload))
if err != nil {
errStr := fmt.Sprintf("Error retrieving state from ledger for queried chaincode: %s", err.Error())
fmt.Printf(errStr)
return shim.Error(errStr)
}
queryArgs = toChaincodeArgs(f, "b")
response = stub.InvokeChaincode(chaincodeName, queryArgs, channelName)
if response.Status != shim.OK {
errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", response.Payload)
fmt.Printf(errStr)
return shim.Error(errStr)
}
Bval, err = strconv.Atoi(string(response.Payload))
if err != nil {
errStr := fmt.Sprintf("Error retrieving state from ledger for queried chaincode: %s", err.Error())
fmt.Printf(errStr)
return shim.Error(errStr)
}
// Compute sum
sumVal = Aval + Bval
fmt.Printf("Query chaincode successful. Got sum %d
", sumVal)
jsonResp := "{\"Name\":\"" + sum + "\",\"Value\":\"" + strconv.Itoa(sumVal) + "\"}"
fmt.Printf("Query Response:%s
", jsonResp)
return shim.Success([]byte(strconv.Itoa(sumVal)))
}
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
if function == "invoke" {
return t.invoke(stub, args)
} else if function == "query" {
return t.query(stub, args)
}
return shim.Success([]byte("Invalid invoke function name. Expecting \"invoke\" \"query\""))
}