Home | 簡體中文 | 繁體中文 | 雜文 | 知乎專欄 | Github | OSChina 博客 | 雲社區 | 雲棲社區 | Facebook | Linkedin | 視頻教程 | 打賞(Donations) | About
知乎專欄多維度架構 | 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者”

26.4. 鏈碼案例

26.4.1. 模仿以太坊 ERC20 規範的 Hyperledger Fabric 實現 Token 通證

借用以太坊思維,將以太坊代幣合約搬到 hyperledger 上,一樣可以實現代幣的功能,這個代幣除了不能上交易所,基本滿足我們替代積分系統的需求,下面是我寫了這樣一個合約,在超級賬本上實現類似以太坊的代幣轉賬功能。

合約實現代幣轉賬,額度查詢,增發代幣,凍結賬號,鎖倉等等伺服器,功能與 ERC20 Token 相仿。

合約實例化所有代幣打入了 coinbase 賬號,分發代幣需要使用轉賬功能從 coinbase 想普通賬號轉賬

普通賬號消費可以在將代幣轉到 coinbase 賬號中,這樣就完成了代幣流通,形成一個閉環。

		
package main 

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	sc "github.com/hyperledger/fabric/protos/peer"
)

// Define the Smart Contract structure
type SmartContract struct {
}

type Token struct {
	Owner		string	`json:"Owner"`
	TotalSupply 	int	`json:"TotalSupply"`
	TokenName 	string	`json:"TokenName"`
	TokenSymbol 	string	`json:"TokenSymbol"`
	BalanceOf	map[string]int	`json:"BalanceOf"`
}

func (token *Token) initialSupply(){
	token.BalanceOf[token.Owner] = token.TotalSupply;
}

func (token *Token) transfer (_from string, _to string, _value int){
	if(token.BalanceOf[_from] >= _value){
		token.BalanceOf[_from] -= _value;
		token.BalanceOf[_to] += _value;
	}
}

func (token *Token) balance (_from string) int{
	return token.BalanceOf[_from]
}

func (token *Token) burn(_value int) {
	if(token.BalanceOf[token.Owner] >= _value){
		token.BalanceOf[token.Owner] -= _value;
		token.TotalSupply -= _value;
	}
}

func (token *Token) burnFrom(_from string, _value int) {
	if(token.BalanceOf[_from] >= _value){
		token.BalanceOf[_from] -= _value;
		token.TotalSupply -= _value;
	}
}

func (token *Token) mint(_value int) {
	
	token.BalanceOf[token.Owner] += _value;
	token.TotalSupply += _value;
	
}

func (s *SmartContract) Init(stub shim.ChaincodeStubInterface) sc.Response {
	return shim.Success(nil)
}

func (s *SmartContract) initLedger(stub shim.ChaincodeStubInterface, args []string) sc.Response {
	
	if len(args) != 3 {
                return shim.Error("Incorrect number of arguments. Expecting 2")
        }

	symbol:= args[0]
	name  := args[1]
	supply,_:= strconv.Atoi(args[2])

	token := &Token{
		Owner: "coinbase",
		TotalSupply: supply,
		TokenName: name,
		TokenSymbol: symbol,
		BalanceOf: map[string]int{}}
	
	token.initialSupply()

	tokenAsBytes, _ := json.Marshal(token)
	err := stub.PutState(symbol, tokenAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("Init %s \n", string(tokenAsBytes))
	
	return shim.Success(nil)
}

func (s *SmartContract) transferToken(stub shim.ChaincodeStubInterface, args []string) sc.Response {

	if len(args) != 4 {
		return shim.Error("Incorrect number of arguments. Expecting 4")
	}
	_from 	:= args[1]
	_to	:= args[2]
	_amount,_	:= strconv.Atoi(args[3])
	if(_amount <= 0){
		return shim.Error("Incorrect number of amount")
	}

	tokenAsBytes,err := stub.GetState(args[0])
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("transferToken - begin %s \n", string(tokenAsBytes))

	token := Token{}

	json.Unmarshal(tokenAsBytes, &token)
	token.transfer(_from, _to, _amount)

	tokenAsBytes, err = json.Marshal(token)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = stub.PutState(args[0], tokenAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("transferToken - end %s \n", string(tokenAsBytes))

	return shim.Success(nil)
}

func (s *SmartContract) balanceToken(stub shim.ChaincodeStubInterface, args []string) sc.Response {

	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting 2")
	}

	tokenAsBytes,err := stub.GetState(args[0])
	if err != nil {
		return shim.Error(err.Error())
	}
	token := Token{}

	json.Unmarshal(tokenAsBytes, &token)
	amount := token.balance(args[1])
	value := strconv.Itoa(amount)
	fmt.Printf("%s balance is %s \n", args[1], value)	
	//jsonVal, _ := json.Marshal(string(value))

	return shim.Success([]byte(value))
}

func (s *SmartContract) Invoke(stub shim.ChaincodeStubInterface) sc.Response {

	// Retrieve the requested Smart Contract function and arguments
	function, args := stub.GetFunctionAndParameters()
	// Route to the appropriate handler function to interact with the ledger appropriately
	if function == "balanceToken" {
		return s.balanceToken(stub, args)
	} else if function == "initLedger" {
		return s.initLedger(stub, args)
	} else if function == "transferToken" {
		return s.transferToken(stub, args)
	}

	return shim.Error("Invalid Smart Contract function name.")
}

// The main function is only relevant in unit test mode. Only included here for completeness.
func main() {

	// Create a new Smart Contract
	err := shim.Start(new(SmartContract))
	if err != nil {
		fmt.Printf("Error creating new Smart Contract: %s", err)
	}
}
		
		
		

這個合約用戶可以創建多套代幣,Args":["Token" 的第一參數 Token就是代幣名稱

		
peer chaincode invoke -C myc -n token -c '{"function":"initLedger","Args":["Apple","水果幣","1000000"]}'
peer chaincode invoke -C myc -n token -c '{"function":"initLedger","Args":["Token","蔬菜幣","1000000"]}'
peer chaincode invoke -C myc -n token -c '{"function":"initLedger","Args":["Oil","糧油幣","1000000"]}'
		
		

這個方案仍有不足之處,作者還不清楚如果用戶上線是多少,達到臨界值後,Hyperledger Fabric 無法在提供服務。

可能 chaincode_example02 做法更靠譜,就是不用 map 保存數據,將每個用戶存儲在 State 數據上。這裡需要創建多套代幣,所以使用了一個key 來存儲所有賬號。如果像 chaincode_example02 那樣就需要部署多個 chaincode 在 channel 中。管理起來比較複雜。

		
[root@localhost fabric-samples]# cd chaincode-docker-devmode/
[root@localhost chaincode-docker-devmode]# docker-compose up -d
[root@localhost chaincode-docker-devmode]# docker exec -it cli bash
root@765cbcd51fd7:/opt/gopath/src/chaincode#		
		
CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=token:1.0 ./chaincode/chaincode/token/token 

peer chaincode install -n token -v 1.0 -p chaincodedev/chaincode/chaincode/token
peer chaincode instantiate -C myc -n token -v 1.0 -c '{"Args":[""]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
peer chaincode instantiate -C myc -n token -v 1.0 -c '{"Args":["init"]}' 
sleep 10
peer chaincode invoke -C myc -n token -c '{"function":"initLedger","Args":["Token","Netkiller Coin","1000000"]}'

peer chaincode invoke -C myc -n token -c '{"function":"transferToken","Args":["Token","coinbase","netkiller","100"]}'		
peer chaincode invoke -C myc -n token -c '{"function":"balanceToken","Args":["Token","netkiller"]}'

peer chaincode invoke -C myc -n token -c '{"function":"transferToken","Args":["Token","netkiller","jerry","100"]}'

peer chaincode query -C myc -n token -c '{"function":"balanceToken","Args":["Token","netkiller"]}'
		
		

測試不存在賬號轉賬

		
peer chaincode invoke -C myc -n token -c '{"function":"transferToken","Args":["Token","neo","netkiller","100"]}'			
		
		

以太坊和超級賬本各有優勢,雖然超級賬本的Token功能無法和以太坊相比,但是使用超級賬本實現的Token交易不用礦工費。同事超級賬本還有一個優勢,就是可以在合約中調用另一個合約,這樣一來可以做出很多複雜的需求

例如我們在訂票的合約中,就可以直接從Token合約中直接扣款。

26.4.2. 萬能的通用合約

我們一般會在合約中定義結構體,然後序列化後存入 state 資料庫中。一旦資料結構變化,就需要升級 chaincode。

下面我們只實現了 create, find, update, delete 四個方法,沒有資料結構,用戶自行提交 json 格式或者其他序列化後的字元串數據。

		
package main

import (
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

type SmartContract struct {}

func (s *SmartContract) Init(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success(nil)
}

func (s *SmartContract) Query(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success(nil)
}

func (s *SmartContract) Invoke(stub shim.ChaincodeStubInterface) pb.Response {

	// Retrieve the requested Smart Contract function and arguments
	function, args := stub.GetFunctionAndParameters()
	// Route to the appropriate handler function to interact with the ledger appropriately
	if function == "create" {
		return s.create(stub, args)
	} else if function == "find" {
		return s.find(stub, args)
	} else if function == "update" {
		return s.update(stub, args)
	} else if function == "delete" {
		return s.delete(stub, args)
	}

	return shim.Error("Invalid Smart Contract function name.")
}

func (s *SmartContract) create(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting 2")
	}

	_key  	:= args[0]
	_data	:= args[1]

	if(_data == ""){
		return shim.Error("Incorrect string of data")
	}

	existAsBytes,err := stub.GetState(_key)
	if string(existAsBytes) != "" {
		fmt.Println("Failed to create account, Duplicate key.")
		return shim.Error("Failed to create account, Duplicate key.")
	}

	err = stub.PutState(_key, []byte(_data))
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("create %s %s \n", _key, string(_data))

	return shim.Success([]byte(_data))
}

func (s *SmartContract) find(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	_key  	:= args[0]
	_data, err := stub.GetState(_key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if string(_data) == "" {
		return shim.Error("The key isn't exist.")
	}else{
		fmt.Printf("query %s %s \n", _key, string(_data))
	}

	return shim.Success(_data)
}

func (s *SmartContract) update(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting 2")
	}

	_key  	:= args[0]
	_data	:= args[1]

	if(_data == ""){
		return shim.Error("Incorrect string of data")
	}

	err := stub.PutState(_key, []byte(_data))
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("update %s %s \n", _key, string(_data))
	}
	
	return shim.Success([]byte(_data))
}

// Deletes an entity from state
func (t *SmartContract) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	_key := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(_key)
	if err != nil {
		return shim.Error("Failed to delete state")
	}

	return shim.Success(nil)
}

func main() {

	err := shim.Start(new(SmartContract))
	if err != nil {
		fmt.Printf("Error creating new Smart Contract: %s", err)
	}
}
		
		

測試環境 Hyperledger Fabric v1.2.0

		
[root@localhost ~]# docker exec -it cli bash

root@8cb899359aec:/opt/gopath/src/chaincodedev# peer chaincode install -v 1.0 -n art -p chaincodedev/chaincode/art
root@8cb899359aec:/opt/gopath/src/chaincodedev# peer chaincode instantiate -C myc -n art -v 1.0 -c '{"Args":["init",""]}'

root@8cb899359aec:/opt/gopath/src/chaincodedev# peer chaincode instantiate -C myc -n art -v 1.0 -c '{"Args":[]}'
		
		

操作演示

		
root@8cb899359aec:/opt/gopath/src/chaincodedev# peer chaincode install -v 1.0 -n art -p chaincodedev/chaincode/art
2018-07-20 02:39:48.091 UTC [viperutil] getKeysRecursively -> DEBU 001 Found map[string]interface{} value for peer.BCCSP
2018-07-20 02:39:48.092 UTC [viperutil] unmarshalJSON -> DEBU 002 Unmarshal JSON: value cannot be unmarshalled: invalid character 'S' looking for beginning of value
2018-07-20 02:39:48.092 UTC [viperutil] getKeysRecursively -> DEBU 003 Found real value for peer.BCCSP.Default setting to string SW
2018-07-20 02:39:48.093 UTC [viperutil] getKeysRecursively -> DEBU 004 Found map[string]interface{} value for peer.BCCSP.SW
2018-07-20 02:39:48.093 UTC [viperutil] unmarshalJSON -> DEBU 005 Unmarshal JSON: value cannot be unmarshalled: invalid character 'S' looking for beginning of value
2018-07-20 02:39:48.093 UTC [viperutil] getKeysRecursively -> DEBU 006 Found real value for peer.BCCSP.SW.Hash setting to string SHA2
2018-07-20 02:39:48.094 UTC [viperutil] unmarshalJSON -> DEBU 007 Unmarshal JSON: value is not a string: 256
2018-07-20 02:39:48.094 UTC [viperutil] getKeysRecursively -> DEBU 008 Found real value for peer.BCCSP.SW.Security setting to int 256
2018-07-20 02:39:48.095 UTC [viperutil] getKeysRecursively -> DEBU 009 Found map[string]interface{} value for peer.BCCSP.SW.FileKeyStore
2018-07-20 02:39:48.095 UTC [viperutil] unmarshalJSON -> DEBU 00a Unmarshal JSON: value cannot be unmarshalled: unexpected end of JSON input
2018-07-20 02:39:48.095 UTC [viperutil] getKeysRecursively -> DEBU 00b Found real value for peer.BCCSP.SW.FileKeyStore.KeyStore setting to string 
2018-07-20 02:39:48.096 UTC [viperutil] getKeysRecursively -> DEBU 00c Found map[string]interface{} value for peer.BCCSP.PKCS11
2018-07-20 02:39:48.096 UTC [viperutil] getKeysRecursively -> DEBU 00d Found map[string]interface{} value for peer.BCCSP.PKCS11.FileKeyStore
2018-07-20 02:39:48.097 UTC [viperutil] unmarshalJSON -> DEBU 00e Unmarshal JSON: value is not a string: <nil>
2018-07-20 02:39:48.098 UTC [viperutil] getKeysRecursively -> DEBU 00f Found real value for peer.BCCSP.PKCS11.FileKeyStore.KeyStore setting to <nil> <nil>
2018-07-20 02:39:48.098 UTC [viperutil] unmarshalJSON -> DEBU 010 Unmarshal JSON: value is not a string: <nil>
2018-07-20 02:39:48.099 UTC [viperutil] getKeysRecursively -> DEBU 011 Found real value for peer.BCCSP.PKCS11.Library setting to <nil> <nil>
2018-07-20 02:39:48.099 UTC [viperutil] unmarshalJSON -> DEBU 012 Unmarshal JSON: value is not a string: <nil>
2018-07-20 02:39:48.100 UTC [viperutil] getKeysRecursively -> DEBU 013 Found real value for peer.BCCSP.PKCS11.Label setting to <nil> <nil>
2018-07-20 02:39:48.101 UTC [viperutil] unmarshalJSON -> DEBU 014 Unmarshal JSON: value is not a string: <nil>
2018-07-20 02:39:48.101 UTC [viperutil] getKeysRecursively -> DEBU 015 Found real value for peer.BCCSP.PKCS11.Pin setting to <nil> <nil>
2018-07-20 02:39:48.102 UTC [viperutil] unmarshalJSON -> DEBU 016 Unmarshal JSON: value is not a string: <nil>
2018-07-20 02:39:48.103 UTC [viperutil] getKeysRecursively -> DEBU 017 Found real value for peer.BCCSP.PKCS11.Hash setting to <nil> <nil>
2018-07-20 02:39:48.103 UTC [viperutil] unmarshalJSON -> DEBU 018 Unmarshal JSON: value is not a string: <nil>
2018-07-20 02:39:48.104 UTC [viperutil] getKeysRecursively -> DEBU 019 Found real value for peer.BCCSP.PKCS11.Security setting to <nil> <nil>
2018-07-20 02:39:48.104 UTC [viperutil] EnhancedExactUnmarshalKey -> DEBU 01a map[peer.BCCSP:map[Default:SW SW:map[Security:256 FileKeyStore:map[KeyStore:] Hash:SHA2] PKCS11:map[Pin:<nil> Hash:<nil> Security:<nil> FileKeyStore:map[KeyStore:<nil>] Library:<nil> Label:<nil>]]]
2018-07-20 02:39:48.105 UTC [bccsp_sw] openKeyStore -> DEBU 01b KeyStore opened at [/etc/hyperledger/msp/keystore]...done
2018-07-20 02:39:48.105 UTC [bccsp] initBCCSP -> DEBU 01c Initialize BCCSP [SW]
2018-07-20 02:39:48.106 UTC [msp] getPemMaterialFromDir -> DEBU 01d Reading directory /etc/hyperledger/msp/signcerts
2018-07-20 02:39:48.106 UTC [msp] getPemMaterialFromDir -> DEBU 01e Inspecting file /etc/hyperledger/msp/signcerts/peer.pem
2018-07-20 02:39:48.106 UTC [msp] getPemMaterialFromDir -> DEBU 01f Reading directory /etc/hyperledger/msp/cacerts
2018-07-20 02:39:48.106 UTC [msp] getPemMaterialFromDir -> DEBU 020 Inspecting file /etc/hyperledger/msp/cacerts/cacert.pem
2018-07-20 02:39:48.107 UTC [msp] getPemMaterialFromDir -> DEBU 021 Reading directory /etc/hyperledger/msp/admincerts
2018-07-20 02:39:48.107 UTC [msp] getPemMaterialFromDir -> DEBU 022 Inspecting file /etc/hyperledger/msp/admincerts/admincert.pem
2018-07-20 02:39:48.107 UTC [msp] getPemMaterialFromDir -> DEBU 023 Reading directory /etc/hyperledger/msp/intermediatecerts
2018-07-20 02:39:48.107 UTC [msp] getMspConfig -> DEBU 024 Intermediate certs folder not found at [/etc/hyperledger/msp/intermediatecerts]. Skipping. [stat /etc/hyperledger/msp/intermediatecerts: no such file or directory]
2018-07-20 02:39:48.107 UTC [msp] getPemMaterialFromDir -> DEBU 025 Reading directory /etc/hyperledger/msp/tlscacerts
2018-07-20 02:39:48.107 UTC [msp] getPemMaterialFromDir -> DEBU 026 Inspecting file /etc/hyperledger/msp/tlscacerts/tlsroot.pem
2018-07-20 02:39:48.107 UTC [msp] getPemMaterialFromDir -> DEBU 027 Reading directory /etc/hyperledger/msp/tlsintermediatecerts
2018-07-20 02:39:48.108 UTC [msp] getPemMaterialFromDir -> DEBU 028 Inspecting file /etc/hyperledger/msp/tlsintermediatecerts/tlsintermediate.pem
2018-07-20 02:39:48.108 UTC [msp] getPemMaterialFromDir -> DEBU 029 Reading directory /etc/hyperledger/msp/crls
2018-07-20 02:39:48.108 UTC [msp] getMspConfig -> DEBU 02a crls folder not found at [/etc/hyperledger/msp/crls]. Skipping. [stat /etc/hyperledger/msp/crls: no such file or directory]
2018-07-20 02:39:48.108 UTC [msp] getMspConfig -> DEBU 02b MSP configuration file not found at [/etc/hyperledger/msp/config.yaml]: [stat /etc/hyperledger/msp/config.yaml: no such file or directory]
2018-07-20 02:39:48.109 UTC [msp] newBccspMsp -> DEBU 02c Creating BCCSP-based MSP instance
2018-07-20 02:39:48.109 UTC [msp] New -> DEBU 02d Creating Cache-MSP instance
2018-07-20 02:39:48.109 UTC [msp] loadLocaMSP -> DEBU 02e Created new local MSP
2018-07-20 02:39:48.110 UTC [msp] Setup -> DEBU 02f Setting up MSP instance DEFAULT
2018-07-20 02:39:48.111 UTC [msp/identity] newIdentity -> DEBU 030 Creating identity instance for cert -----BEGIN CERTIFICATE-----
MIICYjCCAgigAwIBAgIRAL1fEAnz5zp4moJ8MdSb/lYwCgYIKoZIzj0EAwIwgYEx
CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g
RnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMQwwCgYDVQQLEwND
T1AxHDAaBgNVBAMTE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMTEyMTM0MTEx
WhcNMjcxMTEwMTM0MTExWjCBgTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlm
b3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhh
bXBsZS5jb20xDDAKBgNVBAsTA0NPUDEcMBoGA1UEAxMTY2Eub3JnMS5leGFtcGxl
LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGrsQ6oJpk6hDWf63HU3OSNd
bou9KNw/VIee1IngPDI4YJU7O+Xa/XLJuwnFv7BpR8Ytl3f+njC8i/RZP2/svO+j
XzBdMA4GA1UdDwEB/wQEAwIBpjAPBgNVHSUECDAGBgRVHSUAMA8GA1UdEwEB/wQF
MAMBAf8wKQYDVR0OBCIEIIpzkSIZzxBWVIV5unlgZJuyu2XPEeP8+y1uB6LLA5Qr
MAoGCCqGSM49BAMCA0gAMEUCIQDUh/+CC2dAICnYtACXspwUaaEbiyZxYIx+XDvW
o8VVcgIgGz5S4iC5+xkxgeaISPfxKTTVy6yzTdYGzCw1vPppjzo=
-----END CERTIFICATE-----
2018-07-20 02:39:48.112 UTC [msp/identity] newIdentity -> DEBU 031 Creating identity instance for cert -----BEGIN CERTIFICATE-----
MIICNjCCAd2gAwIBAgIRAMnf9/dmV9RvCCVw9pZQUfUwCgYIKoZIzj0EAwIwgYEx
CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g
RnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMQwwCgYDVQQLEwND
T1AxHDAaBgNVBAMTE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMTEyMTM0MTEx
WhcNMjcxMTEwMTM0MTExWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv
cm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEMMAoGA1UECxMDQ09QMR8wHQYD
VQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEZ8S4V71OBJpyMIVZdwYdFXAckItrpvSrCf0HQg40WW9XSoOOO76I+Umf
EkmTlIJXP7/AyRRSRU38oI8Ivtu4M6NNMEswDgYDVR0PAQH/BAQDAgeAMAwGA1Ud
EwEB/wQCMAAwKwYDVR0jBCQwIoAginORIhnPEFZUhXm6eWBkm7K7Zc8R4/z7LW4H
ossDlCswCgYIKoZIzj0EAwIDRwAwRAIgVikIUZzgfuFsGLQHWJUVJCU7pDaETkaz
PzFgsCiLxUACICgzJYlW7nvZxP7b6tbeu3t8mrhMXQs956mD4+BoKuNI
-----END CERTIFICATE-----
2018-07-20 02:39:48.181 UTC [msp/identity] newIdentity -> DEBU 032 Creating identity instance for cert -----BEGIN CERTIFICATE-----
MIICNjCCAd2gAwIBAgIRAMnf9/dmV9RvCCVw9pZQUfUwCgYIKoZIzj0EAwIwgYEx
CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g
RnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMQwwCgYDVQQLEwND
T1AxHDAaBgNVBAMTE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMTEyMTM0MTEx
WhcNMjcxMTEwMTM0MTExWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv
cm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEMMAoGA1UECxMDQ09QMR8wHQYD
VQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEZ8S4V71OBJpyMIVZdwYdFXAckItrpvSrCf0HQg40WW9XSoOOO76I+Umf
EkmTlIJXP7/AyRRSRU38oI8Ivtu4M6NNMEswDgYDVR0PAQH/BAQDAgeAMAwGA1Ud
EwEB/wQCMAAwKwYDVR0jBCQwIoAginORIhnPEFZUhXm6eWBkm7K7Zc8R4/z7LW4H
ossDlCswCgYIKoZIzj0EAwIDRwAwRAIgVikIUZzgfuFsGLQHWJUVJCU7pDaETkaz
PzFgsCiLxUACICgzJYlW7nvZxP7b6tbeu3t8mrhMXQs956mD4+BoKuNI
-----END CERTIFICATE-----
2018-07-20 02:39:48.183 UTC [msp/identity] newIdentity -> DEBU 033 Creating identity instance for cert -----BEGIN CERTIFICATE-----
MIICNjCCAd2gAwIBAgIRAMnf9/dmV9RvCCVw9pZQUfUwCgYIKoZIzj0EAwIwgYEx
CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g
RnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMQwwCgYDVQQLEwND
T1AxHDAaBgNVBAMTE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMTEyMTM0MTEx
WhcNMjcxMTEwMTM0MTExWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv
cm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEMMAoGA1UECxMDQ09QMR8wHQYD
VQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEZ8S4V71OBJpyMIVZdwYdFXAckItrpvSrCf0HQg40WW9XSoOOO76I+Umf
EkmTlIJXP7/AyRRSRU38oI8Ivtu4M6NNMEswDgYDVR0PAQH/BAQDAgeAMAwGA1Ud
EwEB/wQCMAAwKwYDVR0jBCQwIoAginORIhnPEFZUhXm6eWBkm7K7Zc8R4/z7LW4H
ossDlCswCgYIKoZIzj0EAwIDRwAwRAIgVikIUZzgfuFsGLQHWJUVJCU7pDaETkaz
PzFgsCiLxUACICgzJYlW7nvZxP7b6tbeu3t8mrhMXQs956mD4+BoKuNI
-----END CERTIFICATE-----
2018-07-20 02:39:48.183 UTC [msp] setupSigningIdentity -> DEBU 034 Signing identity expires at 2027-11-10 13:41:11 +0000 UTC
2018-07-20 02:39:48.185 UTC [msp] Validate -> DEBU 035 MSP DEFAULT validating identity
2018-07-20 02:39:48.187 UTC [grpc] Printf -> DEBU 036 parsed scheme: ""
2018-07-20 02:39:48.188 UTC [grpc] Printf -> DEBU 037 scheme "" not registered, fallback to default scheme
2018-07-20 02:39:48.188 UTC [grpc] Printf -> DEBU 038 ccResolverWrapper: sending new addresses to cc: [{peer:7051 0  <nil>}]
2018-07-20 02:39:48.188 UTC [grpc] Printf -> DEBU 039 ClientConn switching balancer to "pick_first"
2018-07-20 02:39:48.188 UTC [grpc] Printf -> DEBU 03a pickfirstBalancer: HandleSubConnStateChange: 0xc4203d7c40, CONNECTING
2018-07-20 02:39:48.190 UTC [grpc] Printf -> DEBU 03b pickfirstBalancer: HandleSubConnStateChange: 0xc4203d7c40, READY
2018-07-20 02:39:48.192 UTC [grpc] Printf -> DEBU 03c parsed scheme: ""
2018-07-20 02:39:48.192 UTC [grpc] Printf -> DEBU 03d scheme "" not registered, fallback to default scheme
2018-07-20 02:39:48.192 UTC [grpc] Printf -> DEBU 03e ccResolverWrapper: sending new addresses to cc: [{peer:7051 0  <nil>}]
2018-07-20 02:39:48.192 UTC [grpc] Printf -> DEBU 03f ClientConn switching balancer to "pick_first"
2018-07-20 02:39:48.192 UTC [grpc] Printf -> DEBU 040 pickfirstBalancer: HandleSubConnStateChange: 0xc420452130, CONNECTING
2018-07-20 02:39:48.194 UTC [grpc] Printf -> DEBU 041 pickfirstBalancer: HandleSubConnStateChange: 0xc420452130, READY
2018-07-20 02:39:48.197 UTC [msp] GetDefaultSigningIdentity -> DEBU 042 Obtaining default signing identity
2018-07-20 02:39:48.197 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 043 Using default escc
2018-07-20 02:39:48.198 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 044 Using default vscc
2018-07-20 02:39:48.198 UTC [chaincodeCmd] getChaincodeSpec -> DEBU 045 java chaincode disabled
2018-07-20 02:39:48.266 UTC [golang-platform] getCodeFromFS -> DEBU 046 getCodeFromFS chaincodedev/chaincode/art
2018-07-20 02:39:49.372 UTC [golang-platform] func1 -> DEBU 047 Discarding GOROOT package fmt
2018-07-20 02:39:49.372 UTC [golang-platform] func1 -> DEBU 048 Discarding provided package github.com/hyperledger/fabric/core/chaincode/shim
2018-07-20 02:39:49.372 UTC [golang-platform] func1 -> DEBU 049 Discarding provided package github.com/hyperledger/fabric/protos/peer
2018-07-20 02:39:49.373 UTC [golang-platform] GetDeploymentPayload -> DEBU 04a done
2018-07-20 02:39:49.373 UTC [container] WriteFileToPackage -> DEBU 04b Writing file to tarball: src/chaincodedev/chaincode/art/art.go
2018-07-20 02:39:49.378 UTC [msp/identity] Sign -> DEBU 04c Sign: plaintext: 0AC4070A5C08031A0C08F596C5DA0510...97DB3F010000FFFFD8DB7F9600140000 
2018-07-20 02:39:49.379 UTC [msp/identity] Sign -> DEBU 04d Sign: digest: EFE78D9C254C9A5795FAC35A6AC5A543AAD70322E6F756D1822E9BBEC11AD7E0 
2018-07-20 02:39:49.459 UTC [chaincodeCmd] install -> INFO 04e Installed remotely response:<status:200 payload:"OK" >