什么是FabToken
将资产用tokens表示,将使你利用区块链账本去建立一个与物品之间的特殊状态与所有权,并使用一个被多方信任共识机制转移所有权。就像账本是安全的一样,资产也是安全的,并且未经拥有者的同意是无法被转移的。
Tokens可以代表有形资产,也可以代表无形资产。因为Tokens在未经拥有者同意的前提下是无法被转移的,并且那些转移tokens的交易都会在分布式账本上进行验证,所以使用tokens代表资产可以减少资产在多方转移时的风险和困难。
FabToken是一个允许你使用Hyperledger Fabric发行,转移,回收tokens的token管理系统。Tokens被存放在通道的账本上,并且可以被通道中的任何一个成员持有。FabToken使用Fabric的MSP去认证token拥有者的身份并管理他们得公私钥。FabToken的交易只有在发起方为拥有有效MSP身份的token拥有者时才是有效的。
FaToken利用通道提供的验证和信任提供了一个简单的接口token化资产。Tokens使用通道的orderers和peers来进行共识和验证。Tokens也使用通道的策略去管理哪些成员可以拥有和发行tokens。然而,用户不需要使用智能合约去创建或者管理tokens。Token的建立和资产所有权的确立并不需要通道成员的签名和复杂的业务逻辑去批准。Token的拥有者可以使用受信任的peers来创建token交易,而不需要其他组织去对交易背书。
Token的生命周期
Tokens和Hyperleger Fabric有相似的生命周期。他们可以被发行,转移和回收。
FabTokens使用UTXO模型来验证token交易。UTXO交易保证了资产的唯一性,使其只能被拥有者转移,并且无法被多次消费。每一笔交易必须有一组特定输入输出。输出为交易创建的新tokens。这些将被以未消费的状态列在账本上。输入为被另一笔交易创建的未消费的tokens。如果一笔交易是有效的,消费的tokens将被从通道长辈的数据库中移除。
基于UTXO模式的token生命周期保证了tokens的唯一性,并且只能被消费一次。Token被发行时,它被创建在一个未消费状态,并被发行者指定了一个拥有者。拥有者可以转移和回收Token。当token被转移时,创建者拥有token将作为输入。输出为被交易接收者拥有的新的token。输入的token变为以消费的,并从数据库中移除。这个过程中,输入输出所代表的资产总数是一样的。被回收的token被转移到一个空的拥有者。这使被回收的token不可能在被通道中的成员转移。
发行token
Tokens只能被发行者创建。发行者是通过IssuingPolicy授权发行tokens的通道成员。满足策略的用户可以使用issue交易在账本上增加tokens。
Tokens需要3个参数来创建:
例如,每个美元类型的token表示100美元。为了消费50美元或者增加50美元,新的token将被创建,并且代表新的美元数量。
IssuingPolicy也可以限制发行者可以发行哪种类型的token。在Fabric v2.0 Alpha release中,IssuingPolicy被设置为ANY,意味着所有通道成员可以发行任意类型的token。在之后的版本中用户将可以限制这个策略。
List
你可以使用List方法查询你拥有的未消费的token。成功的List指令会返回以下值:
Transfer
你可以转移你拥有的token给通道中其他成员来消费token。转移token需要提供以下值:
注意,转移交易是针对tokens所代表的基础资产的,而不是转让tokens本身。相反,新的tokens是由传输事务创建的。例如,如果你拥有价值100美元的tokens,你可以使用该tokens花费50美元。传输事务将创建两个新的token作为输出。一个价值50美元的tokens属于你,另一个价值50美元的tokens属于接收者。
转移到交易接收者的资产数量需要与输入的token所代表的数量相同。如果你不想转移tokens所代表的资产的全部数量,你可以只转移资产的一部分,交易将自动使你成为剩余余额的所有者。使用上面的例子,如果100美元的tokens只花费50美元,那么转账交易将自动创建一个价值50美元的新tokens,并且使你作为所有者。
要让交易成功,转移者需要具备以下条件:
Redeem
被回收的tokens无法再被消费。回收tokens意味着将从通道管理的事务网络总移除资产,并保证其不会被再次转移和更改。 如果供应链中的项目达到其最终目的地,或金融资产达到其期限,则表示该资产的tokens可以回收,因为该资产不再需要由通道成员使用。
拥有者想要回收tokens需要提供以下参数:
只有token所有者提交回收交易时,才能回收token。无需回收token所代表的全部资产。例如,如果您有一个代表100美元的token,并且想要回收50美元,那么回收交易将创建一个价值50美元的新token,并将另外50美元转移到一个没有所有者的受限账户。因为帐户没有所有者,50美元不能再由任何通道成员转移。
Token的交易流
FabToken绕开了Fabric的标准背书流程。针对chaincode的交易需要在足够多的组织的peers上调用,以满足chaincode背书策略。这样可以确保交易的结果与智能合约的逻辑一致,并且该逻辑的结果已由多个组织验证。由于token是资产的唯一表示形式,只能由其所有者转移或回收,因此不需要多个组织来验证初始交易。
FabToken的客户端使用受信任的peers,我们叫做prover peers,来创建token交易。例如,属于某个组织的peer的用户可以使用该peer查询其token并使用它们。在Fabric 2.0 Alpha中,任何加入了通道并启用了v2_0功能的peer都可以被用作为prover peer。
一旦客户端通过prover peer生成了token交易,就将该交易发送给了orderer。orderer再将交易发送给记账节点验证并添加到账本。记账节点检查交易是否符合UTXO交易模型,以及基础资产是否被重复使用或过度使用。
FabToken的使用
1.创建配置文件
Token cli使用来自每个组织的配置文件,其中的信息包含了哪些peers是组织信任的,交易将被发向哪个orderer。下面是org1的配置文件。请注意,org1使用自己的peer作为prove peer,并在文件的“prover peer”部分提供peer终端信息。
configorg1.json
{
"ChannelID":"",
"MSPInfo":{
"MSPConfigPath":"",
"MSPID":"Org1MSP",
"MSPType":"bccsp"
},
"Orderer":{
"Address":"orderer.example.com:7050",
"ConnectionTimeout":0,
"TLSEnabled":true,
"TLSRootCertFile":"/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem",
"ServerNameOverride":""
},
"CommitterPeer":{
"Address":"peer0.org1.example.com:7051",
"ConnectionTimeout":0,
"TLSEnabled":true,
"TLSRootCertFile":"/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt",
"ServerNameOverride":""
},
"ProverPeer":{
"Address":"peer0.org1.example.com:7051",
"ConnectionTimeout":0,
"TLSEnabled":true,
"TLSRootCertFile":"/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt",
"ServerNameOverride":""
}
}
configorg2.json
{
"ChannelID":"",
"MSPInfo":{
"MSPConfigPath":"",
"MSPID":"Org2MSP",
"MSPType":"bccsp"
},
"Orderer":{
"Address":"orderer.example.com:7050",
"ConnectionTimeout":0,
"TLSEnabled":true,
"TLSRootCertFile":"/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem",
"ServerNameOverride":""
},
"CommitterPeer":{
"Address":"peer0.org2.example.com:9051",
"ConnectionTimeout":0,
"TLSEnabled":true,
"TLSRootCertFile":"/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt",
"ServerNameOverride":""
},
"ProverPeer":{
"Address":"peer0.org2.example.com:9051",
"ConnectionTimeout":0,
"TLSEnabled":true,
"TLSRootCertFile":"/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt",
"ServerNameOverride":""
}
}
现在我们需要保存一个额外的文件,当我们转移token时将使用这个文件。在文本编辑器中创建一个新文件,并将下面的文件另存为shares.json
[
{
"recipient":"Org2MSP:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp",
"quantity":"50"
}
]
接下来启动Fabric系统。
Issue tokens
首先进入cli
docker exec -it cli bash
发行一个类型为BYFNcoins,数量为100的token。发行者为org1的admin,接收者为org1的user1
token issue --config /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/configorg1.json --mspPath /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp --channel mychannel --type BYFNcoins --quantity 100 --recipient Org1MSP:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
命令运行成功将有下列输出
2019-03-12 00:49:43.864 UTC [token.client] BroadcastReceive -> INFO 001 calling OrdererClient.broadcastReceive
Orderer Status [SUCCESS]
Committed [true]
可以使用list指令查询被创建的token
# List the tokens belonging to User1 of Org1
token list --config /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/configorg1.json --mspPath /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp --channel mychannel
命令运行成功将有下列输出
{"tx_id":"4e2664225d6a67508cfa539108383e682f3d03debb768aa7920851fdeea6f5b7"}
[BYFNcoins,100]
转移token
使用上面创建的shares.json作为转移策略,向org2的user1转移50BYFNcoins
# Transfer 50 BYFNcoins to User1 of Org2
# The split of coins tranfered to Org1 and Org2 is in shares.json
token transfer --config /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/configorg1.json --mspPath /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp --channel mychannel --tokenIDs '[{"tx_id":"4e2664225d6a67508cfa539108383e682f3d03debb768aa7920851fdeea6f5b7"}]' --shares /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/shares.json
使用list指令可以查询到当前org1的usr1只剩写50BYFNcoins,而org2的user1拥有了50BYFNcoins
回收token
使用下面的指令去回收org2,user1的25BYFNcoins
# Redeem tokens belonging to User1 of Org2
token redeem --config /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/configorg2.json --mspPath /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp --channel mychannel --tokenIDs '[{"tx_id":"4eaf466884586106f480dd0bb4f675ddaa54d1290ea53e9c24a2c1344fb71d2c","index":1}]' --quantity 25
再通过list指令查询org2,user1还剩下多少BYFNcoins
# List the tokens belonging to User1 of Org2
token list --config /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/configorg2.json --mspPath /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp --channel mychannel
如果我们再对org2的user1回收50BYFNcoins则会得到错误,因为他只剩下25BYFNcoins了
# Redeem tokens as Org1 belonging to Org2
token redeem --config /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/configorg2.json --mspPath /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp --channel mychannel --tokenIDs '[{"tx_id":"4eaf466884586106f480dd0bb4f675ddaa54d1290ea53e9c24a2c1344fb71d2c"}]' --quantity 50
response:
error from prover: the requestor does not own inputs