bitcoin-ruby 0.0.1 → 0.0.2

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.
Files changed (136) hide show
  1. data/.gitignore +4 -1
  2. data/Gemfile +21 -0
  3. data/README.rdoc +85 -25
  4. data/Rakefile +7 -3
  5. data/bin/bitcoin_node +39 -42
  6. data/bin/bitcoin_shell +1 -0
  7. data/bin/bitcoin_wallet +129 -53
  8. data/bitcoin-ruby.gemspec +4 -7
  9. data/concept-examples/blockchain-pow.rb +1 -1
  10. data/doc/CONFIG.rdoc +5 -5
  11. data/doc/EXAMPLES.rdoc +9 -5
  12. data/doc/NAMECOIN.rdoc +34 -0
  13. data/doc/NODE.rdoc +147 -10
  14. data/examples/balance.rb +10 -4
  15. data/examples/bbe_verify_tx.rb +7 -2
  16. data/examples/forwarder.rb +73 -0
  17. data/examples/generate_tx.rb +34 -0
  18. data/examples/simple_network_monitor_and_util.rb +187 -0
  19. data/examples/verify_tx.rb +1 -1
  20. data/lib/bitcoin.rb +308 -18
  21. data/lib/bitcoin/builder.rb +62 -36
  22. data/lib/bitcoin/config.rb +2 -0
  23. data/lib/bitcoin/connection.rb +11 -8
  24. data/lib/bitcoin/electrum/mnemonic.rb +162 -0
  25. data/lib/bitcoin/ffi/openssl.rb +187 -21
  26. data/lib/bitcoin/gui/addr_view.rb +2 -0
  27. data/lib/bitcoin/gui/conn_view.rb +2 -0
  28. data/lib/bitcoin/gui/connection.rb +2 -0
  29. data/lib/bitcoin/gui/em_gtk.rb +2 -0
  30. data/lib/bitcoin/gui/gui.rb +2 -0
  31. data/lib/bitcoin/gui/helpers.rb +2 -0
  32. data/lib/bitcoin/gui/tree_view.rb +2 -0
  33. data/lib/bitcoin/gui/tx_view.rb +2 -0
  34. data/lib/bitcoin/key.rb +77 -11
  35. data/lib/bitcoin/litecoin.rb +81 -0
  36. data/lib/bitcoin/logger.rb +20 -1
  37. data/lib/bitcoin/namecoin.rb +279 -0
  38. data/lib/bitcoin/network/command_client.rb +7 -6
  39. data/lib/bitcoin/network/command_handler.rb +229 -43
  40. data/lib/bitcoin/network/connection_handler.rb +182 -70
  41. data/lib/bitcoin/network/node.rb +231 -106
  42. data/lib/bitcoin/protocol.rb +44 -23
  43. data/lib/bitcoin/protocol/address.rb +5 -3
  44. data/lib/bitcoin/protocol/alert.rb +3 -4
  45. data/lib/bitcoin/protocol/aux_pow.rb +123 -0
  46. data/lib/bitcoin/protocol/block.rb +98 -18
  47. data/lib/bitcoin/protocol/handler.rb +6 -5
  48. data/lib/bitcoin/protocol/parser.rb +44 -19
  49. data/lib/bitcoin/protocol/tx.rb +105 -52
  50. data/lib/bitcoin/protocol/txin.rb +39 -19
  51. data/lib/bitcoin/protocol/txout.rb +28 -13
  52. data/lib/bitcoin/protocol/version.rb +16 -7
  53. data/lib/bitcoin/script.rb +579 -122
  54. data/lib/bitcoin/storage/{dummy.rb → dummy/dummy_store.rb} +8 -14
  55. data/lib/bitcoin/storage/models.rb +20 -7
  56. data/lib/bitcoin/storage/{sequel_store/sequel_migrations.rb → sequel/migrations.rb} +22 -7
  57. data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +52 -0
  58. data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +50 -0
  59. data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +18 -0
  60. data/lib/bitcoin/storage/sequel/sequel_store.rb +436 -0
  61. data/lib/bitcoin/storage/storage.rb +233 -28
  62. data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +52 -0
  63. data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +18 -0
  64. data/lib/bitcoin/storage/utxo/utxo_store.rb +361 -0
  65. data/lib/bitcoin/validation.rb +369 -0
  66. data/lib/bitcoin/version.rb +1 -1
  67. data/lib/bitcoin/wallet/coinselector.rb +3 -0
  68. data/lib/bitcoin/wallet/keygenerator.rb +3 -1
  69. data/lib/bitcoin/wallet/keystore.rb +6 -2
  70. data/lib/bitcoin/wallet/txdp.rb +6 -4
  71. data/lib/bitcoin/wallet/wallet.rb +54 -16
  72. data/spec/bitcoin/bitcoin_spec.rb +48 -3
  73. data/spec/bitcoin/builder_spec.rb +40 -17
  74. data/spec/bitcoin/fixtures/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +3697 -0
  75. data/spec/bitcoin/fixtures/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +23 -0
  76. data/spec/bitcoin/fixtures/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +24 -0
  77. data/spec/bitcoin/fixtures/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +37 -0
  78. data/spec/bitcoin/fixtures/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +31 -0
  79. data/spec/bitcoin/fixtures/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +27 -0
  80. data/spec/bitcoin/fixtures/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +72 -0
  81. data/spec/bitcoin/fixtures/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +27 -0
  82. data/spec/bitcoin/fixtures/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +24 -0
  83. data/spec/bitcoin/fixtures/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +30 -0
  84. data/spec/bitcoin/fixtures/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +28 -0
  85. data/spec/bitcoin/fixtures/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +27 -0
  86. data/spec/bitcoin/fixtures/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +27 -0
  87. data/spec/bitcoin/fixtures/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +27 -0
  88. data/spec/bitcoin/fixtures/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +34 -0
  89. data/spec/bitcoin/fixtures/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
  90. data/spec/bitcoin/fixtures/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +24 -0
  91. data/spec/bitcoin/fixtures/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +41 -0
  92. data/spec/bitcoin/fixtures/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +23 -0
  93. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
  94. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +43 -0
  95. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
  96. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +67 -0
  97. data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
  98. data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +39 -0
  99. data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
  100. data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +39 -0
  101. data/spec/bitcoin/fixtures/rawblock-auxpow.bin +0 -0
  102. data/spec/bitcoin/fixtures/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +30 -0
  103. data/spec/bitcoin/fixtures/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +23 -0
  104. data/spec/bitcoin/fixtures/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +30 -0
  105. data/spec/bitcoin/fixtures/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +28 -0
  106. data/spec/bitcoin/key_spec.rb +128 -3
  107. data/spec/bitcoin/namecoin_spec.rb +182 -0
  108. data/spec/bitcoin/network_spec.rb +5 -3
  109. data/spec/bitcoin/node/command_api_spec.rb +376 -0
  110. data/spec/bitcoin/protocol/addr_spec.rb +2 -0
  111. data/spec/bitcoin/protocol/alert_spec.rb +2 -0
  112. data/spec/bitcoin/protocol/aux_pow_spec.rb +44 -0
  113. data/spec/bitcoin/protocol/block_spec.rb +134 -39
  114. data/spec/bitcoin/protocol/getblocks_spec.rb +32 -0
  115. data/spec/bitcoin/protocol/inv_spec.rb +10 -8
  116. data/spec/bitcoin/protocol/notfound_spec.rb +31 -0
  117. data/spec/bitcoin/protocol/ping_spec.rb +2 -0
  118. data/spec/bitcoin/protocol/tx_spec.rb +83 -17
  119. data/spec/bitcoin/protocol/version_spec.rb +7 -5
  120. data/spec/bitcoin/script/opcodes_spec.rb +412 -133
  121. data/spec/bitcoin/script/script_spec.rb +112 -13
  122. data/spec/bitcoin/spec_helper.rb +68 -0
  123. data/spec/bitcoin/storage/reorg_spec.rb +199 -0
  124. data/spec/bitcoin/storage/storage_spec.rb +337 -0
  125. data/spec/bitcoin/storage/validation_spec.rb +261 -0
  126. data/spec/bitcoin/wallet/coinselector_spec.rb +10 -7
  127. data/spec/bitcoin/wallet/keygenerator_spec.rb +2 -0
  128. data/spec/bitcoin/wallet/keystore_spec.rb +2 -0
  129. data/spec/bitcoin/wallet/txdp_spec.rb +2 -0
  130. data/spec/bitcoin/wallet/wallet_spec.rb +91 -58
  131. metadata +105 -51
  132. data/lib/bitcoin/storage/sequel.rb +0 -335
  133. data/spec/bitcoin/fixtures/0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd.json +0 -27
  134. data/spec/bitcoin/fixtures/477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590.json +0 -27
  135. data/spec/bitcoin/reorg_spec.rb +0 -129
  136. data/spec/bitcoin/storage_spec.rb +0 -229
@@ -1,3 +1,5 @@
1
+ # encoding: ascii-8bit
2
+
1
3
  require_relative '../spec_helper.rb'
2
4
 
3
5
  describe 'Bitcoin::Protocol::Parser (addr)' do
@@ -1,3 +1,5 @@
1
+ # encoding: ascii-8bit
2
+
1
3
  require_relative '../spec_helper.rb'
2
4
 
3
5
  describe 'Bitcoin::Protocol::Parser (alert)' do
@@ -0,0 +1,44 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+
5
+ include Bitcoin
6
+
7
+ describe Bitcoin::Protocol::AuxPow do
8
+
9
+ before do
10
+ @data = fixtures_file("rawblock-auxpow.bin")
11
+ @blk = P::Block.new(@data)
12
+ @aux_pow = @blk.aux_pow
13
+ end
14
+
15
+ it "should parse AuxPow" do
16
+ @aux_pow.should != nil
17
+ @aux_pow.block_hash.hth.should ==
18
+ "b42124fd99e67ddabe52ebbfcb30a82b8c74268a320b3c5e2311000000000000"
19
+ @aux_pow.branch.map(&:hth).should == [
20
+ "6d4febe909ffec61fb8e7bf24ef4444f070f74b208502285528a9686ba792fc2",
21
+ "d052728459450cec6ff81072c6bd3ec2fd186eaadb09429da7cab0be73646999",
22
+ "64c5e7e42a6cde585602fdfda6d7e5d9232db2c176a49278268cec09f3cfcb20",
23
+ "4e9406d6ce9ef751242bb9a63e7c2009746b3736c356ed5d738dadd6937531e4" ]
24
+ @aux_pow.mrkl_index.should == 0
25
+ @aux_pow.aux_branch.should == []
26
+ @aux_pow.aux_index.should == 0
27
+ @aux_pow.parent_block.hash.should ==
28
+ "00000000000011235e3c0b328a26748c2ba830cbbfeb52beda7de699fd2421b4"
29
+ end
30
+
31
+ it "#to_payload" do
32
+ @blk.to_payload.should == @data
33
+ P::Block.new(@blk.to_payload).to_payload.should == @data
34
+ end
35
+
36
+ it "#to_hash" do
37
+ P::Block.from_hash(@blk.to_hash).to_payload.should == @data
38
+ end
39
+
40
+ it "#to_json" do
41
+ P::Block.from_json(@blk.to_json).to_payload.should == @data
42
+ end
43
+
44
+ end
@@ -1,39 +1,43 @@
1
+ # encoding: ascii-8bit
2
+
1
3
  require_relative '../spec_helper.rb'
4
+ include Bitcoin::Protocol
2
5
 
3
6
  describe 'Bitcoin::Protocol::Block' do
4
7
 
5
- @blocks = {
6
- # block 0: 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
7
- '0' => fixtures_file('rawblock-0.bin'),
8
- # block 1: 000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd
9
- '1' => fixtures_file('rawblock-1.bin'),
10
- # block 9: 000000008d9dc510f23c2657fc4f67bea30078cc05a90eb89e84cc475c080805
11
- '9' => fixtures_file('rawblock-9.bin'),
12
- # block 170: 00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee
13
- '170' => fixtures_file('rawblock-170.bin'),
14
- # block 131025: 00000000000007d938dbdd433c5ae12a782de74abf7f566518bc2b2d0a1df145
15
- '131025' => fixtures_file('rawblock-131025.bin'),
16
- # block 26478: 000000000214a3f06ee99a033a7f2252762d6a18d27c3cd8c8fe2278190da9f3
17
- 'testnet-26478' => fixtures_file('rawblock-testnet-26478.bin'),
18
- }
19
-
8
+ before do
9
+ @blocks = {
10
+ # block 0: 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
11
+ '0' => fixtures_file('rawblock-0.bin'),
12
+ # block 1: 000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd
13
+ '1' => fixtures_file('rawblock-1.bin'),
14
+ # block 9: 000000008d9dc510f23c2657fc4f67bea30078cc05a90eb89e84cc475c080805
15
+ '9' => fixtures_file('rawblock-9.bin'),
16
+ # block 170: 00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee
17
+ '170' => fixtures_file('rawblock-170.bin'),
18
+ # block 131025: 00000000000007d938dbdd433c5ae12a782de74abf7f566518bc2b2d0a1df145
19
+ '131025' => fixtures_file('rawblock-131025.bin'),
20
+ # block 26478: 000000000214a3f06ee99a033a7f2252762d6a18d27c3cd8c8fe2278190da9f3
21
+ 'testnet-26478' => fixtures_file('rawblock-testnet-26478.bin'),
22
+ }
23
+ end
20
24
 
21
25
  it '#new' do
22
26
  proc{
23
- Bitcoin::Protocol::Block.new( nil )
24
- @block = Bitcoin::Protocol::Block.new( @blocks['0'] )
27
+ Block.new( nil )
28
+ @block = Block.new( @blocks['0'] )
25
29
  }.should.not.raise Exception
26
30
 
27
31
  proc{
28
- Bitcoin::Protocol::Block.new( @blocks['0'][0..20] )
32
+ Block.new( @blocks['0'][0..20] )
29
33
  }.should.raise Exception
30
34
 
31
- block = Bitcoin::Protocol::Block.new(nil)
35
+ block = Block.new(nil)
32
36
  block.parse_data(@blocks['0']).should == true
33
37
  block.header_info[7].should == 215
34
38
  block.to_payload.should == @blocks['0']
35
39
 
36
- block = Bitcoin::Protocol::Block.new(nil)
40
+ block = Block.new(nil)
37
41
  block.parse_data(@blocks['0'] + "AAAA").should == "AAAA"
38
42
  block.header_info[7].should == 215
39
43
  block.to_payload.should == @blocks['0']
@@ -45,7 +49,7 @@ describe 'Bitcoin::Protocol::Block' do
45
49
 
46
50
  it '#tx' do
47
51
  @block.tx.size.should == 1
48
- @block.tx[0].is_a?(Bitcoin::Protocol::Tx).should == true
52
+ @block.tx[0].is_a?(Tx).should == true
49
53
  @block.tx[0].hash.should == "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"
50
54
  end
51
55
 
@@ -55,31 +59,100 @@ describe 'Bitcoin::Protocol::Block' do
55
59
 
56
60
  it '#to_json' do
57
61
  @block.to_json.should == fixtures_file('rawblock-0.json')
58
- Bitcoin::Protocol::Block.new( @blocks['1'] ).to_json.should == fixtures_file('rawblock-1.json')
59
- Bitcoin::Protocol::Block.new( @blocks['131025'] ).to_json.should == fixtures_file('rawblock-131025.json')
60
- Bitcoin::Protocol::Block.new( @blocks['testnet-26478'] ).to_json.should == fixtures_file('rawblock-testnet-26478.json')
61
- Bitcoin::P::Block.from_json(@block.to_json).tx[0].in[0].sequence.should == "\xff\xff\xff\xff"
62
+ Block.new( @blocks['1'] ).to_json.should == fixtures_file('rawblock-1.json')
63
+ Block.new( @blocks['131025'] ).to_json.should == fixtures_file('rawblock-131025.json')
64
+ Block.new( @blocks['testnet-26478'] ).to_json.should == fixtures_file('rawblock-testnet-26478.json')
65
+ Block.from_json(@block.to_json).tx[0].in[0].sequence.should == "\xff\xff\xff\xff"
62
66
  end
63
67
 
64
68
  it '#to_payload' do
65
69
  @block.to_payload.should == @block.payload
66
- Bitcoin::Protocol::Block.new( @block.to_payload ).to_payload.should == @block.payload
67
- Bitcoin::Protocol::Block.new( @blocks['1'] ).to_payload.should == @blocks['1']
68
- Bitcoin::Protocol::Block.new( @blocks['131025'] ).to_payload.should == @blocks['131025']
69
- Bitcoin::Protocol::Block.new( @blocks['testnet-26478'] ).to_payload.should == @blocks['testnet-26478']
70
+ Block.new( @block.to_payload ).to_payload.should == @block.payload
71
+ Block.new( @blocks['1'] ).to_payload.should == @blocks['1']
72
+ Block.new( @blocks['131025'] ).to_payload.should == @blocks['131025']
73
+ Block.new( @blocks['testnet-26478'] ).to_payload.should == @blocks['testnet-26478']
70
74
  end
71
75
 
72
- it '#from_json' do
73
- block = Bitcoin::Protocol::Block.from_json(fixtures_file('rawblock-0.json'))
74
- block.to_payload.should == @blocks['0']
75
- block.tx[0].in[0].sequence.should == "\xff\xff\xff\xff"
76
- Bitcoin::Protocol::Block.from_json(fixtures_file('rawblock-1.json')).to_payload.should == @blocks['1']
77
-
78
- Bitcoin::Protocol::Block.from_json(fixtures_file('rawblock-131025.json'))
79
- .to_payload.should == @blocks['131025']
76
+ describe "Block.from_json" do
77
+
78
+ it 'should load blocks from json' do
79
+ block = Block.from_json(fixtures_file('rawblock-0.json'))
80
+ block.to_payload.should == @blocks['0']
81
+ block.tx[0].in[0].sequence.should == "\xff\xff\xff\xff"
82
+ Block.from_json(fixtures_file('rawblock-1.json')).to_payload.should == @blocks['1']
83
+
84
+ Block.from_json(fixtures_file('rawblock-131025.json'))
85
+ .to_payload.should == @blocks['131025']
86
+
87
+ Block.from_json(fixtures_file('rawblock-testnet-26478.json'))
88
+ .to_payload.should == @blocks['testnet-26478']
89
+
90
+ # testnet3 block 0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab
91
+ block_raw = fixtures_file('block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin')
92
+ Block.new(block_raw).to_payload.should == block_raw
93
+ # Block.from_json(Block.new(block_raw).to_json).to_payload.should == block_raw # slow test
94
+ end
95
+
96
+ it "should work with litecoin blocks" do
97
+ Bitcoin.network = :litecoin # change to litecoin
98
+ litecoin_block = "litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2"
99
+ Block.from_json(fixtures_file(litecoin_block + '.json'))
100
+ .to_payload.should == fixtures_file(litecoin_block + '.bin')
101
+
102
+ json = Block.new(fixtures_file(litecoin_block + '.bin')).to_json
103
+ Block.from_json(json)
104
+ .to_payload.should == fixtures_file(litecoin_block + '.bin')
105
+ Block.from_json(json).hash == litecoin_block.split("-").last
106
+
107
+ litecoin_block = "litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f"
108
+ Block.from_json(fixtures_file(litecoin_block + '.json'))
109
+ .to_payload.should == fixtures_file(litecoin_block + '.bin')
110
+
111
+ json = Block.new(fixtures_file(litecoin_block + '.bin')).to_json
112
+ Block.from_json(json)
113
+ .to_payload.should == fixtures_file(litecoin_block + '.bin')
114
+ Block.from_json(json).hash == litecoin_block.split("-").last
115
+ Bitcoin.network = :bitcoin
116
+ end
117
+
118
+ it "should work with freicoin blocks" do
119
+ Bitcoin.network = :freicoin # change to freicoin
120
+ freicoin_block = "freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c"
121
+ Block.from_json(fixtures_file(freicoin_block + '.json'))
122
+ .to_payload.should == fixtures_file(freicoin_block + '.bin')
123
+
124
+ json = Block.new(fixtures_file(freicoin_block + '.bin')).to_json
125
+ Block.from_json(json)
126
+ .to_payload.should == fixtures_file(freicoin_block + '.bin')
127
+ Block.from_json(json).hash == freicoin_block.split("-").last
128
+
129
+ freicoin_block = "freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c"
130
+ Block.from_json(fixtures_file(freicoin_block + '.json'))
131
+ .to_payload.should == fixtures_file(freicoin_block + '.bin')
132
+
133
+ json = Block.new(fixtures_file(freicoin_block + '.bin')).to_json
134
+ Block.from_json(json)
135
+ .to_payload.should == fixtures_file(freicoin_block + '.bin')
136
+ Block.from_json(json).hash == freicoin_block.split("-").last
137
+ Bitcoin.network = :bitcoin
138
+ end
139
+
140
+ it 'should check block hash' do
141
+ block = Block.from_json(fixtures_file('rawblock-0.json'))
142
+ h = block.to_hash
143
+ h['hash'][0] = "1"
144
+ -> { Block.from_hash(h) }.should.raise(Exception)
145
+ .message.should == "Block hash mismatch! Claimed: 10000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048, Actual: 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048"
146
+ end
147
+
148
+ it "should check merkle tree" do
149
+ block = Block.from_json(fixtures_file('rawblock-0.json'))
150
+ h = block.to_hash
151
+ h['tx'][0]['ver'] = 2
152
+ -> { Block.from_hash(h) }.should.raise(Exception)
153
+ .message.should.include?("Block merkle root mismatch!")
154
+ end
80
155
 
81
- Bitcoin::Protocol::Block.from_json(fixtures_file('rawblock-testnet-26478.json'))
82
- .to_payload.should == @blocks['testnet-26478']
83
156
  end
84
157
 
85
158
  it '#header_to_json' do
@@ -98,4 +171,26 @@ describe 'Bitcoin::Protocol::Block' do
98
171
  JSON
99
172
  end
100
173
 
174
+ it '#verify_mrkl_root' do
175
+ block0 = Block.from_json(fixtures_file('rawblock-0.json'))
176
+ block1 = Block.from_json(fixtures_file('rawblock-1.json'))
177
+ block0.tx.size.should == 1
178
+ block0.verify_mrkl_root.should == true
179
+ block0.tx << block.tx.last # test against CVE-2012-2459
180
+ block0.verify_mrkl_root.should == false
181
+ block0.tx = block1.tx
182
+ block0.verify_mrkl_root.should == false
183
+ end
184
+
185
+ it '#bip34_block_height' do
186
+ # block version 1
187
+ block = Block.from_json(fixtures_file('rawblock-131025.json'))
188
+ block.ver.should == 1
189
+ block.bip34_block_height.should == nil
190
+ # block version 2 (introduced by BIP_0034)
191
+ block = Block.from_json(fixtures_file('000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json'))
192
+ block.ver.should == 2
193
+ block.bip34_block_height.should == 197657
194
+ end
195
+
101
196
  end
@@ -0,0 +1,32 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+
5
+ describe 'Bitcoin::Protocol::Parser (getblocks)' do
6
+
7
+ class Getblocks_Handler < Bitcoin::Protocol::Handler
8
+ attr_reader :version, :locator, :stop_hash
9
+ def on_getblocks(version, locator, stop_hash)
10
+ @version, @locator, @stop_hash = version, locator, stop_hash
11
+ end
12
+ end
13
+
14
+ before do
15
+ @parser = Bitcoin::Protocol::Parser.new( @handler = Getblocks_Handler.new )
16
+ @pkt = "f9beb4d9676574626c6f636b7300000065000000b3b7ad6e71110100026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000000000000000000000000000000000000000000000000000000000".htb
17
+ @parser.parse(@pkt + "AAAA").should == "AAAA"
18
+ end
19
+
20
+ it 'parses getblocks' do
21
+ @handler.version.should == 70001
22
+ @handler.locator.should == [
23
+ "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
24
+ "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" ]
25
+ @handler.stop_hash.should == "00"*32
26
+ end
27
+
28
+ it 'builds getblocks' do
29
+ Bitcoin::Protocol.getblocks_pkt(70001, @handler.locator).hth.should == @pkt.hth
30
+ end
31
+
32
+ end
@@ -1,3 +1,5 @@
1
+ # encoding: ascii-8bit
2
+
1
3
  require_relative '../spec_helper.rb'
2
4
 
3
5
  describe 'Bitcoin::Protocol::Parser - Inventory Vectors' do
@@ -5,10 +7,10 @@ describe 'Bitcoin::Protocol::Parser - Inventory Vectors' do
5
7
  class Test_Handler < Bitcoin::Protocol::Handler
6
8
  attr_reader :tx_inv
7
9
  attr_reader :block_inv
8
- def on_inv_transaction(hash); (@tx_inv ||= []) << hth(hash); end
9
- def on_get_transaction(hash); (@tx_inv ||= []) << hth(hash); end
10
- def on_inv_block(hash); (@block_inv ||= []) << hth(hash); end
11
- def on_get_block(hash); (@block_inv ||= []) << hth(hash); end
10
+ def on_inv_transaction(hash); (@tx_inv ||= []) << hash.hth; end
11
+ def on_get_transaction(hash); (@tx_inv ||= []) << hash.hth; end
12
+ def on_inv_block(hash); (@block_inv ||= []) << hash.hth; end
13
+ def on_get_block(hash); (@block_inv ||= []) << hash.hth; end
12
14
  end
13
15
 
14
16
 
@@ -89,13 +91,13 @@ describe 'Bitcoin::Protocol::Parser - Inventory Vectors' do
89
91
 
90
92
  locator_hashes = ["00000000068866924696f410b778911316f92035e9b69b62afa03573974fd750", "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"]
91
93
  stop_hash = "0000000000000000000000000000000000000000000000000000000000000000"
92
- pkt = Bitcoin::Protocol.getblocks_pkt( locator_hashes )
94
+ pkt = Bitcoin::Protocol.getblocks_pkt( Bitcoin.network[:protocol_version], locator_hashes )
93
95
 
94
96
  parser = Bitcoin::Protocol::Parser.new( handler = Test_Handler.new )
95
97
  parser.parse(pkt + "AAAA").should == "AAAA"
96
98
 
97
99
  handler.pkt.should == {
98
- :version => Bitcoin.network[:magic_head],
100
+ :version => Bitcoin.network[:protocol_version],
99
101
  :locator_hashes => locator_hashes,
100
102
  :stop_hash => "0000000000000000000000000000000000000000000000000000000000000000"
101
103
  }
@@ -109,13 +111,13 @@ describe 'Bitcoin::Protocol::Parser - Inventory Vectors' do
109
111
 
110
112
  locator_hashes = ["00000000068866924696f410b778911316f92035e9b69b62afa03573974fd750", "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"]
111
113
  stop_hash = "0000000000000000000000000000000000000000000000000000000000007e57"
112
- pkt = Bitcoin::Protocol.getblocks_pkt( locator_hashes, stop_hash )
114
+ pkt = Bitcoin::Protocol.getblocks_pkt( Bitcoin.network[:protocol_version], locator_hashes, stop_hash )
113
115
 
114
116
  parser = Bitcoin::Protocol::Parser.new( handler = Test_Handler.new )
115
117
  parser.parse(pkt + "AAAA").should == "AAAA"
116
118
 
117
119
  handler.pkt.should == {
118
- :version => Bitcoin.network[:magic_head],
120
+ :version => Bitcoin.network[:protocol_version],
119
121
  :locator_hashes => locator_hashes,
120
122
  :stop_hash => "0000000000000000000000000000000000000000000000000000000000007e57"
121
123
  }
@@ -0,0 +1,31 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+
5
+ describe 'Bitcoin::Protocol::Parser (notfound)' do
6
+
7
+ class Notfound_Handler < Bitcoin::Protocol::Handler
8
+ attr_reader :notfound
9
+ def on_notfound(type, hash); (@notfound ||= []) << [type, hash.hth]; end
10
+ end
11
+
12
+ before do
13
+ @parser = Bitcoin::Protocol::Parser.new( @handler = Notfound_Handler.new )
14
+ end
15
+
16
+ it 'parses notfound block message' do
17
+ payload = "\x01\x01\x00\x00\x00:\xE2\x93bDJ\x01\xA9|\xDA>0\x8F\a\xA3L\n\xEF\x0E\xD2\xF2\xC6\xCE\xCA(\xD19}\x80*h+"
18
+ @parser.parse(Bitcoin::Protocol.pkt("notfound", payload) + "AAAA").should == "AAAA"
19
+ @handler.notfound.should == [
20
+ [:tx, "2b682a807d39d128cacec6f2d20eef0a4ca3078f303eda7ca9014a446293e23a"]
21
+ ]
22
+ end
23
+
24
+ it 'parses notfound tx message' do
25
+ payload = "\x01\x02\x00\x00\x00:\xE2\x93bDJ\x01\xA9|\xDA>0\x8F\a\xA3L\n\xEF\x0E\xD2\xF2\xC6\xCE\xCA(\xD19}\x80*h+"
26
+ @parser.parse(Bitcoin::Protocol.pkt("notfound", payload) + "AAAA").should == "AAAA"
27
+ @handler.notfound.should == [
28
+ [:block, "2b682a807d39d128cacec6f2d20eef0a4ca3078f303eda7ca9014a446293e23a"]
29
+ ]
30
+ end
31
+ end
@@ -1,3 +1,5 @@
1
+ # encoding: ascii-8bit
2
+
1
3
  require_relative '../spec_helper.rb'
2
4
 
3
5
  describe 'Bitcoin::Protocol::Parser (ping/pong)' do
@@ -1,3 +1,5 @@
1
+ # encoding: ascii-8bit
2
+
1
3
  require_relative '../spec_helper.rb'
2
4
 
3
5
  include Bitcoin::Protocol
@@ -101,6 +103,10 @@ describe 'Tx' do
101
103
  tx = Tx.from_json( fixtures_file('rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json') )
102
104
  Tx.new( tx.to_payload ).to_json.should == tx.to_json
103
105
  tx.hash.should == 'ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5'
106
+
107
+ # coinbase tx with non-default sequence
108
+ tx = Tx.from_json( json=fixtures_file('0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json'))
109
+ Tx.new( tx.to_payload ).to_json.should == json
104
110
  end
105
111
 
106
112
  it 'Tx.binary_from_json' do
@@ -127,6 +133,49 @@ describe 'Tx' do
127
133
  outpoint_tx.hash.should == '406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602'
128
134
 
129
135
  tx.verify_input_signature(0, outpoint_tx).should == true
136
+
137
+
138
+ tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json'))
139
+ tx.hash.should == '0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae'
140
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json'))
141
+ outpoint_tx.hash.should == 'aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4'
142
+ tx.verify_input_signature(0, outpoint_tx).should == true
143
+
144
+ # SIGHASH_ANYONECANPAY transaction
145
+ tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json'))
146
+ tx.hash.should == '51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e'
147
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json'))
148
+ outpoint_tx.hash.should == '761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6'
149
+ tx.verify_input_signature(0, outpoint_tx).should == true
150
+
151
+ # BIP12/OP_EVAL does't exist.
152
+ tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json'))
153
+ tx.hash.should == '03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99'
154
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json'))
155
+ outpoint_tx.hash.should == 'f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b'
156
+ tx.verify_input_signature(0, outpoint_tx).should == true
157
+
158
+ # (SIGHASH_ANYONECANPAY | SIGHASH_SINGLE) p2sh transaction
159
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json'))
160
+ tx.hash.should == "7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d"
161
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json'))
162
+ outpoint_tx.hash.should == "3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477"
163
+ tx.verify_input_signature(0, outpoint_tx).should == true
164
+
165
+ # SIGHHASH_SINGLE - https://bitcointalk.org/index.php?topic=260595.0
166
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json'))
167
+ tx.hash.should == "315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f"
168
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json'))
169
+ outpoint_tx.hash.should == "69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc"
170
+ tx.verify_input_signature(0, outpoint_tx).should == true
171
+ tx.verify_input_signature(1, outpoint_tx).should == true
172
+
173
+ # 0:1:01 <signature> 0:1:01 0:1:00 <pubkey> OP_SWAP OP_1ADD OP_CHECKMULTISIG
174
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json'))
175
+ tx.hash.should == "cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2"
176
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json'))
177
+ outpoint_tx.hash.should == "514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58"
178
+ tx.verify_input_signature(0, outpoint_tx).should == true
130
179
  end
131
180
 
132
181
  it '#sign_input_signature' do
@@ -189,26 +238,17 @@ describe 'Tx' do
189
238
  #File.open("rawtx-#{prev_tx.hash}.json",'wb'){|f| f.print prev_tx.to_json }
190
239
  end
191
240
 
241
+ it '#calculate_minimum_fee' do
242
+ tx = Tx.new( fixtures_file('rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin') )
243
+ tx.minimum_relay_fee.should == 0
244
+ tx.minimum_block_fee.should == 0
245
+ tx = Tx.from_json(fixtures_file('bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json'))
246
+ tx.minimum_relay_fee.should == 10_000
247
+ tx.minimum_block_fee.should == 50_000
248
+ end
192
249
 
193
250
  describe "Tx - BIP Scripts" do
194
251
 
195
- it "should do OP_CHECKHASHVERIFY (BIP_0017)" do # https://en.bitcoin.it/wiki/BIP_0017
196
- # scriptSig: [signatures...] OP_CODESEPARATOR 1 [pubkey1] [pubkey2] 2 OP_CHECKMULTISIG
197
- # scriptPubKey: [20-byte-hash of {1 [pubkey1] [pubkey2] 2 OP_CHECKMULTISIG} ] OP_CHECKHASHVERIFY OP_DROP
198
-
199
- tx = Tx.from_json(fixtures_file('bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json'))
200
- tx.hash.should == "bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba"
201
-
202
- prev_tx1 = Tx.from_json(fixtures_file('477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590.json'))
203
- prev_tx1.hash.should == "477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590"
204
-
205
- prev_tx2 = Tx.from_json(fixtures_file('0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd.json'))
206
- prev_tx2.hash.should == "0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd"
207
-
208
- tx.verify_input_signature(0, prev_tx1).should == true
209
- tx.verify_input_signature(1, prev_tx2).should == true
210
- end
211
-
212
252
  it "should do OP_CHECKMULTISIG" do
213
253
  # checkmultisig without checkhashverify
214
254
  tx = Tx.from_json(fixtures_file('23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json'))
@@ -221,6 +261,32 @@ describe 'Tx' do
221
261
  tx.verify_input_signature(0, prev_tx).should == true
222
262
  end
223
263
 
264
+ it "should do P2SH with inner OP_CHECKMULTISIG (BIP 0016)" do
265
+ tx = Tx.from_json(fixtures_file('3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json'))
266
+ prev_tx = Tx.from_json(fixtures_file('35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json'))
267
+ tx.verify_input_signature(0, prev_tx).should == true
268
+
269
+ tx = Tx.from_json(fixtures_file('bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json'))
270
+ prev_tx = Tx.from_json(fixtures_file('ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json'))
271
+ tx.verify_input_signature(1, prev_tx).should == true
272
+
273
+ # p2sh transaction with non-standard OP_CHECKMULTISIG inside found in testnet3 tx: d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830
274
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json'))
275
+ tx.hash.should == "d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830"
276
+ prev_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json'))
277
+ prev_tx.hash.should == "313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0"
278
+ tx.verify_input_signature(0, prev_tx).should == true
279
+ end
280
+
281
+ it "should do P2SH with inner OP_CHECKSIG" do
282
+ # p2sh transaction with non-standard OP_CHECKSIG inside found in testnet3 tx: 3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae
283
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json'))
284
+ tx.hash.should == "3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae"
285
+ prev_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json'))
286
+ prev_tx.hash.should == "44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a"
287
+ tx.verify_input_signature(0, prev_tx).should == true
288
+ end
289
+
224
290
  end
225
291
 
226
292
  end