bitcoin-ruby 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -252,6 +252,13 @@ describe "Bitcoin::Key" do
252
252
  k.to_base58.should == "5JBAonQ4iGKFJxENExZghDtAS6YB8BsCw5mwpHSvZvP3Q2UxmT1"
253
253
  end
254
254
 
255
+ it "should raise error for private key out of range." do
256
+ proc{Bitcoin::Key.new('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141')}.should.raise(Exception)
257
+ proc{Bitcoin::Key.new('00')}.should.raise(Exception)
258
+ proc{Bitcoin::Key.new('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140')}.should.not.raise(Exception)
259
+ proc{Bitcoin::Key.new('01')}.should.not.raise(Exception)
260
+ end
261
+
255
262
  end
256
263
 
257
264
  begin
@@ -30,6 +30,9 @@ describe 'Tx' do
30
30
  proc{
31
31
  Tx.new( @payload[0][0..20] )
32
32
  }.should.raise Exception
33
+
34
+ # Deserializing a new, empty transaction works
35
+ Tx.new(Tx.new.to_payload)
33
36
  end
34
37
 
35
38
  it '#parse_data' do
@@ -38,18 +41,22 @@ describe 'Tx' do
38
41
  tx.hash.should == nil
39
42
  tx.parse_data( @payload[0] ).should == true
40
43
  tx.hash.size.should == 64
44
+ tx.payload.should == @payload[0]
41
45
 
42
46
  tx = Tx.new( nil )
43
47
  tx.parse_data( @payload[0] + "AAAA" ).should == "AAAA"
44
48
  tx.hash.size.should == 64
49
+ tx.payload.should == @payload[0]
45
50
  end
46
51
 
47
52
  it '#parse_witness_data' do
48
53
  tx = Tx.new( @payload[3] )
49
54
  tx.hash.size.should == 64
55
+ tx.payload.should == @payload[3]
50
56
 
51
57
  tx = Tx.new( @payload[3] + "AAAA" )
52
58
  tx.hash.size.should == 64
59
+ tx.payload.should == @payload[3]
53
60
  end
54
61
 
55
62
  it '#hash' do
@@ -110,6 +117,7 @@ describe 'Tx' do
110
117
  it 'Tx.from_hash' do
111
118
  orig_tx = Tx.new( @payload[0] )
112
119
  tx = Tx.from_hash( orig_tx.to_hash )
120
+ tx.payload.should == @payload[0]
113
121
  tx.to_payload.size.should == @payload[0].size
114
122
  tx.to_payload.should == @payload[0]
115
123
  tx.to_hash.should == orig_tx.to_hash
@@ -122,6 +130,7 @@ describe 'Tx' do
122
130
  # witness tx(P2WPKH)
123
131
  orig_tx = Tx.new( @payload[3] )
124
132
  tx = Tx.from_hash( orig_tx.to_hash )
133
+ tx.payload.should == @payload[3]
125
134
  tx.to_witness_payload.size.should == @payload[3].size
126
135
  tx.to_witness_payload.should == @payload[3]
127
136
  tx.to_hash == orig_tx.to_hash
@@ -463,64 +472,80 @@ describe 'Tx' do
463
472
  tx.verify_witness_input_signature(0, 'a9149993a429037b5d912407a71c252019287b8d27a587'.htb, 987654321).should == true
464
473
  end
465
474
 
466
- it '#sign_input_signature' do
467
- prev_tx = Tx.new( fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin') )
468
- prev_tx.hash.should == "2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a"
475
+ describe '#signature_hash_for_input' do
476
+ it 'sighash_all' do
477
+ prev_tx = Tx.new( fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin') )
478
+ prev_tx.hash.should == "2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a"
469
479
 
470
- key = Bitcoin.open_key("56e28a425a7b588973b5db962a09b1aca7bdc4a7268cdd671d03c52a997255dc",
471
- pubkey="04324c6ebdcf079db6c9209a6b715b955622561262cde13a8a1df8ae0ef030eaa1552e31f8be90c385e27883a9d82780283d19507d7fa2e1e71a1d11bc3a52caf3")
472
- new_tx = Tx.new(nil)
473
- new_tx.add_in( TxIn.new(prev_tx.binary_hash, 0, 0) )
474
- new_tx.add_out( TxOut.value_to_address(1000000, "1BVJWLTCtjA8wRivvrCiwjNdL6KjdMUCTZ") )
475
- signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
476
- sig = Bitcoin.sign_data(key, signature_hash)
477
- new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [pubkey].pack("H*"))
480
+ key = Bitcoin.open_key("56e28a425a7b588973b5db962a09b1aca7bdc4a7268cdd671d03c52a997255dc",
481
+ pubkey="04324c6ebdcf079db6c9209a6b715b955622561262cde13a8a1df8ae0ef030eaa1552e31f8be90c385e27883a9d82780283d19507d7fa2e1e71a1d11bc3a52caf3")
482
+ new_tx = Tx.new(nil)
483
+ new_tx.add_in( TxIn.new(prev_tx.binary_hash, 0, 0) )
484
+ new_tx.add_out( TxOut.value_to_address(1000000, "1BVJWLTCtjA8wRivvrCiwjNdL6KjdMUCTZ") )
485
+ signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
486
+ sig = Bitcoin.sign_data(key, signature_hash)
487
+ new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [pubkey].pack("H*"))
478
488
 
479
- new_tx = Tx.new( new_tx.to_payload )
480
- new_tx.hash.should != nil
481
- new_tx.verify_input_signature(0, prev_tx).should == true
489
+ new_tx = Tx.new( new_tx.to_payload )
490
+ new_tx.hash.should != nil
491
+ new_tx.verify_input_signature(0, prev_tx).should == true
482
492
 
483
493
 
484
494
 
485
- prev_tx = Tx.new( fixtures_file('rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin') )
486
- prev_tx.hash.should == "14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984"
495
+ prev_tx = Tx.new( fixtures_file('rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin') )
496
+ prev_tx.hash.should == "14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984"
487
497
 
488
- key = Bitcoin.open_key("115ceda6c1e02d41ce65c35a30e82fb325fe3f815898a09e1a5d28bb1cc92c6e",
489
- pubkey="0409d103127d26ce93ee41f1b9b1ed4c1c243acf48e31eb5c4d88ad0342ccc010a1a8d838846cf7337f2b44bc73986c0a3cb0568fa93d068b2c8296ce8d47b1545")
490
- new_tx = Tx.new(nil)
491
- new_tx.add_in( TxIn.new(prev_tx.binary_hash, 0, 0) )
492
- pk_script = Bitcoin::Script.to_address_script("1FEYAh1x5jeKQMPPuv3bKnKvbgVAqXvqjW")
493
- new_tx.add_out( TxOut.new(1000000, pk_script) )
494
- signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
495
- sig = Bitcoin.sign_data(key, signature_hash)
496
- new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [pubkey].pack("H*"))
498
+ key = Bitcoin.open_key("115ceda6c1e02d41ce65c35a30e82fb325fe3f815898a09e1a5d28bb1cc92c6e",
499
+ pubkey="0409d103127d26ce93ee41f1b9b1ed4c1c243acf48e31eb5c4d88ad0342ccc010a1a8d838846cf7337f2b44bc73986c0a3cb0568fa93d068b2c8296ce8d47b1545")
500
+ new_tx = Tx.new(nil)
501
+ new_tx.add_in( TxIn.new(prev_tx.binary_hash, 0, 0) )
502
+ pk_script = Bitcoin::Script.to_address_script("1FEYAh1x5jeKQMPPuv3bKnKvbgVAqXvqjW")
503
+ new_tx.add_out( TxOut.new(1000000, pk_script) )
504
+ signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
505
+ sig = Bitcoin.sign_data(key, signature_hash)
506
+ new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [pubkey].pack("H*"))
497
507
 
498
- new_tx = Tx.new( new_tx.to_payload )
499
- new_tx.hash.should != nil
500
- new_tx.verify_input_signature(0, prev_tx).should == true
508
+ new_tx = Tx.new( new_tx.to_payload )
509
+ new_tx.hash.should != nil
510
+ new_tx.verify_input_signature(0, prev_tx).should == true
501
511
 
502
512
 
503
513
 
504
- prev_tx = Tx.new( fixtures_file('rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin') )
505
- prev_tx.hash.should == "b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d"
514
+ prev_tx = Tx.new( fixtures_file('rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin') )
515
+ prev_tx.hash.should == "b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d"
506
516
 
507
- key = Bitcoin.open_key("56e28a425a7b588973b5db962a09b1aca7bdc4a7268cdd671d03c52a997255dc",
508
- pubkey="04324c6ebdcf079db6c9209a6b715b955622561262cde13a8a1df8ae0ef030eaa1552e31f8be90c385e27883a9d82780283d19507d7fa2e1e71a1d11bc3a52caf3")
509
- new_tx = Tx.new(nil)
510
- new_tx.add_in( TxIn.new(prev_tx.binary_hash, 0, 0) )
511
- new_tx.add_out( TxOut.value_to_address(1000000, "14yz7fob6Q16hZu4nXfmv1kRJpSYaFtet5") )
512
- signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
513
- sig = Bitcoin.sign_data(key, signature_hash)
514
- new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [pubkey].pack("H*"))
517
+ key = Bitcoin.open_key("56e28a425a7b588973b5db962a09b1aca7bdc4a7268cdd671d03c52a997255dc",
518
+ pubkey="04324c6ebdcf079db6c9209a6b715b955622561262cde13a8a1df8ae0ef030eaa1552e31f8be90c385e27883a9d82780283d19507d7fa2e1e71a1d11bc3a52caf3")
519
+ new_tx = Tx.new(nil)
520
+ new_tx.add_in( TxIn.new(prev_tx.binary_hash, 0, 0) )
521
+ new_tx.add_out( TxOut.value_to_address(1000000, "14yz7fob6Q16hZu4nXfmv1kRJpSYaFtet5") )
522
+ signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
523
+ sig = Bitcoin.sign_data(key, signature_hash)
524
+ new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [pubkey].pack("H*"))
515
525
 
516
- new_tx = Tx.new( new_tx.to_payload )
517
- new_tx.hash.should != nil
518
- new_tx.verify_input_signature(0, prev_tx).should == true
526
+ new_tx = Tx.new( new_tx.to_payload )
527
+ new_tx.hash.should != nil
528
+ new_tx.verify_input_signature(0, prev_tx).should == true
529
+ end
519
530
 
520
- #File.open("rawtx-#{new_tx.hash}.bin",'wb'){|f| f.print new_tx.to_payload }
521
- prev_tx = Tx.new( fixtures_file('rawtx-52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2.bin') )
522
- prev_tx.hash.should == "52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2"
523
- #File.open("rawtx-#{prev_tx.hash}.json",'wb'){|f| f.print prev_tx.to_json }
531
+ it 'sighash JSON tests' do
532
+ test_cases = JSON.parse(fixtures_file('sighash.json'))
533
+ test_cases.each do |test_case|
534
+ # Single element arrays in tests are comments.
535
+ next if test_case.length == 1
536
+
537
+ transaction = Bitcoin::Protocol::Tx.new(test_case[0].htb)
538
+ subscript = test_case[1].htb
539
+ input_index = test_case[2].to_i
540
+ hash_type = test_case[3]
541
+ amount = 0
542
+ expected_sighash = test_case[4].htb_reverse
543
+
544
+ actual_sighash = transaction.signature_hash_for_input(
545
+ input_index, subscript, hash_type, amount, 0)
546
+ actual_sighash.should == expected_sighash
547
+ end
548
+ end
524
549
  end
525
550
 
526
551
  it '#signature_hash_for_witness_input' do
@@ -758,5 +783,109 @@ describe 'Tx' do
758
783
  tx.out[1].pk_script.bth.should == 'bbbbbbbb'
759
784
  tx.out[2].pk_script.bth.should == 'cccccccc'
760
785
  end
761
-
786
+
787
+ describe 'verify_input_signature' do
788
+ def parse_script(script_str)
789
+ script = Bitcoin::Script.new('')
790
+
791
+ buf = ""
792
+ script_str.split.each do |token|
793
+ opcode = Bitcoin::Script::OPCODES_PARSE_STRING[token] ||
794
+ Bitcoin::Script::OPCODES_PARSE_STRING['OP_' + token]
795
+ if opcode
796
+ buf << [opcode].pack('C')
797
+ next
798
+ end
799
+
800
+ data =
801
+ case token
802
+ when /\A-?\d+\z/
803
+ i = token.to_i
804
+ opcode =
805
+ case i
806
+ when -1 then Bitcoin::Script::OP_1NEGATE
807
+ when 0 then Bitcoin::Script::OP_0
808
+ when 1 then Bitcoin::Script::OP_1
809
+ when 2..16 then Bitcoin::Script::OP_2 + i - 2
810
+ end
811
+
812
+ if opcode
813
+ [opcode].pack('C')
814
+ else
815
+ Bitcoin::Script.pack_pushdata(script.cast_to_string(i))
816
+ end
817
+ when /\A'(.*)'\z/ then Bitcoin::Script.pack_pushdata($1)
818
+ when /\A0x([0-9a-fA-F]+)\z/ then $1.htb
819
+ else raise "Unexpected token #{token}"
820
+ end
821
+ buf << data
822
+ end
823
+ buf
824
+ end
825
+
826
+ def parse_flags(flags_str)
827
+ flags_str.split(',').each_with_object({}) do |flag_str, opts|
828
+ case flag_str.to_sym
829
+ when :STRICTENC then opts[:verify_strictenc] = true
830
+ when :DERSIG then opts[:verify_dersig] = true
831
+ when :LOW_S then opts[:verify_low_s] = true
832
+ when :SIGPUSHONLY then opts[:verify_sigpushonly] = true
833
+ when :MINIMALDATA then opts[:verify_minimaldata] = true
834
+ when :CLEANSTACK then opts[:verify_cleanstack] = true
835
+ when :SIGHASH_FORKID then opts[:fork_id] = 0
836
+ end
837
+ end
838
+ end
839
+
840
+ it 'script JSON tests' do
841
+ test_cases = JSON.parse(fixtures_file('script_tests.json'))
842
+ test_cases.each_with_index do |test_case, i|
843
+ # Single element arrays in tests are comments.
844
+ next if test_case.length == 1
845
+
846
+ value =
847
+ if test_case[0].is_a?(Array)
848
+ (test_case.shift[0] * 10**8).to_i
849
+ else
850
+ 0
851
+ end
852
+
853
+ # TODO: Implement these opcodes correctly
854
+ next if test_case[0].match(/CHECKLOCKTIMEVERIFY|CHECKSEQUENCEVERIFY|RESERVED|0x50|VERIF|VERNOTIF/)
855
+ next if test_case[1].match(/CHECKLOCKTIMEVERIFY|CHECKSEQUENCEVERIFY|RESERVED|0x50|VERIF|VERNOTIF/)
856
+
857
+ script_sig = parse_script(test_case[0])
858
+ script_pubkey = parse_script(test_case[1])
859
+ opts = parse_flags(test_case[2])
860
+ expect_success = test_case[3] == 'OK'
861
+
862
+ # A lot of the test cases are failing, so for now we only test the SIGHASH_FORKID ones.
863
+ # TODO: Get this spec passing without this line.
864
+ next unless opts[:fork_id]
865
+
866
+ crediting_tx = Tx.new
867
+ crediting_tx.add_in(TxIn.new)
868
+ crediting_tx.in[0].prev_out_hash = TxIn::NULL_HASH
869
+ crediting_tx.in[0].prev_out_index = TxIn::COINBASE_INDEX
870
+ crediting_tx.in[0].script_sig = parse_script('0 0')
871
+ crediting_tx.add_out(TxOut.new)
872
+ crediting_tx.out[0].value = value
873
+ crediting_tx.out[0].pk_script = script_pubkey
874
+ crediting_tx.refresh_hash
875
+
876
+ spending_tx = Tx.new
877
+ spending_tx.add_in(TxIn.new)
878
+ spending_tx.in[0].prev_out_hash = crediting_tx.binary_hash
879
+ spending_tx.in[0].prev_out_index = 0
880
+ spending_tx.in[0].script_sig = script_sig
881
+ spending_tx.add_out(TxOut.new)
882
+ spending_tx.out[0].value = value
883
+ spending_tx.out[0].pk_script = ''
884
+ spending_tx.refresh_hash
885
+
886
+ success = spending_tx.verify_input_signature(0, crediting_tx, Time.now.to_i, opts)
887
+ success.should == expect_success
888
+ end
889
+ end
890
+ end
762
891
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitcoin-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - lian
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-05 00:00:00.000000000 Z
11
+ date: 2017-10-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: This is a ruby library for interacting with the bitcoin protocol/network
14
14
  email:
@@ -155,6 +155,8 @@ files:
155
155
  - spec/bitcoin/fixtures/reorg/blk_3A.dat
156
156
  - spec/bitcoin/fixtures/reorg/blk_4A.dat
157
157
  - spec/bitcoin/fixtures/reorg/blk_5A.dat
158
+ - spec/bitcoin/fixtures/script_tests.json
159
+ - spec/bitcoin/fixtures/sighash.json
158
160
  - spec/bitcoin/fixtures/testnet/block_0.bin
159
161
  - spec/bitcoin/fixtures/testnet/block_1.bin
160
162
  - spec/bitcoin/fixtures/testnet/block_2.bin
@@ -259,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
259
261
  version: 1.3.6
260
262
  requirements: []
261
263
  rubyforge_project: bitcoin-ruby
262
- rubygems_version: 2.6.11
264
+ rubygems_version: 2.5.2
263
265
  signing_key:
264
266
  specification_version: 4
265
267
  summary: bitcoin utils and protocol in ruby
@@ -356,6 +358,8 @@ test_files:
356
358
  - spec/bitcoin/fixtures/reorg/blk_3A.dat
357
359
  - spec/bitcoin/fixtures/reorg/blk_4A.dat
358
360
  - spec/bitcoin/fixtures/reorg/blk_5A.dat
361
+ - spec/bitcoin/fixtures/script_tests.json
362
+ - spec/bitcoin/fixtures/sighash.json
359
363
  - spec/bitcoin/fixtures/testnet/block_0.bin
360
364
  - spec/bitcoin/fixtures/testnet/block_1.bin
361
365
  - spec/bitcoin/fixtures/testnet/block_2.bin