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
==============================
借用以太坊思维,将以太坊代币合约搬到 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}}