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 (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