spec/bitcoin/protocol/tx_spec.rb in bitcoin-ruby-0.0.5 vs spec/bitcoin/protocol/tx_spec.rb in bitcoin-ruby-0.0.6
- old
+ new
@@ -47,10 +47,27 @@
tx.hash.size.should == 64
tx.hash.should == "6e9dd16625b62cfcd4bf02edb89ca1f5a8c30c4b1601507090fb28e59f2d02b4"
tx.binary_hash.should == "\xB4\x02-\x9F\xE5(\xFB\x90pP\x01\x16K\f\xC3\xA8\xF5\xA1\x9C\xB8\xED\x02\xBF\xD4\xFC,\xB6%f\xD1\x9Dn"
end
+ it '#normalized_hash' do
+ tx = Tx.new( @payload[0] )
+ tx.normalized_hash.size.should == 64
+ tx.normalized_hash.should == "402e30100b6937cc13828ca096377c93afc0ff227ad2f249245e5b1db9123a39"
+
+ new_tx = JSON.parse(tx.to_json)
+ script = Bitcoin::Script.from_string(new_tx['in'][0]['scriptSig'])
+ script.chunks[0].bitcoin_pushdata = Bitcoin::Script::OP_PUSHDATA2
+ script.chunks[0].bitcoin_pushdata_length = script.chunks[0].bytesize
+ new_tx['in'][0]['scriptSig'] = script.to_string
+ new_tx = Bitcoin::P::Tx.from_hash(new_tx)
+
+ new_tx.hash.should != tx.hash
+ new_tx.normalized_hash.size.should == 64
+ new_tx.normalized_hash.should == "402e30100b6937cc13828ca096377c93afc0ff227ad2f249245e5b1db9123a39"
+ end
+
it '#to_payload' do
tx = Tx.new( @payload[0] )
tx.to_payload.size.should == @payload[0].size
tx.to_payload.should == @payload[0]
end
@@ -181,10 +198,57 @@
tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28.json'))
tx.hash.should == "9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28"
outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954.json'))
outpoint_tx.hash.should == "a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954"
tx.verify_input_signature(0, outpoint_tx).should == true
+
+ # drop OP_CODESEPARATOR in subscript for signature_hash_for_input
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json'))
+ tx.hash.should == "46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa"
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json'))
+ outpoint_tx.hash.should == "bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224"
+ tx.verify_input_signature(0, outpoint_tx).should == true
+
+ # drop OP_CODESEPARATOR in subscript for signature_hash_for_input
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json'))
+ tx.hash.should == "aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8"
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json'))
+ outpoint_tx.hash.should == "326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e"
+ tx.verify_input_signature(0, outpoint_tx).should == true
+
+ # drop multisig OP_CODESEPARATOR in subscript for signature_hash_for_input
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json'))
+ tx.hash.should == "6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190"
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json'))
+ outpoint_tx.hash.should == "a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944"
+ tx.verify_input_signature(0, outpoint_tx).should == true
+
+ # drop multisig OP_CODESEPARATOR in subscript for signature_hash_for_input when used in ScriptSig
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json'))
+ tx.hash.should == "eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb"
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json'))
+ outpoint_tx.hash.should == "b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d"
+ tx.verify_input_signature(1, outpoint_tx).should == true
+
+ # OP_DUP OP_HASH160
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json'))
+ tx.hash.should == "5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f"
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json'))
+ outpoint_tx.hash.should == "b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9"
+ tx.verify_input_signature(0, outpoint_tx).should == true
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json'))
+ outpoint_tx.hash.should == "ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742"
+ tx.verify_input_signature(1, outpoint_tx).should == true
+
+ # testnet3 e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json'))
+ tx.hash.should == "e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009"
+ prev_txs = {}
+ tx.in.map{|i| i.previous_output }.uniq.each{|i| prev_txs[i] = Bitcoin::P::Tx.from_json(fixtures_file("tx-#{i}.json")) }
+ tx.in.each.with_index{|i,idx|
+ tx.verify_input_signature(idx, prev_txs[i.previous_output]).should == true
+ }
end
it '#sign_input_signature' do
prev_tx = Tx.new( fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin') )
prev_tx.hash.should == "2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a"
@@ -242,20 +306,126 @@
#File.open("rawtx-#{new_tx.hash}.bin",'wb'){|f| f.print new_tx.to_payload }
prev_tx = Tx.new( fixtures_file('rawtx-52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2.bin') )
prev_tx.hash.should == "52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2"
#File.open("rawtx-#{prev_tx.hash}.json",'wb'){|f| f.print prev_tx.to_json }
end
+
+ it "#legacy_sigops_count" do
+ Tx.new(@payload[0]).legacy_sigops_count.should == 2
+ Tx.new(@payload[1]).legacy_sigops_count.should == 2
+ Tx.new(@payload[2]).legacy_sigops_count.should == 2
+
+ # Test sig ops count in inputs too.
+ tx = Tx.new
+ txin = TxIn.new
+ txin.script_sig = Bitcoin::Script.from_string("10 OP_CHECKMULTISIGVERIFY OP_CHECKSIGVERIFY").to_binary
+ tx.add_in(txin)
+ txout = TxOut.new
+ txout.pk_script = Bitcoin::Script.from_string("5 OP_CHECKMULTISIG OP_CHECKSIG").to_binary
+ tx.add_out(txout)
+ tx.legacy_sigops_count.should == (20 + 1 + 20 + 1)
+
+ end
+
+ describe "Tx - is_final?" do
+ it "should be final if lock_time == 0" do
+ tx = Tx.new
+ tx.lock_time = 0
+ tx.is_final?(0,0).should == true
+
+ # even if has non-final input:
+ txin = TxIn.new
+ txin.sequence = "\x01\x00\x00\x00"
+ tx.add_in(txin)
+ tx.is_final?(0,0).should == true
+ end
+
+ it "should be final if lock_time is below block_height" do
+ tx = Tx.new
+ txin = TxIn.new
+ txin.sequence = "\x01\x00\x00\x00"
+ tx.add_in(txin)
+ tx.lock_time = 6543
+ tx.is_final?(6000,0).should == false
+ tx.is_final?(6543,0).should == false # when equal to block height, still not final
+ tx.is_final?(6544,0).should == true
+ tx.is_final?(9999,0).should == true
+ end
+
+ it "should be final if lock_time is below timestamp" do
+ tx = Tx.new
+ txin = TxIn.new
+ txin.sequence = "\xff\xff\xff\xff"
+ tx.add_in(txin)
+ txin = TxIn.new
+ txin.sequence = "\x01\x00\x00\x00"
+ tx.add_in(txin)
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD # when equal, interpreted as threshold
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD - 1).should == false
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD).should == false # when equal to timestamp, still not final
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == true
+
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD + 666
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == false
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 666).should == false # when equal to timestamp, still not final
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 667).should == true
+ end
+
+ it "should be final if all inputs are finalized regardless of lock_time" do
+ tx = Tx.new
+ txin = TxIn.new
+ txin.sequence = "\xff\xff\xff\xff"
+ tx.add_in(txin)
+ txin = TxIn.new
+ txin.sequence = "\xff\xff\xff\xff"
+ tx.add_in(txin)
+
+ tx.lock_time = 6543
+ tx.is_final?(6000,0).should == true
+ tx.is_final?(6543,0).should == true
+ tx.is_final?(6544,0).should == true
+ tx.is_final?(9999,0).should == true
+
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD - 1).should == true
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD).should == true
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == true
+
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD + 666
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == true
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 666).should == true
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 667).should == true
+ end
+
+ end
it '#calculate_minimum_fee' do
tx = Tx.new( fixtures_file('rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin') )
tx.minimum_relay_fee.should == 0
tx.minimum_block_fee.should == 0
tx = Tx.from_json(fixtures_file('bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json'))
tx.minimum_relay_fee.should == 0
tx.minimum_block_fee.should == 10_000
end
+ it '#calculate_minimum_fee for litecoin' do
+ tx = Tx.from_json(fixtures_file('litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json'))
+ tx.minimum_relay_fee.should == 0
+ tx.minimum_block_fee.should == 30_000
+ Bitcoin.network = :litecoin # change to litecoin
+ tx.minimum_relay_fee.should == 0
+ tx.minimum_block_fee.should == 5_900_000
+ end
+
+ it "should compare transactions" do
+ tx1 = Tx.new( @payload[0] )
+ tx2 = Tx.new( @payload[1] )
+ (tx1 == Bitcoin::P::Tx.from_json(tx1.to_json)).should == true
+ (tx1 == tx2).should == false
+ (tx1 == nil).should == false
+ end
+
describe "Tx - BIP Scripts" do
it "should do OP_CHECKMULTISIG" do
# checkmultisig without checkhashverify
tx = Tx.from_json(fixtures_file('23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json'))
@@ -264,10 +434,15 @@
# p2sh + multisig transaction from mainnet
tx = Tx.from_json( fixtures_file('rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json') )
prev_tx = Tx.from_json( fixtures_file("rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json") )
tx.verify_input_signature(0, prev_tx).should == true
+
+ # checkmultisig for testnet3 tx: 2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1 input index 1
+ tx = Tx.from_json( fixtures_file('tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json') )
+ prev_tx = Tx.from_json( fixtures_file("tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json") )
+ tx.verify_input_signature(1, prev_tx).should == true
end
it "should do P2SH with inner OP_CHECKMULTISIG (BIP 0016)" do
tx = Tx.from_json(fixtures_file('3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json'))
prev_tx = Tx.from_json(fixtures_file('35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json'))
@@ -292,8 +467,16 @@
prev_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json'))
prev_tx.hash.should == "44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a"
tx.verify_input_signature(0, prev_tx).should == true
end
- end
+ it "should do OP_CHECKMULTISIG with OP_0 used as a pubkey" do
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json'))
+ tx.hash.should == "6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba"
+ prev_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json'))
+ prev_tx.hash.should == "4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9"
+ tx.verify_input_signature(0, prev_tx).should == true
+ end
+ end
+
end