#Coluとは
https://www.colu.com/
https://www.colu.com/developers
例えばチケットなどの情報をmetadataとして付与したトランザクション情報を、
Bitcoinのネットワーク(mainnet,testnet)上に記録・送信する仕組み、プラットホーム。
colored coinsがベースとなっている。
metadataにはassetName,description,iconなどのフィールドがあり、
userdataとして自由にフィールドを指定することもできる。
その為、送金用途ではなくモノの所有権の管理などに利用できる。
インターネット上で公開されている巨大なBitcoinのネットワークに記録するため、改ざん防止などのセキュリティ面では安全。
※ただしAPIアクセスキーやprivateSeedの管理には注意が必要
node.jsでのアクセス手段と、JSON-RPCでのAPIアクセス手段が用意されている。
公式ページのドキュメントは新しい情報と古い情報が混在しているようで誤りもあるが、判断できないレベルではない。
登録した情報はcolored coins explorer
http://coloredcoins.org/explorer/
で確認することができる。
##Colored Coins
The Open Source Protocol for Creating Digital Assets On The Bitcoin Blockchain
http://coloredcoins.org/
#構築
CentOS7ベースとするが、Windowsでも可。
###事前準備
sudo yum install epel-release
sudo yum update
sudo yum upgrade
sudo yum install nodejs
###Coluのインストール
npm install --save colu@latest
###Redisインストールと実行
sudo yum install redis
sudo systemctl start redis.service
###Coluサーバー起動
sudo node $(which colu)
http server started on port 80
#クライアントアクセス
##nodeによるアクセス
mainnetへの接続にはAPI Keyが必要になる(testnetでは不要)。
これは
https://www.colu.com/getapikey
からのSigninとログイン後、ColuダッシュボードのSettingsメニューから作成・確認できる。
なお、ダッシュボード上にはサンプルのテンプレートなども用意されており、この画面からのオペレーションも可能。
###PrivateSeed取得
アクセス時にはPrivateSeedというユニークIDのようなものを毎回指定する。
まず、PrivateSeedを取得するAPIを実行する。
####get_private_seed.js
var Colu = require('colu')
var settings = {
network: 'testnet',
privateSeed: null
}
var colu = new Colu(settings)
colu.on('connect', function () {
var privateSeed = colu.hdwallet.getPrivateSeed()
console.log("privateSeed: ", privateSeed)
});
colu.init()
実行
node get_private_seed.js
###アドレス取得
次に、資産(Asset)の定義や送信などを行うアドレスを作成する。
####get_address.js
var Colu = require('colu')
var settings = {
network: 'testnet',
privateSeed: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}
var colu = new Colu(settings)
colu.on('connect', function () {
var address = colu.hdwallet.getAddress()
console.log("address: ", address)
})
colu.init()
実行
node get_address.js
###Asset定義
たとえばチケットを10枚定義してみる。
metadata.userData.metaには独自フィールドを定義できる。
####issue_asset.js
var Colu = require('colu')
var privateSeed = null
var assetId;
var settings = {
network: 'testnet',
privateSeed: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}
var colu = new Colu(settings)
colu.on('connect', function () {
var asset = {
amount: 10,
divisibility: 0,
reissueable: false,
transfer: [{
amount: 10
}],
metadata: {
'assetName': '福山☆冬の大感謝祭',
'issuer': 'チケットぴあ',
'description': '「福山☆冬の大感謝祭」が今年も開催決定!恒例の男性限定LIVE・女性限定LIVEも実施!!',
'urls': [{name:'icon', url: 'http://image.pia.jp/images/201611/201611180030_ex.jpg', mimeType: 'image/jpeg', dataHash: ''}],
'userData': {
'meta' : [
{key: 'Item ID', value: 2, type: 'Number'},
{key: 'Item Name', value: 'Item Name', type: 'String'},
{key: 'Company', value: 'TestCompany', type: 'String'},
{key: 'Address', value: 'Tokyo', type: 'String'}
]
}
}
}
colu.issueAsset(asset, function (err, body) {
if (err) return console.error(err)
console.log("Body: ", body)
})
})
colu.init()
実行
node issue_asset.js
結果
Body: { txHex: '01000000010594727b4b7a7c18de655e3cfa0401f0df93c87221dfd54a23e96b1e734dae11000000001976a9147ba647906203d3fe3726d1579a0e4b36e10a664088acffffffff0358020000000000001976a9147ba647906203d3fe6726d1579a0e4b36e10a564088ac00000000000000003e6a3c43430201782058b816f96e20e2a0510996f0ce0197a3375398c51b3a9db0d7cf4829bfa23d4d57793981bf7c6b6fc6be2995cc4bbcf160ea0a000a1058020000000000001976a9147ba747906203d3fe6726d1579a0e4b36e10a664088ac00000000',
assetId: 'La1oyjuvEnNE3jQf4qzjzmY9NpvyHcn7Ethjz3',
coloredOutputIndexes: [ 0 ],
financeTxid: '10ae4d731e6be9234ad5df2182c893dff00103fa3c5e65de287c6a4b7b728405',
txid: '8485be006d82dfb34215458eb0e21827ac1ad36bef23470cb0b01c282af14c20',
receivingAddresses: [ { amount: 10, address: 'mrnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' } ],
issueAddress: 'mrnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' }
ここで登録されたAssetデータは
http://coloredcoins.org/explorer/
でassetIdやaddress、txidなどから検索して表示することもできる。
###Asset取得
Asset情報取得。
getAssetDataではなく、getAssetMetadataも用意されていたが、こちらは500エラーが返されるため確認できず。metadataの情報はgetAssetDataでも取得できる。
####get_asset_data.js
var Colu = require('colu')
var assetId = 'La1oyjuvEnNE3jQf4qzjzmY9NpvyHcn7Ethjz3'
var addresses = ['mrnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX']
var settings = {
network: 'testnet',
privateSeed: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}
var args= {
assetId: assetId,
addresses: addresses,
numConfirmations: 0
}
var colu = new Colu(settings)
colu.on('connect', function () {
colu.coloredCoins.getAssetData(args, function (err, body) {
if (err) return console.error(err)
console.log("assetData: ", JSON.stringify(body))
})
})
colu.init()
実行
node get_asset_data.js
結果
{
"assetAmount": 10,
"assetData": [
{
"address": "mrnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"amount": 10,
"metadata": {
"aggregationPolicy": "aggregatable",
"assetId": "La1oyjuvEnNE3jQf4qzjzmY9NpvyHcn7Ethjz3",
"divisibility": 0,
"firstBlock": 1000001,
"issuanceTxid": "8485be006d82dfb34215458eb0e21827ac1ad36bef23470cb0b01c282af14c20",
"issueAddress": "mrnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"lockStatus": true,
"metadataOfIssuence": {
"data": {
"assetName": "福山☆冬の大感謝祭",
"description": "「福山☆冬の大感謝祭」が今年も開催決定!恒例の男性限定LIVE・女性限定LIVEも実施!!",
"issuer": "チケットぴあ",
"urls": [
{
"dataHash": "",
"mimeType": "image/jpeg",
"name": "icon",
"url": "http://image.pia.jp/images/201611/201611180030_ex.jpg"
}
],
"userData": {
"meta": [
{
"key": "Item ID",
"type": "Number",
"value": 2
},
{
"key": "Item Name",
"type": "String",
"value": "Item Name"
},
{
"key": "Company",
"type": "String",
"value": "TestCompany"
},
{
"key": "Address",
"type": "String",
"value": "Tokyo"
}
]
}
}
},
"numOfBurns": 0,
"numOfHolders": 1,
"numOfIssuance": 1,
"numOfTransfers": 0,
"sha2Issue": "98c52b3a9db0d7cf4828bfa23d4d57783982bf7c6b6fc6be2895cc4bbcf160ea",
"someUtxo": "8485be006d82dfb34215458eb0e21827ac1ad36bef23470cb0b01c282af14c20:0",
"totalSupply": 10
},
"utxo": "8485be006d82dfb34215458eb0e21827ac1ad36bef23470cb0b01c282af14c20:0"
}
],
"assetId": "La1oyjuvEnNE3jQf4qzjzmY9NpvyHcn7Ethjz3",
"assetTotalAmount": 10
}
###Asset送信
Assetの送信。
送信先のアドレスは先に作っておく。
####send_asset_data.js
var Colu = require('colu')
var settings = {
network: 'testnet',
privateSeed: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}
var colu = new Colu(settings)
var assetId = 'La1oyjuvEnNE3jQf4qzjzmY9NpvyHcn7Ethjz3'
var fromAddress = 'mrnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
var toAddress = 'mj6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
var send = {
from: [fromAddress],
to: [{
address: toAddress,
assetId: assetId,
amount: 1
}]
};
colu.on('connect', function () {
colu.sendAsset(send, function (err, body) {
if (err) return console.error(err)
console.log("Body: ",body)
})
})
colu.init()
実行
node send_asset_data.js
これで、fromAddressからtoAddressにAssetが1つ送信される。
実行結果のレスポンスにtxidを含むため、explorerをtxidで検索するか、
送信元、送信先のアドレスで検索すれば、送信したトランザクションの内容を見ることができる。
送信側からはamountがマイナス1され、受信側はプラス1される。
###使う際
metadataはissueのタイミングでのみ設定できる。
そのため、たとえばチケットの基本情報を定義することは可能だが、配布したチケットに個別の情報を持たせることはできない。
issue時に、発行枚数分でamountを定義し、そのうち1amountを購入者に送る。
購入者が保有しているかどうかは、addressからgetAssetDataなどで確認する形になる。
###Assetの廃棄
個別のアドレスが保有しているAssetを廃棄する(無効にする)場合、
burnAssetを使用する。廃棄ととるか、使用済みの位置づけにするか、使い方次第。
####burn_asset.js
var Colu = require('colu')
var privateSeed = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
var assetId = 'La1oyjuvEnNE3jQf4qzjzmY9NpvyHcn7Ethjz3'
var fromAddress = 'mj6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
var settings = {
network: 'testnet',
privateSeed: privateSeed
}
var colu = new Colu(settings)
colu.on('connect', function () {
var args = {
from: [fromAddress],
burn: [{
assetId: assetId,
amount: 1
}]
}
colu.burnAsset(args, function (err, body) {
if (err) return console.error(err)
console.log("Body: ", body)
})
})
colu.init()
アドレスとassetIdがわかっていれば、burnAssetを実行することでそのアドレスの持つAssetが指定したamount数分無効になる。
Assetを保有していない状態で、そのアドレスに対してgetAssetDataを実行すると、assetAmountが0、assetDataが空要素の結果が返却される。
assetData: {"assetId":"La1oyjuvEnNE3jQf4qzjzmY9NpvyHcn7Ethjz3","assetAmount":0,"assetTotalAmount":9,"assetData":[]}
assetを保有しているアドレスが減ってからassetのデータをexplorerでみると(getAssetDataを実行しても可)、Holdersの数が減る。そのassetを持っている人数が減ったということ。
Total Supplyの数は変わらないので、これが最初にassetを発行した数となる。
##JSON-RPCによるアクセス
別ウィンドウからcurlで実行してみる。
###getPrivateSeed
$ curl -X POST -i http://localhost/ -H "Content-Type:application/json" --data '{ "jsonrpc": "2.0", "method": "hdwallet.getPrivateSeed", "id":1 }'
結果
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Content-Type: application/json
Content-Length: 100
Date: Fri, 25 Nov 2016 08:21:35 GMT
Connection: keep-alive
{"jsonrpc":"2.0","id":1,"result":"7737900196e3fa34baf8f58e151f8368379f21cb4e9e5910f80b2f876e1ac4cf"}
###getAddress
$ curl -X POST -i http://localhost/ -H "Content-Type:application/json" --data '{ "jsonrpc": "2.0", "method": "hdwallet.getAddress", "id":1 }'
結果
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Content-Type: application/json
Content-Length: 70
Date: Fri, 25 Nov 2016 09:41:50 GMT
Connection: keep-alive
{"jsonrpc":"2.0","id":1,"result":"142xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
80番ポートで起動しているので、80番ポートが空いていれば外部からもJSON-RPCでのAPI実行は可能。
###key
blockchain,bitcoin,colu,coloredcoin