#Transaction malleabilityとは
日本語ではトランザクション展性と呼ばれています。
ビットコインではトランザクションに署名を行うのですが、トランザクションの構成要素である、scriptSigという署名を格納するスクリプトには署名を行いません。
scriptSigに署名は行いませんが、トランザクションのID(txid)の計算にscriptSigは絡んできます。
従って、このscriptSigを変更することで、トランザクションの意味を失わずにtxidを変更することが可能になります。これがtransaction malleabilityです。
#準備
regtest環境 (v0.16.3) で実験を行う。
まずはブロックの生成。
$ bitcoin-cli -regtest generate 101
[
"481154f46e3a0823adadeb08b688095f9dd3a2ad0a0a7a14fcba83734da7a7cb",
"475cb6e1f629cd78d4b9b59c588ed25b282919d2beabf6582b42a6b67892f602",
...
"3f317090c7eb981b24cfc5318e0c112dd6f57231a0ab389b7826e24002662dab"
]
未使用アウトプットを確認し、50BTC保持していることが分かる。
$ bitcoin-cli -regtest listunspent
[
{
"txid": "a5449d3d6826c854bcc64bae4efdb5cf6a7578775c819ae5b6e5add178923538",
"vout": 0,
"address": "ms1CW9fcUxTDzs1FquA1p7ck5XVLgY29hk",
"scriptPubKey": "21037973215150cd5ae90799905a702db97e98aeaa928e98118adf88baf3f1d56658ac",
"amount": 50.00000000,
"confirmations": 101,
"spendable": true,
"solvable": true,
"safe": true
}
]
中身を確認する。
$ bitcoin-cli -regtest gettxout a5449d3d6826c854bcc64bae4efdb5cf6a7578775c819ae5b6e5add178923538 0
{
"bestblock": "3f317090c7eb981b24cfc5318e0c112dd6f57231a0ab389b7826e24002662dab",
"confirmations": 101,
"value": 50.00000000,
"scriptPubKey": {
"asm": "037973215150cd5ae90799905a702db97e98aeaa928e98118adf88baf3f1d56658 OP_CHECKSIG",
"hex": "21037973215150cd5ae90799905a702db97e98aeaa928e98118adf88baf3f1d56658ac",
"reqSigs": 1,
"type": "pubkey",
"addresses": [
"ms1CW9fcUxTDzs1FquA1p7ck5XVLgY29hk"
]
},
"coinbase": true
}
新しいアドレスを生成。
$ bitcoin-cli -regtest getnewaddress
2N1bv8S529pHgyjZqocuwnsvMppcymnkS5v
"ms1CW9fcUxTDzs1FquA1p7ck5XVLgY29hk"から"2N1bv8S529pHgyjZqocuwnsvMppcymnkS5v"へ 30BTC 送信してみる。
手数料は0.001BTCとした。
$ bitcoin-cli -regtest createrawtransaction '[{"txid":"a5449d3d6826c854bcc64bae4efdb5cf6a7578775c819ae5b6e5add178923538", "vout":0}]' '{"ms1CW9fcUxTDzs1FquA1p7ck5XVLgY29hk":19.999, "2N1bv8S529pHgyjZqocuwnsvMppcymnkS5v":30}'
020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a50000000000ffffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000
署名する。signrawtransactionコマンドの前にwallepassphraseコマンドで秘密鍵のロックを行うのを忘れずに。
$ bitcoin-cli -regtest signrawtransaction 020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a50000000000ffffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000
{
"hex": "020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a500000000484730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01ffffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000",
"complete": true
}
#トランザクションの中身を見てみる
signrawtransactionコマンドで返ってきた16進数テキストをデコードする。
$ bitcoin-cli -regtest decoderawtransaction 020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a500000000484730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01ffffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000
{
"txid": "aa31a089161541e0993f213d5266142878b556088ea9a8f052f430a112e6f453",
"hash": "aa31a089161541e0993f213d5266142878b556088ea9a8f052f430a112e6f453",
"version": 2,
"size": 189,
"vsize": 189,
"locktime": 0,
"vin": [
{
"txid": "a5449d3d6826c854bcc64bae4efdb5cf6a7578775c819ae5b6e5add178923538",
"vout": 0,
"scriptSig": {
"asm": "30440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e[ALL]",
"hex": "4730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01"
},
"sequence": 4294967295
}
],
"vout": [
{
"value": 19.99900000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 7e00e4295f101b0e67b93c98700b2f406bee501f OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"ms1CW9fcUxTDzs1FquA1p7ck5XVLgY29hk"
]
}
},
{
"value": 30.00000000,
"n": 1,
"scriptPubKey": {
"asm": "OP_HASH160 5baad546a71ab49cb984c6f3eb43aa423edce3c0 OP_EQUAL",
"hex": "a9145baad546a71ab49cb984c6f3eb43aa423edce3c087",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"2N1bv8S529pHgyjZqocuwnsvMppcymnkS5v"
]
}
}
]
}
何が起こったかよく分からないので、元の16進を整形してみる。
"020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a500000000484730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01ffffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000"
トランザクションの構成は 参考サイト を参照してください。リトルエンディアンである点に注意!!
02000000 // バージョン
01 // インプットの数
38359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a5 // txid
00000000 // インデックス
48 // scriptSigのバイト長
47 // 署名のバイト長
30440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01
ffffffff // シーケンスナンバー
02 // アウトプットの数
600d347700000000 // 19.999 BTC = 1999900000 satoshi = 0x77340D60 satoshi
19 // scriptPubKey のバイト長
76a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac // scriptPubKey
005ed0b200000000 // 30 BTC
17 // scriptPubKey のバイト長
a9145baad546a71ab49cb984c6f3eb43aa423edce3c087 // scriptPubKey
00000000 // ロックタイム
#Transaction malleabilityをやってみる
sendrawtransactionコマンドで、ビットコインネットワーク(この環境でネットワークと呼ぶのは正しくないと思うが)にトランザクションを送信する。
$ bitcoin-cli -regtest sendrawtransaction 020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a500000000484730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01ffffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000
aa31a089161541e0993f213d5266142878b556088ea9a8f052f430a112e6f453
txid "aa31a089161541e0993f213d5266142878b556088ea9a8f052f430a112e6f453"が返ってきたので、上手くいってる。
このトランザクションの妥当性を失わずにtxidを変えたい。
scriptSigは署名対象ではないが、txidの算出には関わるので、scriptSigをいじればtransaction malleabilityを行うことができる。
scriptSigにOP_NOP(0x61)を加えてみる。
02000000 // バージョン
01 // インプットの数
38359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a5 // txid
00000000 // インデックス
49 // scriptSigのバイト長
OP_NOP(0x61) 47 // 署名のバイト長
30440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01
ffffffff // シーケンスナンバー
02 // アウトプットの数
600d347700000000 // 19.999 BTC = 1999900000 satoshi = 0x77340D60 satoshi
19 // scriptPubKey のバイト長
76a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac // scriptPubKey
005ed0b200000000 // 30 BTC
17 // scriptPubKey のバイト長
a9145baad546a71ab49cb984c6f3eb43aa423edce3c087 // scriptPubKey
00000000 // ロックタイム
赤字部分が変更されたところ
"020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a50000000049614730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01ffffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000"
デコードも問題ない。
$ bitcoin-cli -regtest decoderawtransaction 020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a50
000000049614730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01ff
ffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000
{
"txid": "055320a1ab4e48e6858d8795b6ff32873447646f833048b1f1806878e32039fa",
"hash": "055320a1ab4e48e6858d8795b6ff32873447646f833048b1f1806878e32039fa",
"version": 2,
"size": 190,
"vsize": 190,
"locktime": 0,
"vin": [
{
"txid": "a5449d3d6826c854bcc64bae4efdb5cf6a7578775c819ae5b6e5add178923538",
"vout": 0,
"scriptSig": {
"asm": "OP_NOP 30440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e[ALL]",
"hex": "614730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01"
},
"sequence": 4294967295
}
],
"vout": [
{
"value": 19.99900000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 7e00e4295f101b0e67b93c98700b2f406bee501f OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"ms1CW9fcUxTDzs1FquA1p7ck5XVLgY29hk"
]
}
},
{
"value": 30.00000000,
"n": 1,
"scriptPubKey": {
"asm": "OP_HASH160 5baad546a71ab49cb984c6f3eb43aa423edce3c0 OP_EQUAL",
"hex": "a9145baad546a71ab49cb984c6f3eb43aa423edce3c087",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"2N1bv8S529pHgyjZqocuwnsvMppcymnkS5v"
]
}
}
]
}
再び、sendrawtransactionコマンド。
$ bitcoin-cli -regtest sendrawtransaction 020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a50000000049614730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01ffffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000
error code: -26
error message:
18: txn-mempool-conflict
同一UTXOを参照しているからコンフリクトが起こっているみたい。
この辺りを参照し、mempoolをクリーンアップ。
$ rm ~/.bitcoin/regtest/mempool.dat
$ bitcoin-cli -regtest stop
$ bitcoind -regtest -zapwallettxes -daemon
もう一度、sendrawtransactionコマンド。
$ bitcoin-cli -regtest sendrawtransaction 020000000138359278d1ade5b6e59a815c7778756acfb5fd4eae4bc6bc54c826683d9d44a50000000049614730440220400f1e3d0ce28bf9fb2ac6749554177b13ec018f6a9171df4ce81883818f70b4022062c77d8271812f68e86b8e8531470d94810e9be304855a086e4d9431c9d68d8e01ffffffff02600d3477000000001976a9147e00e4295f101b0e67b93c98700b2f406bee501f88ac005ed0b20000000017a9145baad546a71ab49cb984c6f3eb43aa423edce3c08700000000
055320a1ab4e48e6858d8795b6ff32873447646f833048b1f1806878e32039fa
txid "055320a1ab4e48e6858d8795b6ff32873447646f833048b1f1806878e32039fa"が返ってきた。
先程のtxid "aa31a089161541e0993f213d5266142878b556088ea9a8f052f430a112e6f453"と異なっていることが分かる。