Hyperledger Fabric 积分代币上链方案

本文节选自电子书《Netkiller Blockchain 手札》

Netkiller Blockchain 手札

本文作者提供有偿顾问服务,有意向致电 13113668890

Mr. Neo Chan, 陈景峯(BG7NYT)

中国广东省深圳市龙华新区民治街道溪山美地 518131 +86 13113668890 <netkiller@msn.com>

文档始创于2018-02-10

版权 © 2018 Netkiller(Neo Chan). All rights reserved.

版权声明

转载请与作者联系,转载时请务必标明文章原始出处和作者信息及本声明。

微信订阅号 netkiller-ebook (微信扫描二维码)

QQ:13721218 请注明“读者”

QQ群:128659835 请注明“读者”

网站:http://www.netkiller.cn

内容摘要

这一部关于区块链开发及运维的电子书。

为什么会写区块链电子书?因为2018年是区块链年。

这本电子书是否会出版(纸质图书)? 不会,因为互联网技术更迭太快,纸质书籍的内容无法实时更新,一本书动辄百元,很快就成为垃圾,你会发现目前市面的上区块链书籍至少是一年前写的,内容已经过时,很多例子无法正确运行。所以我不会出版,电子书的内容会追逐技术发展,及时跟进软件版本的升级,做到内容最新,至少是主流。

这本电子书与其他区块链书籍有什么不同?市面上大部分区块链书籍都是用2/3去讲区块链原理,只要不到 1/3 的干货,干货不够理论来凑,通篇将理论或是大谈特谈区块链行业,这些内容更多是头脑风暴,展望区块链,均无法落地实施。本书与那些书籍完全不同,不讲理论和原理,面向应用落地,注重例子,均是干货。

电子书更新频率?每天都会有新内容加入,更新频率最迟不会超过一周,更新内容请关注 https://github.com/netkiller/netkiller.github.io/commits/master

本文采用碎片化写作,原文会不定期更新,请尽量阅读原文。

http://www.netkiller.cn/blockchain/index.html

您的打赏是我的写作动力:http://www.netkiller.cn/blockchain/donations.html

==============================

传统币 Point (点) 仅仅是一个数字,数字存在数据库中,例如

Username	| Point (Integer)
-----------------------
Neo		| 1000
Jam		| 500

因为仅仅是一个数字,管理员可以随意修改,黑客也可随意修改,例如

update member set point = 1000000000000 where username = 'Neo'	

瞬间就有 1000000000000 点。由于是在数据库中修改,没有日志,不知道谁操作的,可能是开发人员,可以是管理员,也可能是黑客。

如何消费“点呢”,例如消费 100 个点:

update member set point = point - 100 where username = 'Neo'

传统币“点”,只是一个数字做加法和减法运算,安全性主要依赖于开发团队的能(期望别出BUG),运维团队的能力(被别黑客攻击),以及DBA(数据库管理员)的节操。

审计全靠开发人员打印出的日志。

现在我们再看看数字货币,跟很多朋友聊天中发现,他们还没有理解什么是币,他们认为数字代币花掉就没了(消失了),然后通过挖矿不停的产生新币,这种理解完全错误。

数字币是这样运作的,首先发行时设置了币的总量例如 1000000,然后将所有代币存入发行者账号,例如 account 1

account			| coin
---------------------------------
account1     	| 1000000
account2     	| 0
account3     	| 0
account4     	| 0
account5     	| 0				

现在 account2 游戏在线1小时奖励 10 个币,系统从账号account1转账5个币给 account2

account			| coin
---------------------------------
account1     	| 999990
account2     	| 10
account3     	| 0
account4     	| 0
account5     	| 0				

以此类推,从 account1 转账给其他账号。

account			| coin
---------------------------------
account1     	| 999960
account2     	| 10
account3     	| 10
account4     	| 10
account5     	| 10			

现在 account3 消费 5个币买了装备。从 account3 转 5 个币到 account1

account			| coin
---------------------------------
account1     	| 999965
account2     	| 10
account3     	| 5
account4     	| 10
account5     	| 10			

现在你应该看懂了把,代币是流通的,总量是不变的。account1 账号负责币的发行,回收等等工作。

同时任何转账将产生区块,历史数据永久记录。

-----------

借用以太坊思维,将以太坊代币合约搬到 hyperledger 上,一样可以实现代币的功能,这个代币除了不能上交易所,基本满足我们替代积分系统的需求,下面是我写了这样一个合约,在超级账本上实现类似以太坊的代币转账功能。

合约实现代币转账,额度查询,增发代币,冻结账号,锁仓等等服务器,功能与 ERC20 Token 相仿。

合约实例化所有代币打入了 coinbase 账号,分发代币需要使用转账功能从 coinbase 想普通账号转账

普通账号消费可以在将代币转到 coinbase 账号中,这样就完成了代币流通,形成一个闭环。

package main 

/* 
--------------------------------------------------
Author: netkiller <netkiller@msn.com>
Home: http://www.netkiller.cn
Data: 2018-03-19
--------------------------------------------------
*/

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

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



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"`
	FrozenAccount	map[string]int	`json:"FrozenAccount"`
	Lock		bool	`json:"Lock"`
}

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

func (token *Token) transfer (_from string, _to string, _value int){
	if(token.Lock) return
	if(token.FrozenAccount[_from] || token.FrozenAccount[_to]) return
	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.Lock) return
	if(token.BalanceOf[token.Owner] >= _value){
		token.BalanceOf[token.Owner] -= _value;
		token.TotalSupply -= _value;
	}
}

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

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

func (token *Token) setLock(_lock bool) {
	token.Lock = _look;	
}

func (token *Token) frozen(_account string, _status bool) {
	token.FrozenAccount[_account] = _status;	
}

type Account struct {
	Owner		string	`json:"Owner"`
	TokenName 	string	`json:"TokenName"`
	TokenSymbol string	`json:"TokenSymbol"`
	Balance		int		`json:"BalanceOf"`
	Frozen		bool	`json:"FrozenAccount"`
}

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

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{},
		FrozenAccount: map[string]int{},
		Lock: false}

	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) pb.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) mintToken(stub shim.ChaincodeStubInterface, args []string) pb.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())
	}
	// fmt.Printf("setLock - begin %s \n", string(tokenAsBytes))

	token := Token{}

	json.Unmarshal(tokenAsBytes, &token)
	_amount,_	:= strconv.Atoi(args[1])
	token.mint(_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("mintToken - end %s \n", string(tokenAsBytes))

	return shim.Success(nil)
}

func (s *SmartContract) setLock(stub shim.ChaincodeStubInterface, args []string) pb.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())
	}
	// fmt.Printf("setLock - begin %s \n", string(tokenAsBytes))

	token := Token{}

	json.Unmarshal(tokenAsBytes, &token)
	token.setLock(args[1])

	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("setLock - end %s \n", string(tokenAsBytes))

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

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

	token := Token{}

	json.Unmarshal(tokenAsBytes, &token)

	var status bool
	if(args[1] == "true"){
		status = true;
	}else{
		status = false
	}

	token.frozen(args[1],status)

	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("frozenAccount - end %s \n", string(tokenAsBytes))

	return shim.Success(nil)
}

func (s *SmartContract) balanceToken(stub shim.ChaincodeStubInterface, args []string) pb.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])
	status := token.FrozenAccount[args[1]]

	account := Account{
		Owner: token.Owner,
		TokenName: token.TokenName,
		TokenSymbol: token.TokenSymbol
		Balance: amount,
		Frozen: status}

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

	return shim.Success(tokenAsBytes)
}
func (s *SmartContract) Query(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	if function == "balanceToken" {
		return s.balanceToken(stub, args)
	} else {

	}
}

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 == "initLedger" {
		return s.initLedger(stub, args)
	} else if function == "setLock" {
		return s.setLock(stub, args)
	} else if function == "transferToken" {
		return s.transferToken(stub, args)
	} else if function == "frozenAccount" {
		return s.frozenAccount(stub, args)
	} else if function == "mintToken" {
		return s.mintToken(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)
	}
}

测试步骤

peer chaincode install -n token -v 1.0 -p chaincodedev/chaincode/token

peer chaincode instantiate -C myc -n token -v 1.0 -c '{"Args":[""]}' 
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"]}'

这个合约用户可以创建多套代币,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 中。管理起来比较复杂。

测试日志

Init {"Owner":"coinbase","TotalSupply":1000000,"TokenName":"Netkiller Coin","TokenSymbol":"Token","BalanceOf":{"coinbase":1000000}} 
 
transferToken - begin {"Owner":"coinbase","TotalSupply":1000000,"TokenName":"Netkiller Coin","TokenSymbol":"Token","BalanceOf":{"coinbase":1000000}} 
transferToken - end {"Owner":"coinbase","TotalSupply":1000000,"TokenName":"Netkiller Coin","TokenSymbol":"Token","BalanceOf":{"coinbase":999900,"netkiller":100}} 
netkiller balance is 100 
transferToken - begin {"Owner":"coinbase","TotalSupply":1000000,"TokenName":"Netkiller Coin","TokenSymbol":"Token","BalanceOf":{"coinbase":999900,"netkiller":100}} 
transferToken - end {"Owner":"coinbase","TotalSupply":1000000,"TokenName":"Netkiller Coin","TokenSymbol":"Token","BalanceOf":{"coinbase":999900,"netkiller":100}} 



transferToken - begin {"Owner":"coinbase","TotalSupply":1000000,"TokenName":"Netkiller Coin","TokenSymbol":"Token","BalanceOf":{"coinbase":999900,"netkiller":100}} 
transferToken - end {"Owner":"coinbase","TotalSupply":1000000,"TokenName":"Netkiller Coin","TokenSymbol":"Token","BalanceOf":{"coinbase":999900,"jerry":100,"netkiller":0}} 

延伸阅读《使用代币替代传统积分系统》

以太坊和超级账本各有优势,虽然超级账本的Token功能无法和以太坊相比,但是使用超级账本实现的Token交易不用矿工费。同事超级账本还有一个优势,就是可以在合约中调用另一个合约,这样一来可以做出很多复杂的需求。

例如我们在订票的合约中,就可以直接从Token合约中直接扣款。

--------------------- 2018-03-20 11:11 PM 更新 -----------------------

由于上面合约使用map 保存所有账号信息存在缺陷,经过一天的努力终于完成了Token合约改进

package main 

/* 
--------------------------------------------------
Author: netkiller <netkiller@msn.com>
Home: http://www.netkiller.cn
Data: 2018-03-20 11:00 PM
--------------------------------------------------

CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=token3:1.0 chaincode/token/token3

peer chaincode install -n token3 -v 1.0 -p chaincodedev/chaincode/token
peer chaincode instantiate -C myc -n token3 -v 1.0 -c '{"Args":[""]}' -P "OR ('Org1MSP.member','Org2MSP.member')"


peer chaincode invoke -C myc -n token3 -c '{"function":"createAccount","Args":["coinbase"]}'
peer chaincode invoke -C myc -n token3 -v 1.0 -c '{"function":"showAccount","Args":["coinbase"]}'
peer chaincode invoke -C myc -n token3 -c '{"function":"balanceAll","Args":["coinbase"]}'

peer chaincode invoke -C myc -n token3 -c '{"function":"initCurrency","Args":["Netkiller Token","NKC","1000000","coinbase"]}'
peer chaincode invoke -C myc -n token3 -c '{"function":"initCurrency","Args":["NEO Token","NEC","1000000","coinbase"]}'

peer chaincode invoke -C myc -n token3 -c '{"function":"setLock","Args":["true"]}'
peer chaincode invoke -C myc -n token3 -c '{"function":"setLock","Args":["false"]}'

peer chaincode invoke -C myc -n token3 -c '{"function":"mintToken","Args":["NKC","5000","coinbase"]}'

peer chaincode invoke -C myc -n token3 -c '{"function":"createAccount","Args":["netkiller"]}'
peer chaincode invoke -C myc -n token3 -c '{"function":"transferToken","Args":["coinbase","netkiller","NKC","100"]}'		
peer chaincode invoke -C myc -n token3 -c '{"function":"balance","Args":["netkiller","NKC"]}'

peer chaincode invoke -C myc -n token3 -c '{"function":"frozenAccount","Args":["netkiller","true"]}'

--------------------------------------------------

*/

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

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

type Msg struct{
	Status 	bool	`json:"Status"`
	Code 	int		`json:"Code"`
	Message string	`json:"Message"`
}

type Currency struct{
	TokenName 		string	`json:"TokenName"`
	TokenSymbol 	string	`json:"TokenSymbol"`
	TotalSupply 	float64	`json:"TotalSupply"`
}

type Token struct {
	Lock		bool	`json:"Lock"`
	Currency	map[string]Currency	`json:"Currency"`
}

func (token *Token) transfer (_from *Account, _to *Account, _currency string, _value float64) []byte{

	var rev []byte
	if (token.Lock){
		msg := &Msg{Status: false, Code: 0, Message: "锁仓状态,停止一切转账活动"}
		rev, _ = json.Marshal(msg)
		return rev
	}
	if(_from.Frozen ) {
		msg := &Msg{Status: false, Code: 0, Message: "From 账号冻结"}
		rev, _ = json.Marshal(msg)
		return rev
	}
	if( _to.Frozen) {
		msg := &Msg{Status: false, Code: 0, Message: "To 账号冻结"}
		rev, _ = json.Marshal(msg)
		return rev
	}
	if(!token.isCurrency(_currency)){
		msg := &Msg{Status: false, Code: 0, Message: "货币符号不存在"}
		rev, _ = json.Marshal(msg)
		return rev
	}
	if(_from.BalanceOf[_currency] >= _value){
		_from.BalanceOf[_currency] -= _value;
		_to.BalanceOf[_currency] += _value;

		msg := &Msg{Status: true, Code: 0, Message: "转账成功"}
		rev, _ = json.Marshal(msg)
		return rev
	}else{
		msg := &Msg{Status: false, Code: 0, Message: "余额不足"}
		rev, _ = json.Marshal(msg)
		return rev
	}
	
}
func (token *Token) initialSupply(_name string, _symbol string, _supply float64, _account *Account) []byte{
	if _,ok := token.Currency[_symbol]; ok {
		msg := &Msg{Status: false, Code: 0, Message: "代币已经存在"}
		rev, _ := json.Marshal(msg)
		return rev
	}

	if _account.BalanceOf[_symbol] > 0 {
		msg := &Msg{Status: false, Code: 0, Message: "账号中存在代币"}
		rev, _ := json.Marshal(msg)
		return rev
	}else{
		token.Currency[_symbol] = Currency{TokenName: _name, TokenSymbol: _symbol, TotalSupply: _supply}
		_account.BalanceOf[_symbol] = _supply

		msg := &Msg{Status: true, Code: 0, Message: "代币初始化成功"}
		rev, _ := json.Marshal(msg)
		return rev
	}

}

func (token *Token) mint(_currency string, _amount float64, _account *Account) []byte{
	if(!token.isCurrency(_currency)){
		msg := &Msg{Status: false, Code: 0, Message: "货币符号不存在"}
		rev, _ := json.Marshal(msg)
		return rev
	}
	cur := token.Currency[_currency]
	cur.TotalSupply += _amount;
	token.Currency[_currency] = cur
	_account.BalanceOf[_currency] += _amount;

	msg := &Msg{Status: true, Code: 0, Message: "代币增发成功"}
	rev, _ := json.Marshal(msg)
	return rev
	
}
func (token *Token) burn(_currency string, _amount float64, _account *Account) []byte{
	if(!token.isCurrency(_currency)){
		msg := &Msg{Status: false, Code: 0, Message: "货币符号不存在"}
		rev, _ := json.Marshal(msg)
		return rev
	}
	if(token.Currency[_currency].TotalSupply >= _amount){
		cur := token.Currency[_currency]
		cur.TotalSupply -= _amount;
		token.Currency[_currency] = cur
		_account.BalanceOf[_currency] -= _amount;

		msg := &Msg{Status: false, Code: 0, Message: "代币回收成功"}
		rev, _ := json.Marshal(msg)
		return rev
	}else{
		msg := &Msg{Status: false, Code: 0, Message: "代币回收失败,回收额度不足"}
		rev, _ := json.Marshal(msg)
		return rev
	}
	
}
func (token *Token) isCurrency(_currency string) bool {
	if _, ok := token.Currency[_currency]; ok {
		return true
	}else{
		return false
	}
}
func (token *Token) setLock(_look bool) bool {
	token.Lock = _look
	return token.Lock
}
type Account struct {
	Name			string	`json:"Name"`
	Frozen			bool	`json:"Frozen"`
	BalanceOf		map[string]float64	`json:"BalanceOf"`
}
func (account *Account) balance (_currency string) map[string]float64{
	bal	:= map[string]float64{_currency:account.BalanceOf[_currency]}
	return bal
}

func (account *Account) balanceAll() map[string]float64{
	return account.BalanceOf
}

// -----------
const TokenKey = "Token"

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

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

	token := &Token{Currency: map[string]Currency{}}

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

func (s *SmartContract) Query(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	if function == "balance" {
		return s.balance(stub, args)
	} else if function == "balanceAll" {
		return s.balanceAll(stub, args)
	} else if function == "showAccount" {
		return s.showAccount(stub, args)
	}
	return shim.Error("Invalid Smart Contract function name.")
}

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 == "initLedger" {
		return s.initLedger(stub, args)
	} else if function == "createAccount" {
		return s.createAccount(stub, args)
	} else if function == "initCurrency" {
		return s.initCurrency(stub, args)
	} else if function == "setLock" {
		return s.setLock(stub, args)
	} else if function == "transferToken" {
		return s.transferToken(stub, args)
	} else if function == "frozenAccount" {
		return s.frozenAccount(stub, args)
	} else if function == "mintToken" {
		return s.mintToken(stub, args)
	} else if function == "balance" {
		return s.balance(stub, args)
	} else if function == "balanceAll" {
		return s.balanceAll(stub, args)
	} else if function == "showAccount" {
		return s.showAccount(stub, args)
	} else if function == "showToken" {
		return s.showToken(stub, args)
	}

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

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

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

	key  := args[0]
	name  := args[0]
	existAsBytes,err := stub.GetState(key)
	fmt.Printf("GetState(%s) %s \n", key, string(existAsBytes))
	if string(existAsBytes) != "" {
		fmt.Println("Failed to create account, Duplicate key.")
		return shim.Error("Failed to create account, Duplicate key.")
	}

	account := Account{
		Name: name,
		Frozen: false,
		BalanceOf: map[string]float64{}}

	accountAsBytes, _ := json.Marshal(account)
	err = stub.PutState(key, accountAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("createAccount %s \n", string(accountAsBytes))

	return shim.Success(accountAsBytes)
}
func (s *SmartContract) initLedger(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	return shim.Success(nil)
}
func (s *SmartContract) showToken(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	tokenAsBytes,err := stub.GetState(TokenKey)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("GetState(%s)) %s \n", TokenKey, string(tokenAsBytes))
	}
	return shim.Success(tokenAsBytes)
}

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

	_name  := args[0]
	_symbol:= args[1]
	_supply,_:= strconv.ParseFloat(args[2], 64)
	_account := args[3]

	coinbaseAsBytes,err := stub.GetState(_account)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("Coinbase before %s \n", string(coinbaseAsBytes))

	coinbase := &Account{}

	json.Unmarshal(coinbaseAsBytes, &coinbase)

	token := Token{}
	existAsBytes,err := stub.GetState(TokenKey)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("GetState(%s)) %s \n", TokenKey, string(existAsBytes))
	}
	json.Unmarshal(existAsBytes, &token)
	
	result := token.initialSupply(_name,_symbol,_supply, coinbase)

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

	coinbaseAsBytes, _ = json.Marshal(coinbase)
	err = stub.PutState(_account, coinbaseAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("Coinbase after %s \n", string(coinbaseAsBytes))

	

	return shim.Success(result)
}

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

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

	fromAsBytes,err := stub.GetState(_from)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("fromAccount %s \n", string(fromAsBytes))
	fromAccount := &Account{}
	json.Unmarshal(fromAsBytes, &fromAccount)

	toAsBytes,err := stub.GetState(_to)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("toAccount %s \n", string(toAsBytes))
	toAccount := &Account{}
	json.Unmarshal(toAsBytes, &toAccount)

	tokenAsBytes,err := stub.GetState(TokenKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("Token %s \n", string(toAsBytes))
	token := Token{Currency: map[string]Currency{}}
	json.Unmarshal(tokenAsBytes, &token)

	result := token.transfer(fromAccount, toAccount, _currency, _amount)
	fmt.Printf("Result %s \n", string(result))

	fromAsBytes, err = json.Marshal(fromAccount)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = stub.PutState(_from, fromAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("fromAccount %s \n", string(fromAsBytes))
	}

	toAsBytes, err = json.Marshal(toAccount)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = stub.PutState(_to, toAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("toAccount %s \n", string(toAsBytes))
	}

	return shim.Success(result)
}
func (s *SmartContract) mintToken(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	
	if len(args) != 3 {
		return shim.Error("Incorrect number of arguments. Expecting 3")
	}
	_currency 	:= args[0]
	_amount,_	:= strconv.ParseFloat(args[1], 32)
	_account	:= args[2]

	coinbaseAsBytes,err := stub.GetState(_account)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("Coinbase before %s \n", string(coinbaseAsBytes))
	}

	coinbase := &Account{}
	json.Unmarshal(coinbaseAsBytes, &coinbase)

	tokenAsBytes,err := stub.GetState(TokenKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("Token before %s \n", string(tokenAsBytes))

	token := Token{}

	json.Unmarshal(tokenAsBytes, &token)
	
	result := token.mint(_currency, _amount, coinbase)

	tokenAsBytes, err = json.Marshal(token)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = stub.PutState(TokenKey, tokenAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Printf("Token after %s \n", string(tokenAsBytes))

	coinbaseAsBytes, _ = json.Marshal(coinbase)
	err = stub.PutState(_account, coinbaseAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("Coinbase after %s \n", string(coinbaseAsBytes))
	}

	fmt.Printf("mintToken %s \n", string(tokenAsBytes))

	return shim.Success(result)
}

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

	_look := args[0]

	tokenAsBytes,err := stub.GetState(TokenKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	// fmt.Printf("setLock - begin %s \n", string(tokenAsBytes))

	token := Token{}

	json.Unmarshal(tokenAsBytes, &token)

	if(_look == "true"){
		token.setLock(true)
	}else{
		token.setLock(false)
	}

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

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

	_account	:= args[0]
	_status		:= args[1]

	accountAsBytes,err := stub.GetState(_account)
	if err != nil {
		return shim.Error(err.Error())
	}
	// fmt.Printf("setLock - begin %s \n", string(tokenAsBytes))

	account := Account{}

	json.Unmarshal(accountAsBytes, &account)

	var status bool
	if(_status == "true"){
		status = true;
	}else{
		status = false
	}

	account.Frozen = status
	
	accountAsBytes, err = json.Marshal(account)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = stub.PutState(_account, accountAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("frozenAccount - end %s \n", string(accountAsBytes))
	}

	return shim.Success(nil)
}

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

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

	accountAsBytes,err := stub.GetState(_account)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("Account balance %s \n", string(accountAsBytes))
	}
	return shim.Success(accountAsBytes)
}

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

	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}
	_account 	:= args[0]
	_currency 	:= args[1]

	accountAsBytes,err := stub.GetState(_account)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("Account balance %s \n", string(accountAsBytes))
	}

	account := Account{}
	json.Unmarshal(accountAsBytes, &account)
	result := account.balance(_currency)

	resultAsBytes, _ := json.Marshal(result)
	fmt.Printf("%s balance is %s \n", _account, string(resultAsBytes))	

	return shim.Success(resultAsBytes)
}

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

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

	accountAsBytes,err := stub.GetState(_account)
	if err != nil {
		return shim.Error(err.Error())
	}else{
		fmt.Printf("Account balance %s \n", string(accountAsBytes))
	}

	account := Account{}
	json.Unmarshal(accountAsBytes, &account)
	result := account.balanceAll()
	resultAsBytes, _ := json.Marshal(result)
	fmt.Printf("%s balance is %s \n", _account, string(resultAsBytes))	

	return shim.Success(resultAsBytes)
}

// 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)
	}
}
 

测试日志

2018-03-20 14:46:11.957 UTC [shim] SetupChaincodeLogging -> INFO 001 Chaincode log level not provided; defaulting to: INFO
2018-03-20 14:46:11.957 UTC [shim] SetupChaincodeLogging -> INFO 002 Chaincode (build level: ) starting up ...
Coinbase before {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":4000,"NBA":999900}} 
Token before {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":20000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Token after {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":24000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Coinbase after {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":8000,"NBA":999900}} 
mintToken {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":24000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Account balance {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":8000,"NBA":999900}} 
jam balance is {"BBC":10000,"CCE":10000,"EJB":8000,"NBA":999900} 
Coinbase before {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":8000,"NBA":999900}} 
Token before {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":24000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Token after {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":28000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Coinbase after {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":12000,"NBA":999900}} 
mintToken {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":28000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Account balance {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":8000,"NBA":999900}} 
jam balance is {"BBC":10000,"CCE":10000,"EJB":8000,"NBA":999900} 


Coinbase before {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":12000,"NBA":999900}} 
Token before {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":28000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Token after {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":30000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Coinbase after {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":14000,"NBA":999900}} 
mintToken {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":30000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 


Account balance {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":14000,"NBA":999900}} 
jam balance is {"BBC":10000,"CCE":10000,"EJB":14000,"NBA":999900} 
Coinbase before {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":14000,"NBA":999900}} 
Token before {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":30000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Token after {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":36000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Coinbase after {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":20000,"NBA":999900}} 
mintToken {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":36000},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Account balance {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":14000,"NBA":999900}} 
jam balance is {"BBC":10000,"CCE":10000,"EJB":14000,"NBA":999900} 



frozenAccount - end {"Name":"netkiller","Frozen":true,"BalanceOf":{"NKC":300}} 
fromAccount {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":20000,"NBA":999900}} 
toAccount {"Name":"netkiller","Frozen":true,"BalanceOf":{"NKC":300}} 
Token {"Name":"netkiller","Frozen":true,"BalanceOf":{"NKC":300}} 
Result {"Status":false,"Code":0,"Message":"To 账号冻结"} 
fromAccount {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":20000,"NBA":999900}} 
toAccount {"Name":"netkiller","Frozen":true,"BalanceOf":{"NKC":300}} 
frozenAccount - end {"Name":"netkiller","Frozen":false,"BalanceOf":{"NKC":300}} 
fromAccount {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":20000,"NBA":999900}} 
toAccount {"Name":"netkiller","Frozen":false,"BalanceOf":{"NKC":300}} 
Token {"Name":"netkiller","Frozen":false,"BalanceOf":{"NKC":300}} 
Result {"Status":true,"Code":0,"Message":"转账成功"} 
fromAccount {"Name":"jam","Frozen":false,"BalanceOf":{"BBC":10000,"CCE":10000,"EJB":19900,"NBA":999900}} 
toAccount {"Name":"netkiller","Frozen":false,"BalanceOf":{"EJB":100,"NKC":300}} 



Account balance {"Name":"netkiller","Frozen":false,"BalanceOf":{"EJB":100,"NKC":300}} 
netkiller balance is {"NKC":300} 
Account balance {"Name":"netkiller","Frozen":false,"BalanceOf":{"EJB":100,"NKC":300}} 
netkiller balance is {"NKCs":0} 
Account balance {"Name":"netkiller","Frozen":false,"BalanceOf":{"EJB":100,"NKC":300}} 
netkiller balance is {"NKC":300} 
Coinbase before {"Name":"coinbase","Frozen":false,"BalanceOf":{"NKC":4600}} 
GetState(Token)) {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":36400},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NAS":{"TokenName":"NAS Token","TokenSymbol":"NAS","TotalSupply":2000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Init Token {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":36400},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NAS":{"TokenName":"NAS Token","TokenSymbol":"NAS","TotalSupply":2000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Coinbase after {"Name":"coinbase","Frozen":false,"BalanceOf":{"NKC":4600}} 




Coinbase before {"Name":"coinbase","Frozen":false,"BalanceOf":{"NKC":4600}} 
GetState(Token)) {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":36400},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NAS":{"TokenName":"NAS Token","TokenSymbol":"NAS","TotalSupply":2000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Init Token {"Lock":false,"Currency":{"BBC":{"TokenName":"NEO Token","TokenSymbol":"BBC","TotalSupply":10000},"CCE":{"TokenName":"NEO Token","TokenSymbol":"CCE","TotalSupply":10000},"EJB":{"TokenName":"NEO Token","TokenSymbol":"EJB","TotalSupply":36400},"K8":{"TokenName":"888","TokenSymbol":"K8","TotalSupply":1000000},"NAS":{"TokenName":"NAS Token","TokenSymbol":"NAS","TotalSupply":2000},"NBA":{"TokenName":"NEO Token","TokenSymbol":"NBA","TotalSupply":1000000},"NEC":{"TokenName":"NEO Token","TokenSymbol":"NEC","TotalSupply":1000000},"NKC":{"TokenName":"Netkiller Token","TokenSymbol":"NKC","TotalSupply":1005000},"NKCKK":{"TokenName":"Netkillersss","TokenSymbol":"NKCKK","TotalSupply":1000000},"TTC":{"TokenName":"NEO Token","TokenSymbol":"TTC","TotalSupply":1000000}}} 
Coinbase after {"Name":"coinbase","Frozen":false,"BalanceOf":{"NKC":4600}} 

作者相关文章:

区块链银行应用探索(Hyperledger fabric)

Hyperledger Fabric 积分代币上链方案

Hyperledger fabric Chaincode 开发详解

Hyperledger也能实现Token代币

食品安全溯源区块链解决方案探索

征信区块链解决方案探索(Hyperledger)

使用代币替代传统积分系统

竞猜活动区块链方案探索

游戏领域区块链探索

传统数据库也能实现区块链存储

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

Golang生产级可靠UDP库

kcp-go is a Production-Grade Reliable-UDP library for golang.

7612
来自专栏程序你好

在.Net Core中构建一个基本的区块链

1382
来自专栏菩提树下的杨过

ExtJs学习笔记(3)_GridPanel[XML做数据源]

这一节,将学习到除了用JSON做GridPanel的数据源外,还可以使用XML 一。静态示例 1.xml文件内容: <?xml version="1.0...

2308
来自专栏智能计算时代

Github: Use Watson Personality Insights to analyze sample text

image.png This SPSS Modeler node allows you to easily send text to the Watson P...

30410
来自专栏智能计算时代

Microservices Ecosystem Transit Map

…we assembled a map of the ecosystem to help guide practitioners, vendors, inves...

3994
来自专栏智能计算时代

Create a natural language classifier that identifies spam

With the advent of cognitive computing and smart machines, machine learning and ...

2996
来自专栏游戏杂谈

国际化语种名称的标识

国内因为版号的问题,导致很多游戏厂商选择出海。在国际化的市场要想取得好的成绩,就必须要做好深度的本地化,其中最基础的一块就是语言。

2642
来自专栏Kubernetes

Kubernetes GC in v1.3

本文是对kubernetes GC proposal的解读分析,是对GC in kubernetes v1.3的内部结构剖析,并记录了其中一些关键点,以便日后能...

3035
来自专栏hotqin888的专栏

MeritMS+jQuery.Gantt价值管理系统增加项目进度展示

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

2941
来自专栏WOLFRAM

Mathematica带您一起迎接五一

1924

扫码关注云+社区

领取腾讯云代金券