bitcoin-ruby 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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