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 (version)' do
@@ -19,7 +21,7 @@ describe 'Bitcoin::Protocol::Parser (version)' do
19
21
  pkt = handler.pkt
20
22
  pkt.fields.should == {
21
23
  :version => 60000,
22
- :services => "\x01\x00\x00\x00\x00\x00\x00\x00",
24
+ :services => Bitcoin::Protocol::Version::NODE_NETWORK,
23
25
  :time => 1329775027,
24
26
  :from => "127.0.0.1:18333",
25
27
  :to => "127.0.0.1:57802",
@@ -39,12 +41,12 @@ describe 'Bitcoin::Protocol::Parser (version)' do
39
41
  pkt = handler.pkt
40
42
  pkt.fields.should == {
41
43
  :version => 40000,
42
- :services => "\x01\x00\x00\x00\x00\x00\x00\x00",
44
+ :services => Bitcoin::Protocol::Version::NODE_NETWORK,
43
45
  :time => 1321812496,
44
46
  :from => "127.0.0.1:18333",
45
47
  :to => "127.0.0.1:1234",
46
48
  :nonce => 8210299263586646091,
47
- :user_agent => nil,
49
+ :user_agent => '',
48
50
  :last_block => 250
49
51
  }
50
52
  end
@@ -63,8 +65,8 @@ describe 'Bitcoin::Protocol::Parser (version)' do
63
65
 
64
66
  pkt = handler.pkt
65
67
  pkt.fields.should == {
66
- :version => Bitcoin::Protocol::VERSION,
67
- :services => "\x01\x00\x00\x00\x00\x00\x00\x00",
68
+ :version => Bitcoin.network[:protocol_version],
69
+ :services => Bitcoin::Protocol::Version::NODE_NETWORK,
68
70
  :time => 1337,
69
71
  :to => "127.0.0.1:8333",
70
72
  :from => "127.0.0.1:1234",
@@ -1,3 +1,5 @@
1
+ # encoding: ascii-8bit
2
+
1
3
  require_relative '../spec_helper.rb'
2
4
  require 'bitcoin/script'
3
5
 
@@ -6,7 +8,6 @@ describe "Bitcoin::Script OPCODES" do
6
8
  before do
7
9
  @script = Bitcoin::Script.new("")
8
10
  @script.class.instance_eval { attr_accessor :stack, :stack_alt }
9
- @script.stack << "foobar"
10
11
  end
11
12
 
12
13
  def op(op, stack)
@@ -16,68 +17,52 @@ describe "Bitcoin::Script OPCODES" do
16
17
  end
17
18
 
18
19
  it "should do OP_NOP" do
19
- @script.op_nop
20
- @script.stack.should == ["foobar"]
20
+ op(:nop, ["foobar"]).should == ["foobar"]
21
21
  end
22
22
 
23
23
  it "should do OP_DUP" do
24
- @script.op_dup
25
- @script.stack.should == ["foobar", "foobar"]
24
+ op(:dup, ["foobar"]).should == ["foobar", "foobar"]
26
25
  end
27
26
 
28
27
  it "should do OP_SHA256" do
29
- @script.op_sha256
30
- @script.stack.should ==
31
- [["c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"].pack("H*")]
28
+ op(:sha256, ["foobar"]).should == [["c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"].pack("H*")]
32
29
  end
33
30
 
34
31
  it "should do OP_SHA1" do
35
- @script.op_sha1
36
- @script.stack.should ==
37
- [["8843d7f92416211de9ebb963ff4ce28125932878"].pack("H*")]
32
+ op(:sha1, ["foobar"]).should == [["8843d7f92416211de9ebb963ff4ce28125932878"].pack("H*")]
38
33
  end
39
34
 
40
35
  it "should do OP_HASH160" do
41
- @script.op_hash160
42
- @script.stack.should ==
43
- [["f6c97547d73156abb300ae059905c4acaadd09dd"].pack("H*")]
36
+ op(:hash160, ["foobar"]).should == [["f6c97547d73156abb300ae059905c4acaadd09dd"].pack("H*")]
44
37
  end
45
38
 
46
39
  it "should do OP_RIPEMD160" do
47
- @script.op_ripemd160
48
- @script.stack.should ==
49
- [["a06e327ea7388c18e4740e350ed4e60f2e04fc41"].pack("H*")]
40
+ op(:ripemd160, ["foobar"]).should == [["a06e327ea7388c18e4740e350ed4e60f2e04fc41"].pack("H*")]
50
41
  end
51
42
 
52
43
  it "should do OP_HASH256" do
53
- @script.op_hash256
54
- @script.stack.should ==
55
- [["3f2c7ccae98af81e44c0ec419659f50d8b7d48c681e5d57fc747d0461e42dda1"].pack("H*")]
44
+ op(:hash256, ["foobar"]).should == [["3f2c7ccae98af81e44c0ec419659f50d8b7d48c681e5d57fc747d0461e42dda1"].pack("H*")]
56
45
  end
57
46
 
58
47
  it "should do OP_TOALTSTACK" do
59
- @script.op_toaltstack
60
- @script.stack.should == []
48
+ op(:toaltstack, ["foobar"]).should == []
61
49
  @script.stack_alt.should == ["foobar"]
62
50
  end
63
51
 
64
52
  it "should do OP_FROMALTSTACK" do
65
- @script.instance_eval { @stack_alt << "barfoo" }
53
+ @script.instance_eval { @stack = [] }
54
+ @script.instance_eval { @stack_alt = ["foo"] }
66
55
  @script.op_fromaltstack
67
- @script.stack.should == ["foobar", "barfoo"]
56
+ @script.stack.should == ["foo"]
68
57
  @script.stack_alt.should == []
69
58
  end
70
59
 
71
60
  it "should do OP_TUCK" do
72
- @script.instance_eval { @stack += ["foo", "bar"] }
73
- @script.op_tuck
74
- @script.stack.should == ["foobar", "bar", "foo", "bar"]
61
+ op(:tuck, ["foobar", "foo", "bar"]).should == ["foobar", "bar", "foo", "bar"]
75
62
  end
76
63
 
77
64
  it "should do OP_SWAP" do
78
- @script.instance_eval { @stack << "barfoo" }
79
- @script.op_swap
80
- @script.stack.should == ["barfoo", "foobar"]
65
+ op(:swap, ["foo", "bar"]).should == ["bar", "foo"]
81
66
  end
82
67
 
83
68
  it "should do OP_BOOLAND" do
@@ -94,20 +79,19 @@ describe "Bitcoin::Script OPCODES" do
94
79
  end
95
80
 
96
81
  it "should do OP_SUB" do
97
- op(:sub, [2, 3]).should == [1]
98
- op(:sub, [1, 9]).should == [8]
99
- op(:sub, [3, 1]).should == [-2]
82
+ op(:sub, [3, 2]).should == [1]
83
+ op(:sub, [9, 1]).should == [8]
84
+ op(:sub, [1, 3]).should == [-2]
100
85
  end
101
86
 
102
87
  it "should do OP_GREATERTHANOREQUAL" do
103
- op(:greaterthanorequal, [1, 2]).should == [1]
88
+ op(:greaterthanorequal, [2, 1]).should == [1]
104
89
  op(:greaterthanorequal, [2, 2]).should == [1]
105
- op(:greaterthanorequal, [2, 1]).should == [0]
90
+ op(:greaterthanorequal, [1, 2]).should == [0]
106
91
  end
107
92
 
108
93
  it "should do OP_DROP" do
109
- @script.op_drop
110
- @script.stack.should == []
94
+ op(:drop, ["foo"]).should == []
111
95
  end
112
96
 
113
97
  it "should do OP_EQUAL" do
@@ -128,75 +112,340 @@ describe "Bitcoin::Script OPCODES" do
128
112
  end
129
113
 
130
114
  it "should do OP_0" do
131
- @script.op_0
132
- @script.stack.should == ["foobar", ""]
115
+ op("0", ["foo"]).should == ["foo", ""]
133
116
  end
134
117
 
135
118
  it "should do OP_1" do
136
- @script.op_1
137
- @script.stack.should == ["foobar", 1]
119
+ op("1", ["foo"]).should == ["foo", 1]
138
120
  end
139
121
 
140
122
  it "should do OP_MIN" do
141
123
  [
142
- [4, 5], [5, 4], [4, 4]
143
- ].each{|s|
144
- @script.instance_eval { @stack = s }
145
- @script.op_min
146
- @script.stack.should == [4]
124
+ [[4, 5], 4],
125
+ [[5, 4], 4],
126
+ [[4, 4], 4],
127
+ [["\x04", "\x05"], 4],
128
+
129
+ [[1, 0], 0],
130
+ [[0, 1], 0],
131
+ [[-1, 0], -1],
132
+ [[0, -2147483647], -2147483647],
133
+ ].each{|stack, expected|
134
+ op(:min, stack).should == [expected]
147
135
  }
148
136
  end
149
137
 
150
138
  it "should do OP_MAX" do
151
139
  [
152
- [4, 5], [5, 4], [5, 5]
153
- ].each{|s|
154
- @script.instance_eval { @stack = s }
155
- @script.op_max
156
- @script.stack.should == [5]
140
+ [[4, 5], 5],
141
+ [[5, 4], 5],
142
+ [[4, 4], 4],
143
+ [["\x04", "\x05"], 5],
144
+
145
+ [[2147483647, 0], 2147483647],
146
+ [[0, 100], 100],
147
+ [[-100, 0], 0],
148
+ [[0, -2147483647], 0],
149
+ ].each{|stack, expected|
150
+ op(:max, stack).should == [expected]
157
151
  }
158
152
  end
159
-
153
+
160
154
  it "should do op_2over" do
161
- @script.instance_eval { @stack = [1,2,3,4] }
162
- @script.op_2over
163
- @script.stack.should == [1,2,3,4,1,2]
155
+ op('2over', [1,2,3,4]).should == [1,2,3,4,1,2]
164
156
  end
165
-
157
+
166
158
  it "should do op_2swap" do
167
- @script.instance_eval { @stack = [1,2,3,4] }
168
- @script.op_2swap
169
- @script.stack.should == [3,4,1,2]
159
+ op("2swap", [1,2,3,4]).should == [3,4,1,2]
170
160
  end
171
-
161
+
172
162
  it "should do op_ifdup" do
173
- @script.instance_eval { @stack = [1] }
174
- @script.op_ifdup
175
- @script.stack.should == [1,1]
176
-
177
- @script.instance_eval { @stack = ['a'] }
178
- @script.op_ifdup
179
- @script.stack.should == ['a','a']
180
-
181
- @script.instance_eval { @stack = [0] }
182
- @script.op_ifdup
183
- @script.stack.should == [0]
163
+ op(:ifdup, [1]).should == [1,1]
164
+ op(:ifdup, ['a']).should == ['a','a']
165
+ op(:ifdup, [0]).should == [0]
184
166
  end
185
167
 
186
168
  it "should do op_1negate" do
187
- @script.instance_eval { @stack = [] }
188
- @script.op_1negate
189
- @script.stack.should == [ -1 ]
169
+ op("1negate", []).should == [ -1 ]
190
170
  end
191
-
171
+
192
172
  it "should do op_depth" do
193
- @script.instance_eval { @stack = [] }
194
- @script.op_depth
195
- @script.stack.should == [0]
196
-
197
- @script.instance_eval { @stack = [1,2,3] }
198
- @script.op_depth
199
- @script.stack.should == [1,2,3,3]
173
+ op(:depth, []).should == [0]
174
+ op(:depth, [1,2,3]).should == [1,2,3,3]
175
+ end
176
+
177
+ it "should do op_boolor" do
178
+ [
179
+ [[ 1, 1], 1],
180
+ [[ 1, 0], 1],
181
+ [[ 0, 1], 1],
182
+ [[ 0, 0], 0],
183
+ [[16, 17], 1],
184
+ [[-1, 0], 1],
185
+ #[[1 ], :invalid],
186
+ ].each{|stack, expected|
187
+ op(:boolor, stack).should == [ expected ]
188
+ }
189
+ end
190
+
191
+ it "should do op_lessthan" do
192
+ [
193
+ [[ 11, 10], 0],
194
+ [[ 4, 4], 0],
195
+ [[ 10, 11], 1],
196
+ [[-11, 11], 1],
197
+ [[-11,-10], 1],
198
+ [[ -1, 0], 1],
199
+ ].each{|stack, expected|
200
+ op(:lessthan, stack).should == [ expected ]
201
+ }
202
+ end
203
+
204
+ it "should do op_lessthanorequal" do
205
+ [
206
+ [[ 11, 10], 0],
207
+ [[ 4, 4], 1],
208
+ [[ 10, 11], 1],
209
+ [[-11, 11], 1],
210
+ [[-11,-10], 1],
211
+ [[ -1, 0], 1],
212
+ ].each{|stack, expected|
213
+ op(:lessthanorequal, stack).should == [ expected ]
214
+ }
215
+ end
216
+
217
+ it "should do op_greaterthan" do
218
+ [
219
+ [[ 11, 10], 1],
220
+ [[ 4, 4], 0],
221
+ [[ 10, 11], 0],
222
+ [[-11, 11], 0],
223
+ [[-11,-10], 0],
224
+ [[ -1, 0], 0],
225
+ [[ 1, 0], 1],
226
+ ].each{|stack, expected|
227
+ op(:greaterthan, stack).should == [expected]
228
+ }
229
+ end
230
+
231
+ it "should do op_greaterthanorequal" do
232
+ [
233
+ [[ 11, 10], 1],
234
+ [[ 4, 4], 1],
235
+ [[ 10, 11], 0],
236
+ [[-11, 11], 0],
237
+ [[-11,-10], 0],
238
+ [[ -1, 0], 0],
239
+ [[ 1, 0], 1],
240
+ [[ 0, 0], 1],
241
+ ].each{|stack, expected|
242
+ op(:greaterthanorequal, stack).should == [expected]
243
+ }
244
+ end
245
+
246
+ it "should do op_not" do
247
+ op(:not, [0]).should == [1]
248
+ op(:not, [1]).should == [0]
249
+ end
250
+
251
+ it "should do op_0notequal" do
252
+ [
253
+ [[0], 0],
254
+ [[1], 1],
255
+ [[111], 1],
256
+ [[-111], 1],
257
+ ].each{|stack, expected|
258
+ op("0notequal", stack).should == [expected]
259
+ }
260
+ end
261
+
262
+ it "should do op_abs" do
263
+ [
264
+ [[0], 0],
265
+ [[16], 16],
266
+ [[-16], 16],
267
+ [[-1], 1],
268
+ ].each{|stack, expected|
269
+ op(:abs, stack).should == [expected]
270
+ }
271
+ end
272
+
273
+ it "should do op_2div" do
274
+ op("2div", [ 2]).should == [ 1]
275
+ op("2div", [ 10]).should == [ 5]
276
+ op("2div", [-10]).should == [-5]
277
+ end
278
+
279
+ it "should do op_2mul" do
280
+ op("2mul", [ 2]).should == [ 4]
281
+ op("2mul", [ 10]).should == [ 20]
282
+ op("2mul", [-10]).should == [-20]
283
+ end
284
+
285
+ it "should do op_1add" do
286
+ op("1add", [ 2]).should == [ 3]
287
+ op("1add", [ 10]).should == [11]
288
+ op("1add", [-10]).should == [-9]
289
+ end
290
+
291
+ it "should do op_1sub" do
292
+ op("1sub", [ 2]).should == [ 1]
293
+ op("1sub", [ 10]).should == [ 9]
294
+ op("1sub", [-10]).should == [-11]
295
+ end
296
+
297
+ it "should do op_negate" do
298
+ op("negate", [-2]).should == [ 2]
299
+ op("negate", [ 2]).should == [-2]
300
+ op("negate", [ 0]).should == [ 0]
301
+ end
302
+
303
+ it "should do op_within" do
304
+ [
305
+ [[0, 0, 1], 1],
306
+ [[1, 0, 1], 0],
307
+ [[0, -2147483647, 2147483647], 1],
308
+ [[-1, -100, 100], 1],
309
+ [[11, -100, 100], 1],
310
+ [[-2147483647, -100, 100], 0],
311
+ [[2147483647, -100, 100], 0],
312
+ [[-1, -1, 0], 1],
313
+ ].each{|stack, expected|
314
+ op(:within, stack).should == [expected]
315
+ }
316
+ end
317
+
318
+ it "should do op_numequal" do
319
+ [
320
+ [[0, 0], 1],
321
+ [[0, 1], 0],
322
+ ].each{|stack, expected|
323
+ op(:numequal, stack).should == [expected]
324
+ }
325
+ end
326
+
327
+ it "should do op_numequalverify" do
328
+ [
329
+ [[0, 0], []],
330
+ [[0, 1], [0]],
331
+ ].each{|stack, expected|
332
+ op(:numequalverify, stack).should == expected
333
+ }
334
+ end
335
+
336
+ it "should do op_numnotequal" do
337
+ [
338
+ [[0, 0], 0],
339
+ [[0, 1], 1],
340
+ ].each{|stack, expected|
341
+ op(:numnotequal, stack).should == [expected]
342
+ }
343
+ end
344
+
345
+ it "should do op_over" do
346
+ [
347
+ [[1, 0], [1,0,1]],
348
+ [[-1, 1], [-1,1,-1]],
349
+ [[1], [1]],
350
+ ].each{|stack, expected|
351
+ op(:over, stack).should == expected
352
+ }
353
+ end
354
+
355
+ it "should do op_pick" do
356
+ [
357
+ [[1, 0, 0, 0, 3], [1,0,0,0,1]],
358
+ [[1, 0], [1,1]],
359
+ ].each{|stack, expected|
360
+ op(:pick, stack).should == expected
361
+ }
362
+ end
363
+
364
+ it "should do op_roll" do
365
+ [
366
+ [[1, 0, 0, 0, 3], [0,0,0,1]],
367
+ [[1, 0], [1]],
368
+ ].each{|stack, expected|
369
+ op(:roll, stack).should == expected
370
+ }
371
+ end
372
+
373
+ it "should do op_rot" do
374
+ op(:rot, [22, 21, 20]).should == [21, 20, 22]
375
+ op(:rot, [21, 20]).should == [21, 20]
376
+ end
377
+
378
+ it "should do op_2drop" do
379
+ op('2drop', [1,2,3]).should == [1]
380
+ op('2drop', [ 2,3]).should == [ ]
381
+ end
382
+
383
+ it "should do op_2dup" do
384
+ op('2dup', [2,3]).should == [2,3,2,3]
385
+ op('2dup', [3 ]).should == [ 3 ]
386
+ end
387
+
388
+ it "should do op_3dup" do
389
+ op('3dup', [1,2,3]).should == [1,2,3,1,2,3]
390
+ op('3dup', [ 2,3]).should == [ 2,3 ]
391
+ op('3dup', [ 3]).should == [ 3 ]
392
+ end
393
+
394
+ it "should do op_nip" do
395
+ op(:nip, [1,2]).should == [2]
396
+ op(:nip, [1,2,3]).should == [1,3]
397
+ end
398
+
399
+ it "should do op_size" do
400
+ [
401
+ [[0], [0,0]],
402
+ [[1], [1,1]],
403
+ [[127], [127,1]],
404
+ [[128], [128,2]],
405
+ [[32767], [32767,2]],
406
+ [[32768], [32768,3]],
407
+ [[8388607], [8388607,3]],
408
+ [[8388608], [8388608,4]],
409
+ [[2147483647], [2147483647,4]],
410
+ [[2147483648], [2147483648,5]],
411
+ [[-1], [-1,1]],
412
+ [[-127], [-127,1]],
413
+ [[-128], [-128,2]],
414
+ [[-32767], [-32767,2]],
415
+ [[-32768], [-32768,3]],
416
+ [[-8388607], [-8388607,3]],
417
+ [[-8388608], [-8388608,4]],
418
+ [[-2147483647], [-2147483647,4]],
419
+ [[-2147483648], [-2147483648,5]],
420
+ [["abcdefghijklmnopqrstuvwxyz"], ["abcdefghijklmnopqrstuvwxyz",26]],
421
+ ].each{|stack, expected|
422
+ op(:size, stack).should == expected
423
+ }
424
+ end
425
+
426
+ it "should do if/notif/else/end" do
427
+ [
428
+ "1 1 OP_IF OP_IF 1 OP_ELSE 0 OP_ENDIF OP_ENDIF",
429
+ "1 0 OP_IF OP_IF 1 OP_ELSE 0 OP_ENDIF OP_ENDIF",
430
+ "1 1 OP_IF OP_IF 1 OP_ELSE 0 OP_ENDIF OP_ELSE OP_IF 0 OP_ELSE 1 OP_ENDIF OP_ENDIF",
431
+ "0 0 OP_IF OP_IF 1 OP_ELSE 0 OP_ENDIF OP_ELSE OP_IF 0 OP_ELSE 1 OP_ENDIF OP_ENDIF",
432
+ "1 1 OP_NOTIF OP_IF 1 OP_ELSE 0 OP_ENDIF OP_ENDIF",
433
+ "1 0 OP_NOTIF OP_IF 1 OP_ELSE 0 OP_ENDIF OP_ENDIF",
434
+ "1 0 OP_NOTIF OP_IF 1 OP_ELSE 0 OP_ENDIF OP_ELSE OP_IF 0 OP_ELSE 1 OP_ENDIF OP_ENDIF",
435
+ "0 1 OP_NOTIF OP_IF 1 OP_ELSE 0 OP_ENDIF OP_ELSE OP_IF 0 OP_ELSE 1 OP_ENDIF OP_ENDIF",
436
+ "0 OP_IF OP_RETURN OP_ENDIF 1",
437
+ "1 OP_IF 1 OP_ENDIF",
438
+ "0 OP_IF 50 OP_ENDIF 1",
439
+ "0 OP_IF OP_VER OP_ELSE 1 OP_ENDIF",
440
+ "0 OP_IF 50 40 OP_ELSE 1 OP_ENDIF",
441
+ "1 OP_DUP OP_IF OP_ENDIF",
442
+ "1 OP_IF 1 OP_ENDIF",
443
+ "1 OP_DUP OP_IF OP_ELSE OP_ENDIF",
444
+ "1 OP_IF 1 OP_ELSE OP_ENDIF",
445
+ "0 OP_IF OP_ELSE 1 OP_ENDIF",
446
+ ].each{|script|
447
+ Bitcoin::Script.from_string(script).run.should == true
448
+ }
200
449
  end
201
450
 
202
451
  it "should do OP_CHECKSIG" do
@@ -287,6 +536,9 @@ describe "Bitcoin::Script OPCODES" do
287
536
  sig2 = (k2.sign("foobar") + "\x01").unpack("H*")[0]
288
537
  sig3 = (k3.sign("foobar") + "\x01").unpack("H*")[0]
289
538
 
539
+ script = "0 #{sig1} 1 #{k1.pub} 1 OP_CHECKMULTISIG"
540
+ run_script(script, "foobar").should == true
541
+
290
542
  script = "0 #{sig1} #{sig2} 2 #{k1.pub} #{k2.pub} 2 OP_CHECKMULTISIG"
291
543
  run_script(script, "foobar").should == true
292
544
 
@@ -335,6 +587,15 @@ describe "Bitcoin::Script OPCODES" do
335
587
  script = "0 #{sig1} f0f0f0f0 #{sig3} 3 #{k1.pub} #{k2.pub} #{k3.pub} 3 OP_CHECKMULTISIG"
336
588
  run_script(script, "foobar").should == false
337
589
 
590
+ # mainnet tx output: 514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58
591
+ script = "0 #{sig1} 1 0 #{k1.pub} OP_SWAP OP_1ADD OP_CHECKMULTISIG"
592
+ run_script(script, "foobar").should == true
593
+ Bitcoin::Script.from_string(script).get_addresses.should == []
594
+ Bitcoin::Script.from_string(script).is_multisig?.should == false
595
+ script = "#{k1.pub} OP_SWAP OP_1ADD OP_CHECKMULTISIG"
596
+ Bitcoin::Script.from_string(script).get_addresses.should == []
597
+ Bitcoin::Script.from_string(script).is_multisig?.should == false
598
+
338
599
  # # TODO: check signature order; these assertions should fail:
339
600
  # script = "0 #{sig2} #{sig1} 2 #{k1.pub} #{k2.pub} #{k3.pub} 3 OP_CHECKMULTISIG"
340
601
  # run_script(script, "foobar").should == false
@@ -344,57 +605,6 @@ describe "Bitcoin::Script OPCODES" do
344
605
  # run_script(script, "foobar").should == false
345
606
  end
346
607
 
347
-
348
- it "should do OP_CHECKHASHVERIFY" do # https://en.bitcoin.it/wiki/BIP_0017
349
- k1 = Bitcoin::Key.new; k1.generate
350
- k2 = Bitcoin::Key.new; k2.generate
351
- k3 = Bitcoin::Key.new; k2.generate
352
- sig1 = (k1.sign("foobar") + "\x01").unpack("H*")[0]
353
- sig2 = (k2.sign("foobar") + "\x01").unpack("H*")[0]
354
- sig3 = (k2.sign("foobar") + "\x01").unpack("H*")[0]
355
-
356
-
357
- # scriptSig: [signatures...] OP_CODESEPARATOR 1 [pubkey1] [pubkey2] 2 OP_CHECKMULTISIG
358
- # scriptPubKey: [20-byte-hash of {1 [pubkey1] [pubkey2] 2 OP_CHECKMULTISIG} ] OP_CHECKHASHVERIFY OP_DROP
359
- script = "1 #{k1.pub} #{k2.pub} 2 OP_CHECKMULTISIG"
360
- checkhash = Bitcoin.hash160(Bitcoin::Script.binary_from_string(script).unpack("H*")[0])
361
- script = "0 #{sig1} OP_CODESEPARATOR #{script} #{checkhash} OP_CHECKHASHVERIFY OP_DROP"
362
- run_script(script, "foobar").should == true
363
-
364
- script = "1 #{k1.pub} #{k2.pub} 2 OP_CHECKMULTISIG"
365
- checkhash = Bitcoin.hash160(Bitcoin::Script.binary_from_string(script).unpack("H*")[0])
366
- script = "0 #{sig1} OP_CODESEPARATOR #{script} #{checkhash} OP_NOP2 OP_DROP" # tests OP_NOP2 as OP_CHECKHASHVERIFY
367
- run_script(script, "foobar").should == true
368
-
369
- # invalid checkhashverify
370
- script = "1 #{k1.pub} #{k2.pub} 2 OP_CHECKMULTISIG"
371
- checkhash = Bitcoin.hash160(Bitcoin::Script.binary_from_string(script).unpack("H*")[0])
372
- script = "1 #{k1.pub} #{k3.pub} 2 OP_CHECKMULTISIG"
373
- script = "0 #{sig1} OP_CODESEPARATOR #{script} #{checkhash} OP_NOP2 OP_DROP" # tests OP_NOP2 as OP_CHECKHASHVERIFY
374
- run_script(script, "foobar").should == false
375
-
376
-
377
- # scriptSig: [signature] OP_CODESEPARATOR [pubkey] OP_CHECKSIG
378
- # scriptPubKey: [20-byte-hash of {[pubkey] OP_CHECKSIG} ] OP_CHECKHASHVERIFY OP_DROP
379
- script = "#{k1.pub} OP_CHECKSIG"
380
- checkhash = Bitcoin.hash160(Bitcoin::Script.binary_from_string(script).unpack("H*")[0])
381
- script = "#{sig1} OP_CODESEPARATOR #{script} #{checkhash} OP_CHECKHASHVERIFY OP_DROP"
382
- run_script(script, "foobar").should == true
383
-
384
- # invalid checkhashverify
385
- script = "#{k2.pub} OP_CHECKSIG"
386
- checkhash = Bitcoin.hash160(Bitcoin::Script.binary_from_string(script).unpack("H*")[0])
387
- script = "#{k1.pub} OP_CHECKSIG"
388
- script = "#{sig1} OP_CODESEPARATOR #{script} #{checkhash} OP_CHECKHASHVERIFY OP_DROP"
389
- run_script(script, "foobar").should == false
390
-
391
- # invalid signature in checksig
392
- script = "#{k1.pub} OP_CHECKSIG"
393
- checkhash = Bitcoin.hash160(Bitcoin::Script.binary_from_string(script).unpack("H*")[0])
394
- script = "#{sig2} OP_CODESEPARATOR #{script} #{checkhash} OP_CHECKHASHVERIFY OP_DROP"
395
- run_script(script, "foobar").should == false
396
- end
397
-
398
608
  it "should do P2SH" do
399
609
  k1 = Bitcoin::Key.new; k1.generate
400
610
  sig = (k1.sign("foobar") + "\x01").unpack("H*")[0]
@@ -405,6 +615,10 @@ describe "Bitcoin::Script OPCODES" do
405
615
  run_script(script.to_string, "foobar").should == true
406
616
  run_script(script.to_string, "barbaz").should == false
407
617
 
618
+ script = Bitcoin::Script.from_string("0 #{sig} #{inner_script} OP_HASH160 #{script_hash} OP_EQUAL")
619
+ script.is_p2sh?.should == true
620
+ run_script(script.to_string, "foobar").should == true
621
+
408
622
  script = Bitcoin::Script.from_string("OP_HASH160 #{script_hash} OP_EQUAL")
409
623
  script.is_p2sh?.should == true
410
624
  run_script(script.to_string, "foobar").should == false
@@ -414,4 +628,69 @@ describe "Bitcoin::Script OPCODES" do
414
628
  script.type.should == :p2sh
415
629
  end
416
630
 
631
+ it "should skip OP_EVAL" do
632
+ Bitcoin::Script.from_string("1 OP_EVAL").to_string.should == "1 OP_NOP1"
633
+ Bitcoin::Script.from_string("1 OP_EVAL").run.should == true
634
+ Bitcoin::Script.from_string("0 OP_EVAL").run.should == false
635
+ end
636
+
637
+ it "should do testnet3 scripts" do
638
+ [
639
+ "OP_1NEGATE OP_1NEGATE OP_ADD 82 OP_EQUAL",
640
+ "6f 1 OP_ADD 12 OP_SUB 64 OP_EQUAL",
641
+ "76:1:07 7 OP_EQUAL",
642
+ "OP_1NEGATE e4 64 OP_WITHIN",
643
+ "0 ffffffff ffffff7f OP_WITHIN",
644
+ "6162636465666768696a6b6c6d6e6f707172737475767778797a OP_SIZE 1a OP_EQUAL",
645
+ "0 OP_IFDUP OP_DEPTH 1 OP_EQUALVERIFY 0 OP_EQUAL",
646
+ "1 OP_NOP1 OP_CHECKHASHVERIFY OP_NOP3 OP_NOP4 OP_NOP5 OP_NOP6 OP_NOP7 OP_NOP8 OP_NOP9 OP_NOP10 1 OP_EQUAL",
647
+ "1 OP_NOP1 OP_NOP2 OP_NOP3 OP_NOP4 OP_NOP5 OP_NOP6 OP_NOP7 OP_NOP8 OP_NOP9 OP_NOP10 1 OP_EQUAL",
648
+ "0 ffffffff ffffff7f OP_WITHIN",
649
+ "0:1:16 0:1:15 0:1:14 OP_ROT OP_ROT 0:1:15 OP_EQUAL",
650
+ "ffffff7f OP_NEGATE OP_DUP OP_ADD feffffff80 OP_EQUAL",
651
+ "90 OP_ABS 90 OP_NEGATE OP_EQUAL",
652
+ "0 OP_DROP OP_DEPTH 0 OP_EQUAL",
653
+ "1 0 OP_NOTIF OP_IF 1 OP_ELSE 0 OP_ENDIF OP_ELSE OP_IF 0 OP_ELSE 1 OP_ENDIF OP_ENDIF",
654
+ "6f OP_1SUB 6e OP_EQUAL",
655
+ "13 14 OP_2DUP OP_ROT OP_EQUALVERIFY OP_EQUAL",
656
+ "10 0 11 OP_TOALTSTACK OP_DROP OP_FROMALTSTACK OP_ADD 0:1:15 OP_EQUAL",
657
+ "ffffff7f OP_DUP OP_ADD feffffff00 OP_EQUAL",
658
+ "77:1:08 8 OP_EQUAL",
659
+ "1 OP_NOT 0 OP_EQUAL",
660
+ "0 OP_DROP OP_DEPTH 0 OP_EQUAL",
661
+ "6f 1 OP_ADD 12 OP_SUB 64 OP_EQUAL",
662
+ "0:1:0b 11 OP_EQUAL",
663
+ "13 14 OP_2DUP OP_ROT OP_EQUALVERIFY OP_EQUAL",
664
+ "ffffff7f OP_DUP OP_ADD feffffff00 OP_EQUAL",
665
+ "0 OP_DROP OP_DEPTH 0 OP_EQUAL",
666
+ "0 ffffffff OP_MIN ffffffff OP_NUMEQUAL",
667
+ "90 OP_ABS 90 OP_NEGATE OP_EQUAL",
668
+ "OP_1NEGATE e803 OP_ADD e703 OP_EQUAL",
669
+ "0:1:16 0:1:15 0:1:14 OP_ROT OP_ROT OP_ROT 0:1:14 OP_EQUAL",
670
+ "13 14 OP_2DUP OP_ROT OP_EQUALVERIFY OP_EQUAL",
671
+ "8b 11 OP_LESSTHANOREQUAL",
672
+ "ffffff7f ffffffff OP_ADD 0 OP_EQUAL",
673
+ "ffffff7f OP_NEGATE OP_DUP OP_ADD feffffff80 OP_EQUAL",
674
+ "8b 11 OP_GREATERTHANOREQUAL OP_NOT",
675
+ "0 OP_0NOTEQUAL 0 OP_EQUAL",
676
+ "2 82 OP_ADD 0 OP_EQUAL",
677
+ ].each{|script|
678
+ Bitcoin::Script.from_string(script).run.should == true
679
+ }
680
+ end
681
+
682
+ it "should do OP_VER" do
683
+ s = Bitcoin::Script.from_string("OP_VER"); s.run; s.invalid?.should == true
684
+ s = Bitcoin::Script.from_string("1 OP_IF OP_VER 1 OP_ELSE 0 OP_ENDIF"); s.run.should == false; s.invalid?.should == true
685
+ s = Bitcoin::Script.from_string("1 OP_IF 1 OP_ELSE OP_VER 0 OP_ENDIF"); s.run.should == true; s.invalid?.should == false
686
+ end
687
+
688
+ it "should not allow DISABLED_OPCODES" do
689
+ Bitcoin::Script::DISABLED_OPCODES.each{|opcode|
690
+ s = Bitcoin::Script.from_string(Bitcoin::Script::OPCODES[opcode] + " 1"); s.run.should == false; s.invalid?.should == true
691
+ s = Bitcoin::Script.from_string("1 OP_IF #{Bitcoin::Script::OPCODES[opcode]} 1 OP_ELSE 1 OP_ENDIF"); s.run.should == false; s.invalid?.should == true
692
+ s = Bitcoin::Script.from_string("1 OP_IF 1 OP_ELSE #{Bitcoin::Script::OPCODES[opcode]} 1 OP_ENDIF"); s.run.should == false; s.invalid?.should == true
693
+ }
694
+ end
695
+
417
696
  end