CounterpartyのNumeric Assetを作成する

f:id:yzono:20150102184757j:plain

はじめに

Counterpartyd v9.47.0からAssetを無料でも作れるようになりました。無料の場合、Asset名は'A'を頭文字にして、その後ろに数字が並ぶ形式で"Numeric Asset"と呼ばれています。今回はNumeric Assetの作り方について書きます。

目次

  • CounterwalletからAsset作成
  • Counterpartyd APIを使用してAsset作成
  • 同一の名前を設定した場合

CounterwalletからAsset作成

Counterwalletからの作成は簡単です。

Address > Create a Token (Asset) > Name typeをFree numeric nameに設定。

0.5XCP持っていないアドレスでやろうとすると以下エラーがでます。バグだと思います。(報告しました)

You need at least 0.5 XCP to create a token, however, your current balance is only 0 XCP.

Please deposit more XCP into this address and try again.

Counterpartyd APIを使用してAsset作成

現時点ではAPIリファレンスにはNumeric Assetの作り方は書いていないのでCounterwalletのソースを読みました。

Numeric Asset名の設定(クライアント側の処理)

Asset名は、balances_asset.jsのgenerateRandomIdで作られています。

self.generateRandomId = function() {
    var r = bigInt.randBetween(NUMERIC_ASSET_ID_MIN, NUMERIC_ASSET_ID_MAX);
    self.name('A' + r);
}

最小値、最大値はconsts.jsで設定されています。

var NUMERIC_ASSET_ID_MIN = bigInt(26).pow(12).add(1);
var NUMERIC_ASSET_ID_MAX = bigInt(256).pow(8);

bigIntは、big-integer/BigInteger.min.jsを使用しており。最小値と最大値は以下の通りです。

var bigInt = require('big-integer')

var NUMERIC_ASSET_ID_MIN = bigInt(26).pow(12).add(1);
var NUMERIC_ASSET_ID_MAX = bigInt(256).pow(8);

console.log('NUMERIC_ASSET_ID_MIN: %d', NUMERIC_ASSET_ID_MIN); // 95428956661682180
console.log('NUMERIC_ASSET_ID_MAX: %d', NUMERIC_ASSET_ID_MAX); // 18446744073709552000

AssetのバリデーションとAsset作成手数料(XCP)の決定

AssetのバリデーションとAsset作成手数料(XCP)の決定は、issuance.pyのvalidateメソッド内で行われています。

if util.enabled('numeric_asset_names', block_index):  # Protocol change.
    if len(asset) >= 13: # 通常のAssetは12文字まで
        fee = 0
    else:
        fee = int(0.5 * config.UNIT)

Counterpartyd API create_issuanceを実行

上記のとおり名前を適当に決めてしまえばヨロシクやってくれそうです。実際に実行してみます。

実行前の残高確認(BTC)

bitcoind --datadir=/home/xcp/.bitcoin-test listaddressgroupings
[
    [
        [
            "mo1kgfktQfRaLMR5SvehDMHLa9Cu7xJp4m",
            0.11000000,
            ""
        ]
]

実行前の残高確認(XPC)

curl http://127.0.0.1:14000/api/ --user rpc:xcppw1234 -H 'Content-Type: application/json; charset=UTF-8' -H 'Accept: application/json, text/javascript' --data-binary '{"jsonrpc":"2.0", "id":0, "method":"get_balances", "params":{"filters": {"field": "address", "op": "==", "value": "mo1kgfktQfRaLMR5SvehDMHLa9Cu7xJp4m"}}}'

{"id": 0, "result": [{"asset": "XCP", "quantity": 9991974826, "address": "mo1kgfktQfRaLMR5SvehDMHLa9Cu7xJp4m"}], "jsonrpc": "2.0"}

create_issuance実行

curl http://127.0.0.1:14000/api/ --user rpc:xcppw1234 -H 'Content-Type: application/json; charset=UTF-8' -H 'Accept: application/json, text/javascript' --data-binary '{"jsonrpc":"2.0", "id":0, "method":"create_issuance", "params":{"source":"mo1kgfktQfRaLMR5SvehDMHLa9Cu7xJp4m", "quantity":10, "asset":"A15128863744940229000"}}'

{"id": 0, "result": "2fe5b344e7254692dac52abe5599501db873598b4bb847fc9f6faa9e673e6e51", "jsonrpc": "2.0"}

blockrでトランザクションを見る

実行後の残高確認(BTC)

bitcoind --datadir=/home/xcp/.bitcoin-test listaddressgroupings
[
    [
        [
            "mo1kgfktQfRaLMR5SvehDMHLa9Cu7xJp4m",
            0.10982200,
            ""
        ]
]

(BTC) 0.11000000 - 0.10982200 = 0.000178BTC(手数料)

実行後の残高確認(XPC)

curl http://127.0.0.1:14000/api/ --user rpc:xcppw1234 -H 'Content-Type: application/json; charset=UTF-8' -H 'Accept: application/json, text/javascript' --data-binary '{"jsonrpc":"2.0", "id":0, "method":"get_balances", "params":{"filters": {"field": "address", "op": "==", "value": "mo1kgfktQfRaLMR5SvehDMHLa9Cu7xJp4m"}}}'

{"result": [{"asset": "A15128863744940229000", "quantity": 10, "address": "mo1kgfktQfRaLMR5SvehDMHLa9Cu7xJp4m"}, {"asset": "XCP", "quantity": 9991974826, "address": "mo1kgfktQfRaLMR5SvehDMHLa9Cu7xJp4m"}], "id": 0, "jsonrpc": "2.0"}

(XCP) 9991974826 - 9991974826 = 0XCP(手数料は0XCP)

同一の名前を設定した場合

Numeric Asset名が仮に既に登録されていた場合にどうなるか試しました。

別アドレス"mfs4uCpPkWNTC5L3cWLRjFdgXJ9LP61Ztw"がcreate_issuanceを実行します。

curl http://127.0.0.1:14000/api/ --user rpc:xcppw1234 -H 'Content-Type: application/json; charset=UTF-8' -H 'Accept: application/json, text/javascript' --data-binary '{"jsonrpc":"2.0", "id":0, "method":"create_issuance", "params":{"source":"mfs4uCpPkWNTC5L3cWLRjFdgXJ9LP61Ztw", "quantity":10, "asset":"A15128863744940229000"}}'

{"error": {"data": {"args": [["issued by another address"]], "type": "ComposeError", "message": "['issued by another address']"}, "code": -32000, "message": "Server error"}, "id": 0, "jsonrpc": "2.0"}

エラー'issued by another address'が発生します。

issuance.pyのvalidateメソッド内でチェックされています。

# Valid re-issuance?
cursor = db.cursor()
cursor.execute('''SELECT * FROM issuances \
                  WHERE (status = ? AND asset = ?)
                  ORDER BY tx_index ASC''', ('valid', asset))
issuances = cursor.fetchall()
cursor.close()
if issuances:
    reissuance = True
    last_issuance = issuances[-1]

    if last_issuance['issuer'] != source:
        problems.append('issued by another address')

まとめ

API経由で無料のNumeric Assetを作成することができました。

ソースを眺めていると、私が不正にソースを改変して、例えばAsset名に"BTC"としてブロードキャストしたらどうなるか、XCPの手数料をタダにしてブロードキャストした場合にシステムとして不正を検知できるのか気になってきました。今度試してみます。

参考

big-integer