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 Chaincode 开发详解
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法