前回の記事
openassets-rubyをrailsに組み込んでみる - アルゴリズムとかオーダーとかの続きです。
今回はbitcoin-rubyで定義されているBitcoin::Protocol::BlockとBitcoin::Protocol::Txクラスを生成してみます。
まずはBlockから。説明は後回しでまずはソースをぺたり。
# blockのcountを指定してblockを取得する def getblockbycount(blockcount) blockhash = provider.getblockhash(blockcount) blockdata = provider.getblock(blockhash, false) Bitcoin::Protocol::Block.new(blockdata.htb) end
上記のメソッドを前回作ったBitcoinUtilに追加して、rails consoleで実行してみます。
実行結果は以下のようになるはず。
irb(main):003:0* BitcoinUtil.getblockbycount(101) => #<Bitcoin::Protocol::Block:0x007fb01f21dac8 @tx=[#<Bitcoin::Protocol::Tx:0x007fb01eba9368 @scripts=[], @out=[#<Bitcoin::Protocol::TxOut:0x007fb01f2f1788 @value=5000000000, @pk_script_length=35, @pk_script="!\x03\xF5\xB8\xC4\xE4\x19\x95\r\x10\xB1\x11;\xC7k\xE0vD\x18K/\x8BC7\xC6\x96\x01\xE9Oq\x99\x9F\xB0\x12\xAC">], @in=[#<Bitcoin::Protocol::TxIn:0x007fb01f2e2b20 @prev_out_hash="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", @prev_out_index=4294967295, @script_sig_length=4, @script_sig="\x01e\x01\x01", @sequence="\xFF\xFF\xFF\xFF", @script_witness=#<Bitcoin::Protocol::ScriptWitness:0x007fb01f2e0578 @stack=[]>>], @lock_time=0, @ver=1, @enable_bitcoinconsensus=false, @hash="7e05fcff4af0a77ff0b8f265b2b9ca82def9c69a6801bc52b71178415c7736af", @payload="\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x04\x01e\x01\x01\xFF\xFF\xFF\xFF\x01\x00\xF2\x05*\x01\x00\x00\x00#!\x03\xF5\xB8\xC4\xE4\x19\x95\r\x10\xB1\x11;\xC7k\xE0vD\x18K/\x8BC7\xC6\x96\x01\xE9Oq\x99\x9F\xB0\x12\xAC\x00\x00\x00\x00">], @ver=536870912, @prev_block_hash="|\xE8\xF8\xC7c|c\x96\f{\xF8\xC0\xEB\"\x1C\xE1\x81\xBD\xCA\xD1\"\xBB\xC7\xCA\x9A\xAE\x10\a\r\ri\x04", @mrkl_root="\xAF6w\\Ax\x11\xB7R\xBC\x01h\x9A\xC6\xF9\xDE\x82\xCA\xB9\xB2e\xF2\xB8\xF0\x7F\xA7\xF0J\xFF\xFC\x05~", @time=1509588862, @bits=545259519, @nonce=1, @hash="27d6943a0532cf70654090a71ebbc0ed8d04ae738581182bc1bb57c3e1eeb59e", @tx_count=1, @payload="\x00\x00\x00 |\xE8\xF8\xC7c|c\x96\f{\xF8\xC0\xEB\"\x1C\xE1\x81\xBD\xCA\xD1\"\xBB\xC7\xCA\x9A\xAE\x10\a\r\ri\x04\xAF6w\\Ax\x11\xB7R\xBC\x01h\x9A\xC6\xF9\xDE\x82\xCA\xB9\xB2e\xF2\xB8\xF0\x7F\xA7\xF0J\xFF\xFC\x05~~\x7F\xFAY\xFF\xFF\x7F \x01\x00\x00\x00\x01\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x04\x01e\x01\x01\xFF\xFF\xFF\xFF\x01\x00\xF2\x05*\x01\x00\x00\x00#!\x03\xF5\xB8\xC4\xE4\x19\x95\r\x10\xB1\x11;\xC7k\xE0vD\x18K/\x8BC7\xC6\x96\x01\xE9Oq\x99\x9F\xB0\x12\xAC\x00\x00\x00\x00">
コードの説明をします。
blockhash = provider.getblockhash(blockcount)
blockdata = provider.getblock(blockhash, false)
の2行でbitcoindから指定されたblock countのblockデータを取得しています。注意点は2行目の第2引数でfalseを指定してるところです。
rpcコマンドのgetblock "hash" で第2引数を指定せずにblockデータを取得するとjson形式で取得できます。
Bitcoint::Protocol::Block#binary_from_hashメソッドにこのjsonを渡してクラスを生成しようとすると、jsonパラメータの名前が違っていてうまく生成できません。(※exampleみるとbitcoinexplorerから取得して生成してるっぽいのでbitcoinexplorerの形式に合わせてるのかな?)
なので、第2引数にfalseを指定してhex stringのままblockデータを取得しています。
最後の3行目でBitcoin::Protocol::Blockクラスを生成しています。
Bitcoin::Protocol::Block.new(blockdata.htb)
ここで説明するものとしてはhtbメソッドぐらいかな?
bitcoin-rubyを入れるとStringクラスが拡張されて、hex stringをbinary stringに変換するhtbとその逆のbthメソッドなどの便利メソッドが追加されます。
Bitcoin::Protocol::Block#newではバイナリーstringを要求されるのでここではrpcコマンドで受け取ったhex stringを上記の便利メソッドを使ったバイナリーStringに変換して渡してます。
続いてBitcoin::Protocol::Txの生成方法。内容がほぼBlockと同じなので説明を省いてソースと実行結果だけ載せておきます。
# txidからtransactionを取得 def gettransaction(txid) txdata = provider.getrawtransaction(txid) Bitcoin::Protocol::Tx.new(txdata.htb) end
上記のメソッドをBlockの時とおなじく、BitcoinUtilに追加してrails consoleで実行してみた結果が以下の通り
irb(main):003:0* block = BitcoinUtil.getblockbycount(101) => #<Bitcoin::Protocol::Block:0x007fb01f369170 @tx=[#<Bitcoin::Protocol::Tx:0x007fb01eb48630 @scripts=[], @out=[#<Bitcoin::Protocol::TxOut:0x007fb01eb7d178 @value=5000000000, @pk_script_length=35, @pk_script="!\x03\xF5\xB8\xC4\xE4\x19\x95\r\x10\xB1\x11;\xC7k\xE0vD\x18K/\x8BC7\xC6\x96\x01\xE9Oq\x99\x9F\xB0\x12\xAC">], @in=[#<Bitcoin::Protocol::TxIn:0x007fb01eb6e2b8 @prev_out_hash="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", @prev_out_index=4294967295, @script_sig_length=4, @script_sig="\x01e\x01\x01", @sequence="\xFF\xFF\xFF\xFF", @script_witness=#<Bitcoin::Protocol::ScriptWitness:0x007fb01bc42fc0 @stack=[]>>], @lock_time=0, @ver=1, @enable_bitcoinconsensus=false, @hash="7e05fcff4af0a77ff0b8f265b2b9ca82def9c69a6801bc52b71178415c7736af", @payload="\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x04\x01e\x01\x01\xFF\xFF\xFF\xFF\x01\x00\xF2\x05*\x01\x00\x00\x00#!\x03\xF5\xB8\xC4\xE4\x19\x95\r\x10\xB1\x11;\xC7k\xE0vD\x18K/\x8BC7\xC6\x96\x01\xE9Oq\x99\x9F\xB0\x12\xAC\x00\x00\x00\x00">], @ver=536870912, @prev_block_hash="|\xE8\xF8\xC7c|c\x96\f{\xF8\xC0\xEB\"\x1C\xE1\x81\xBD\xCA\xD1\"\xBB\xC7\xCA\x9A\xAE\x10\a\r\ri\x04", @mrkl_root="\xAF6w\\Ax\x11\xB7R\xBC\x01h\x9A\xC6\xF9\xDE\x82\xCA\xB9\xB2e\xF2\xB8\xF0\x7F\xA7\xF0J\xFF\xFC\x05~", @time=1509588862, @bits=545259519, @nonce=1, @hash="27d6943a0532cf70654090a71ebbc0ed8d04ae738581182bc1bb57c3e1eeb59e", @tx_count=1, @payload="\x00\x00\x00 |\xE8\xF8\xC7c|c\x96\f{\xF8\xC0\xEB\"\x1C\xE1\x81\xBD\xCA\xD1\"\xBB\xC7\xCA\x9A\xAE\x10\a\r\ri\x04\xAF6w\\Ax\x11\xB7R\xBC\x01h\x9A\xC6\xF9\xDE\x82\xCA\xB9\xB2e\xF2\xB8\xF0\x7F\xA7\xF0J\xFF\xFC\x05~~\x7F\xFAY\xFF\xFF\x7F \x01\x00\x00\x00\x01\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x04\x01e\x01\x01\xFF\xFF\xFF\xFF\x01\x00\xF2\x05*\x01\x00\x00\x00#!\x03\xF5\xB8\xC4\xE4\x19\x95\r\x10\xB1\x11;\xC7k\xE0vD\x18K/\x8BC7\xC6\x96\x01\xE9Oq\x99\x9F\xB0\x12\xAC\x00\x00\x00\x00"> irb(main):004:0> txid = block.tx.first.hash => "7e05fcff4af0a77ff0b8f265b2b9ca82def9c69a6801bc52b71178415c7736af" irb(main):005:0> BitcoinUtil.gettransaction(txid) => #<Bitcoin::Protocol::Tx:0x007fb01eb565c8 @scripts=[], @out=[#<Bitcoin::Protocol::TxOut:0x007fb01eb560c8 @value=5000000000, @pk_script_length=35, @pk_script="!\x03\xF5\xB8\xC4\xE4\x19\x95\r\x10\xB1\x11;\xC7k\xE0vD\x18K/\x8BC7\xC6\x96\x01\xE9Oq\x99\x9F\xB0\x12\xAC">], @in=[#<Bitcoin::Protocol::TxIn:0x007fb01eb563c0 @prev_out_hash="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", @prev_out_index=4294967295, @script_sig_length=4, @script_sig="\x01e\x01\x01", @sequence="\xFF\xFF\xFF\xFF", @script_witness=#<Bitcoin::Protocol::ScriptWitness:0x007fb01eb56320 @stack=[]>>], @lock_time=0, @ver=1, @enable_bitcoinconsensus=false, @hash="7e05fcff4af0a77ff0b8f265b2b9ca82def9c69a6801bc52b71178415c7736af", @payload="\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x04\x01e\x01\x01\xFF\xFF\xFF\xFF\x01\x00\xF2\x05*\x01\x00\x00\x00#!\x03\xF5\xB8\xC4\xE4\x19\x95\r\x10\xB1\x11;\xC7k\xE0vD\x18K/\x8BC7\xC6\x96\x01\xE9Oq\x99\x9F\xB0\x12\xAC\x00\x00\x00\x00"> irb(main):007:0> BitcoinUtil.gettransaction(txid).out.first.value => 5000000000
Blockを取得してBlockからtxidを取得して、txを取得してます。
最後にこのtxが送信したBTCが50BTC(表示はsatoshi単位になってるけど)かどうか確認してます。