bitcoin-ruby 0.0.6 → 0.0.7

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +2 -7
  4. data/COPYING +1 -1
  5. data/Gemfile +2 -6
  6. data/Gemfile.lock +34 -0
  7. data/README.rdoc +16 -68
  8. data/Rakefile +3 -6
  9. data/bin/bitcoin_shell +0 -1
  10. data/{concept-examples/blockchain-pow.rb → examples/concept-blockchain-pow.rb} +0 -0
  11. data/lib/bitcoin.rb +350 -296
  12. data/lib/bitcoin/builder.rb +3 -1
  13. data/lib/bitcoin/connection.rb +2 -1
  14. data/lib/bitcoin/contracthash.rb +76 -0
  15. data/lib/bitcoin/dogecoin.rb +97 -0
  16. data/lib/bitcoin/ffi/bitcoinconsensus.rb +74 -0
  17. data/lib/bitcoin/ffi/openssl.rb +98 -2
  18. data/lib/bitcoin/ffi/secp256k1.rb +144 -0
  19. data/lib/bitcoin/key.rb +12 -2
  20. data/lib/bitcoin/logger.rb +3 -12
  21. data/lib/bitcoin/protocol/block.rb +3 -9
  22. data/lib/bitcoin/protocol/parser.rb +6 -2
  23. data/lib/bitcoin/protocol/tx.rb +44 -13
  24. data/lib/bitcoin/protocol/txin.rb +4 -2
  25. data/lib/bitcoin/protocol/txout.rb +2 -2
  26. data/lib/bitcoin/script.rb +212 -37
  27. data/lib/bitcoin/trezor/mnemonic.rb +130 -0
  28. data/lib/bitcoin/version.rb +1 -1
  29. data/spec/bitcoin/bitcoin_spec.rb +32 -3
  30. data/spec/bitcoin/builder_spec.rb +18 -0
  31. data/spec/bitcoin/contracthash_spec.rb +45 -0
  32. data/spec/bitcoin/dogecoin_spec.rb +176 -0
  33. data/spec/bitcoin/ffi_openssl.rb +45 -0
  34. data/spec/bitcoin/fixtures/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +24 -0
  35. data/spec/bitcoin/fixtures/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +24 -0
  36. data/spec/bitcoin/fixtures/coinbase-toshi.json +33 -0
  37. data/spec/bitcoin/fixtures/coinbase.json +24 -0
  38. data/spec/bitcoin/fixtures/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
  39. data/spec/bitcoin/fixtures/rawtx-01-toshi.json +46 -0
  40. data/spec/bitcoin/fixtures/rawtx-02-toshi.json +46 -0
  41. data/spec/bitcoin/fixtures/rawtx-03-toshi.json +73 -0
  42. data/spec/bitcoin/fixtures/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
  43. data/spec/bitcoin/fixtures/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
  44. data/spec/bitcoin/fixtures/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
  45. data/spec/bitcoin/fixtures/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
  46. data/spec/bitcoin/fixtures/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
  47. data/spec/bitcoin/fixtures/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
  48. data/spec/bitcoin/protocol/block_spec.rb +0 -22
  49. data/spec/bitcoin/protocol/tx_spec.rb +145 -2
  50. data/spec/bitcoin/script/script_spec.rb +282 -0
  51. data/spec/bitcoin/secp256k1_spec.rb +48 -0
  52. data/spec/bitcoin/spec_helper.rb +0 -51
  53. data/spec/bitcoin/trezor/mnemonic_spec.rb +161 -0
  54. metadata +48 -98
  55. data/bin/bitcoin_dns_seed +0 -130
  56. data/bin/bitcoin_gui +0 -80
  57. data/bin/bitcoin_node +0 -153
  58. data/bin/bitcoin_node_cli +0 -81
  59. data/bin/bitcoin_wallet +0 -402
  60. data/doc/CONFIG.rdoc +0 -66
  61. data/doc/EXAMPLES.rdoc +0 -13
  62. data/doc/NAMECOIN.rdoc +0 -34
  63. data/doc/NODE.rdoc +0 -225
  64. data/doc/STORAGE.rdoc +0 -33
  65. data/doc/WALLET.rdoc +0 -102
  66. data/examples/balance.rb +0 -66
  67. data/examples/forwarder.rb +0 -73
  68. data/examples/index_nhash.rb +0 -24
  69. data/examples/reindex_p2sh_addrs.rb +0 -44
  70. data/examples/relay_tx.rb +0 -22
  71. data/examples/verify_tx.rb +0 -57
  72. data/lib/bitcoin/config.rb +0 -58
  73. data/lib/bitcoin/gui/addr_view.rb +0 -44
  74. data/lib/bitcoin/gui/bitcoin-ruby.png +0 -0
  75. data/lib/bitcoin/gui/bitcoin-ruby.svg +0 -80
  76. data/lib/bitcoin/gui/conn_view.rb +0 -38
  77. data/lib/bitcoin/gui/connection.rb +0 -70
  78. data/lib/bitcoin/gui/em_gtk.rb +0 -30
  79. data/lib/bitcoin/gui/gui.builder +0 -1643
  80. data/lib/bitcoin/gui/gui.rb +0 -292
  81. data/lib/bitcoin/gui/helpers.rb +0 -115
  82. data/lib/bitcoin/gui/tree_view.rb +0 -84
  83. data/lib/bitcoin/gui/tx_view.rb +0 -69
  84. data/lib/bitcoin/namecoin.rb +0 -280
  85. data/lib/bitcoin/network/command_client.rb +0 -104
  86. data/lib/bitcoin/network/command_handler.rb +0 -570
  87. data/lib/bitcoin/network/connection_handler.rb +0 -387
  88. data/lib/bitcoin/network/node.rb +0 -565
  89. data/lib/bitcoin/storage/dummy/dummy_store.rb +0 -179
  90. data/lib/bitcoin/storage/models.rb +0 -171
  91. data/lib/bitcoin/storage/sequel/migrations.rb +0 -99
  92. data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +0 -52
  93. data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +0 -45
  94. data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +0 -18
  95. data/lib/bitcoin/storage/sequel/migrations/004_change_txin_prev_out_to_blob.rb +0 -18
  96. data/lib/bitcoin/storage/sequel/migrations/005_change_tx_hash_to_bytea.rb +0 -14
  97. data/lib/bitcoin/storage/sequel/migrations/006_add_tx_nhash.rb +0 -31
  98. data/lib/bitcoin/storage/sequel/migrations/007_add_prev_out_index_index.rb +0 -16
  99. data/lib/bitcoin/storage/sequel/migrations/008_add_txin_p2sh_type.rb +0 -31
  100. data/lib/bitcoin/storage/sequel/migrations/009_add_addrs_type.rb +0 -56
  101. data/lib/bitcoin/storage/sequel/sequel_store.rb +0 -551
  102. data/lib/bitcoin/storage/storage.rb +0 -517
  103. data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +0 -52
  104. data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +0 -18
  105. data/lib/bitcoin/storage/utxo/migrations/003_update_indices.rb +0 -14
  106. data/lib/bitcoin/storage/utxo/migrations/004_add_addrs_type.rb +0 -14
  107. data/lib/bitcoin/storage/utxo/utxo_store.rb +0 -374
  108. data/lib/bitcoin/validation.rb +0 -400
  109. data/lib/bitcoin/wallet/coinselector.rb +0 -33
  110. data/lib/bitcoin/wallet/keygenerator.rb +0 -77
  111. data/lib/bitcoin/wallet/keystore.rb +0 -207
  112. data/lib/bitcoin/wallet/txdp.rb +0 -118
  113. data/lib/bitcoin/wallet/wallet.rb +0 -281
  114. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
  115. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +0 -43
  116. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
  117. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +0 -67
  118. data/spec/bitcoin/namecoin_spec.rb +0 -182
  119. data/spec/bitcoin/node/command_api_spec.rb +0 -663
  120. data/spec/bitcoin/storage/models_spec.rb +0 -104
  121. data/spec/bitcoin/storage/reorg_spec.rb +0 -236
  122. data/spec/bitcoin/storage/storage_spec.rb +0 -387
  123. data/spec/bitcoin/storage/validation_spec.rb +0 -300
  124. data/spec/bitcoin/wallet/coinselector_spec.rb +0 -38
  125. data/spec/bitcoin/wallet/keygenerator_spec.rb +0 -69
  126. data/spec/bitcoin/wallet/keystore_spec.rb +0 -190
  127. data/spec/bitcoin/wallet/txdp_spec.rb +0 -76
  128. data/spec/bitcoin/wallet/wallet_spec.rb +0 -238
@@ -1,400 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- # Validates blocks and transactions before they are accepted into the local blockchain.
4
- # There are two modes of validation, "syntax" and "context". "syntax" validates everything
5
- # that can be validated without access to the rest of the blockchain, for example that the
6
- # block hash matches the claimed difficulty, and the tx hashes add up to the given merkle
7
- # root, etc. The "context" rules include the checks that need to cross-reference data
8
- # against the local database, like comparing the difficulty target to the last blocks, or
9
- # checking for doublespends. (Suggestions for better names for these modes are welcome!)
10
- # Everything accepted into the local storage should at least be syntax-validated, but it
11
- # should be possible to skip context-validation when the current block is already known,
12
- # for example when checkpoints are used.
13
- module Bitcoin::Validation
14
-
15
- class ValidationError < StandardError
16
- end
17
-
18
-
19
- class Block
20
- attr_accessor :block, :store, :prev_block, :error
21
-
22
- RULES = {
23
- syntax: [:hash, :tx_list, :bits, :max_timestamp, :coinbase, :coinbase_scriptsig, :mrkl_root, :transactions_syntax],
24
- context: [:prev_hash, :difficulty, :coinbase_value, :min_timestamp, :transactions_context]
25
- }
26
-
27
- # TODO merged mining validations
28
- if Bitcoin.namecoin?
29
- RULES[:syntax] -= [:bits, :coinbase, :coinbase_scriptsig, :mrkl_root]
30
- RULES[:context] -= [:difficulty, :coinbase_value]
31
- end
32
-
33
- if Bitcoin.litecoin?
34
- RULES[:syntax] -= [:bits]
35
- RULES[:syntax] += [:scrypt_bits]
36
- end
37
-
38
- # validate block rules. +opts+ are:
39
- # rules:: which rulesets to validate (default: [:syntax, :context])
40
- # raise_errors:: whether to raise ValidationError on failure (default: false)
41
- def validate(opts = {})
42
- return true if KNOWN_EXCEPTIONS.include?(block.hash)
43
- opts[:rules] ||= [:syntax, :context]
44
- opts[:rules].each do |name|
45
- store.log.debug { "validating block #{name} #{block.hash} (#{block.to_payload.bytesize} bytes)" }
46
- RULES[name].each.with_index do |rule, i|
47
- unless (res = send(rule)) && res == true
48
- raise ValidationError, "block error: #{name} check #{i} - #{rule} failed" if opts[:raise_errors]
49
- @error = [rule, res]
50
- return false
51
- end
52
- end
53
- end
54
- true
55
- end
56
-
57
- # setup new validator for given +block+, validating context with +store+,
58
- # optionally passing the +prev_block+ for optimization.
59
- def initialize block, store, prev_block = nil
60
- @block, @store, @error = block, store, nil
61
- @prev_block = prev_block || store.get_block(block.prev_block.reverse_hth)
62
- end
63
-
64
- # check that block hash matches header
65
- def hash
66
- claimed = block.hash; real = block.recalc_block_hash
67
- claimed == real || [claimed, real]
68
- end
69
-
70
- # check that block has at least one tx (the coinbase)
71
- def tx_list
72
- block.tx.any? || block.tx.size
73
- end
74
-
75
- # check that block hash matches claimed bits
76
- def bits
77
- actual = block.hash.to_i(16)
78
- expected = Bitcoin.decode_compact_bits(block.bits).to_i(16)
79
- actual <= expected || [actual, expected]
80
- end
81
-
82
- # check that block hash matches claimed bits using Scrypt hash
83
- def scrypt_bits
84
- actual = block.recalc_block_scrypt_hash.to_i(16)
85
- expected = Bitcoin.decode_compact_bits(block.bits).to_i(16)
86
- actual <= expected || [actual, expected]
87
- end
88
-
89
- # check that block time is not greater than max
90
- def max_timestamp
91
- time, max = block.time, Time.now.to_i + 2*60*60
92
- time < max || [time, max]
93
- end
94
-
95
- # check that coinbase is present
96
- def coinbase
97
- coinbase, *rest = block.tx.map{|t| t.inputs.size == 1 && t.inputs.first.coinbase? }
98
- (coinbase && rest.none?) || [coinbase ? 1 : 0, rest.select{|r| r}.size]
99
- end
100
-
101
- # check that coinbase scriptsig is valid
102
- def coinbase_scriptsig
103
- size = block.tx.first.in.first.script_sig.bytesize
104
- size.between?(2,100) || [size, 2, 100]
105
- end
106
-
107
- # check that coinbase value is valid; no more than reward + fees
108
- def coinbase_value
109
- reward = ((50.0 / (2 ** (store.get_depth / Bitcoin::REWARD_DROP.to_f).floor)) * 1e8).to_i
110
- fees = 0
111
- block.tx[1..-1].map.with_index do |t, idx|
112
- val = tx_validators[idx]
113
- fees += t.in.map.with_index {|i, idx|
114
- val.prev_txs[idx].out[i.prev_out_index].value rescue 0
115
- }.inject(:+)
116
- val.clear_cache # memory optimization on large coinbases, see testnet3 block 4110
117
- end
118
- coinbase_output = block.tx[0].out.map(&:value).inject(:+)
119
- coinbase_output <= reward + fees || [coinbase_output, reward, fees]
120
- end
121
-
122
- # check that merkle root matches transaction hashes
123
- def mrkl_root
124
- actual, expected = block.mrkl_root.reverse_hth, Bitcoin.hash_mrkl_tree(block.tx.map(&:hash))[-1]
125
- actual == expected || [actual, expected]
126
- end
127
-
128
- def prev_hash
129
- @prev_block && @prev_block.hash == block.prev_block.reverse_hth
130
- end
131
-
132
- # check that bits satisfy required difficulty
133
- def difficulty
134
- return true if Bitcoin.network[:no_difficulty] == true
135
- block.bits == next_bits_required || [block.bits, next_bits_required]
136
- end
137
-
138
- # check that timestamp is newer than the median of the last 11 blocks
139
- def min_timestamp
140
- return true if store.get_depth <= 11
141
- d = store.get_depth
142
- first = store.db[:blk][hash: block.prev_block.reverse.blob]
143
- times = [first[:time]]
144
- (10).times { first = store.db[:blk][hash: first[:prev_hash].blob]
145
- times << first[:time] }
146
- times.sort!
147
- mid, rem = times.size.divmod(2)
148
- min_time = (rem == 0 ? times[mid-1, 2].inject(:+) / 2.0 : times[mid])
149
-
150
- block.time > min_time || [block.time, min_time]
151
- end
152
-
153
- # Run all syntax checks on transactions
154
- def transactions_syntax
155
- # check if there are no double spends within this block
156
- return false if block.tx.map(&:in).flatten.map {|i| [i.prev_out, i.prev_out_index] }.uniq! != nil
157
-
158
- tx_validators.all?{|v|
159
- begin
160
- v.validate(rules: [:syntax], raise_errors: true)
161
- rescue ValidationError
162
- store.log.info { $!.message }
163
- return false
164
- end
165
- }
166
- end
167
-
168
- # Run all context checks on transactions
169
- def transactions_context
170
- tx_validators.all?{|v|
171
- begin
172
- v.validate(rules: [:context], raise_errors: true)
173
- rescue ValidationError
174
- store.log.info { $!.message }
175
- return false
176
- end
177
- }
178
- end
179
-
180
- # Get validators for all tx objects in the current block
181
- def tx_validators
182
- @tx_validators ||= block.tx[1..-1].map {|tx| tx.validator(store, block, self)}
183
- end
184
-
185
- # Fetch all prev_txs that will be needed for validation
186
- # Used for optimization in tx validators
187
- def prev_txs_hash
188
- @prev_tx_hash ||= (
189
- inputs = block.tx[1..-1].map {|tx| tx.in }.flatten
190
- txs = store.get_txs(inputs.map{|i| i.prev_out.reverse_hth })
191
- Hash[*txs.map {|tx| [tx.hash, tx] }.flatten]
192
- )
193
- end
194
-
195
- # Fetch all prev_outs that already have a next_in, i.e. are already spent.
196
- def spent_outs_txins
197
- @spent_outs_txins ||= (
198
- next_ins = store.get_txins_for_txouts(block.tx[1..-1].map(&:in).flatten.map.with_index {|txin, idx| [txin.prev_out.reverse_hth, txin.prev_out_index] })
199
- # Only returns next_ins that are in blocks in the main chain
200
- next_ins.select {|i| store.get_block_id_for_tx_id(i.tx_id) }
201
- )
202
- end
203
-
204
- def next_bits_required
205
- retarget = (Bitcoin.network[:retarget_interval] || Bitcoin::RETARGET_INTERVAL)
206
- index = (prev_block.depth + 1) / retarget
207
- max_target = Bitcoin.decode_compact_bits(Bitcoin.network[:proof_of_work_limit]).to_i(16)
208
- return Bitcoin.network[:proof_of_work_limit] if index == 0
209
- return prev_block.bits if (prev_block.depth + 1) % retarget != 0
210
- last = store.db[:blk][hash: prev_block.hash.htb.blob]
211
- first = store.db[:blk][hash: last[:prev_hash].blob]
212
- (retarget - 2).times { first = store.db[:blk][hash: first[:prev_hash].blob] }
213
-
214
- nActualTimespan = last[:time] - first[:time]
215
- nTargetTimespan = retarget * 600
216
-
217
- nActualTimespan = [nActualTimespan, nTargetTimespan/4].max
218
- nActualTimespan = [nActualTimespan, nTargetTimespan*4].min
219
-
220
- target = Bitcoin.decode_compact_bits(last[:bits]).to_i(16)
221
- new_target = [max_target, (target * nActualTimespan)/nTargetTimespan].min
222
- Bitcoin.encode_compact_bits new_target.to_s(16)
223
- end
224
-
225
- KNOWN_EXCEPTIONS = [
226
- Bitcoin.network[:genesis_hash], # genesis block
227
- "00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec", # BIP30 exception
228
- "00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721", # BIP30 exception
229
- ]
230
-
231
- end
232
-
233
- class Tx
234
- attr_accessor :tx, :store, :error, :block_validator
235
-
236
- RULES = {
237
- syntax: [:hash, :lists, :max_size, :output_values, :inputs, :lock_time, :standard],
238
- context: [:prev_out, :signatures, :not_spent, :input_values, :output_sum]
239
- }
240
-
241
- # validate tx rules. +opts+ are:
242
- # rules:: which rulesets to validate (default: [:syntax, :context])
243
- # raise_errors:: whether to raise ValidationError on failure (default: false)
244
- def validate(opts = {})
245
- return true if KNOWN_EXCEPTIONS.include?(tx.hash)
246
- opts[:rules] ||= [:syntax, :context]
247
- opts[:rules].each do |name|
248
- store.log.debug { "validating tx #{name} #{tx.hash} (#{tx.to_payload.bytesize} bytes)" } if store
249
- RULES[name].each.with_index do |rule, i|
250
- unless (res = send(rule)) && res == true
251
- raise ValidationError, "tx error: #{name} check #{i} - #{rule} failed" if opts[:raise_errors]
252
- @error = [rule, res]
253
- return false
254
- end
255
- end
256
- end
257
- clear_cache # memory optimizatons
258
- true
259
- end
260
-
261
- KNOWN_EXCEPTIONS = [
262
- # p2sh with invalid inner script, accepted by old miner before 4-2012 switchover
263
- "6a26d2ecb67f27d1fa5524763b49029d7106e91e3cc05743073461a719776192",
264
- # p2sh with invalid inner script, accepted by old miner before 4-2012 switchover (testnet)
265
- "b3c19d78b4953b694717a47d9852f8ea1ccd4cf93a45ba2e43a0f97d7cdb2655"
266
- ]
267
-
268
- # Setup new validator for given +tx+, validating context with +store+.
269
- # Also needs the +block+ that includes the tx to be validated, to find
270
- # prev_outs for chains of txs inside the block.
271
- # Optionally accepts the validator object for the block, to optimize fetching
272
- # prev_txs and checking for doublespends.
273
- def initialize(tx, store, block = nil, block_validator = nil)
274
- @tx, @store, @block, @errors = tx, store, block, []
275
- @block_validator = block_validator
276
- end
277
-
278
- # check that tx hash matches data
279
- def hash
280
- generated_hash = tx.generate_hash(tx.to_payload)
281
- tx.hash == generated_hash || [tx.hash, generated_hash]
282
- end
283
-
284
- # check that tx has at least one input and one output
285
- def lists
286
- (tx.in.any? && tx.out.any?) || [tx.in.size, tx.out.size]
287
- end
288
-
289
- # check that tx size doesn't exceed MAX_BLOCK_SIZE.
290
- def max_size
291
- tx.to_payload.bytesize <= Bitcoin::MAX_BLOCK_SIZE || [tx.to_payload.bytesize, Bitcoin::MAX_BLOCK_SIZE]
292
- end
293
-
294
- # check that total output value doesn't exceed MAX_MONEY.
295
- def output_values
296
- total = tx.out.inject(0) {|e, out| e + out.value }
297
- total <= Bitcoin::network[:max_money] || [total, Bitcoin::network[:max_money]]
298
- end
299
-
300
- # check that none of the inputs is coinbase
301
- # (coinbase tx do not get validated)
302
- def inputs
303
- tx.inputs.none?(&:coinbase?) || [tx.inputs.index(tx.inputs.find(&:coinbase?))]
304
- end
305
-
306
- # check that lock_time doesn't exceed INT_MAX
307
- def lock_time
308
- tx.lock_time <= Bitcoin::UINT32_MAX || [tx.lock_time, Bitcoin::UINT32_MAX]
309
- end
310
-
311
- # check that min_size is at least 86 bytes
312
- # (smaller tx can't be valid / do anything useful)
313
- def min_size
314
- tx.to_payload.bytesize >= 86 || [tx.to_payload.bytesize, 86]
315
- end
316
-
317
- # check that tx matches "standard" rules.
318
- # this is currently disabled since not all miners enforce it.
319
- def standard
320
- return true # not enforced by all miners
321
- return false unless min_size
322
- tx.out.all? {|o| Bitcoin::Script.new(o.pk_script).is_standard? }
323
- end
324
-
325
- # check that all prev_outs exist
326
- # (and are in a block in the main chain, or the current block; see #prev_txs)
327
- def prev_out
328
- missing = tx.in.reject.with_index {|txin, idx|
329
- prev_txs[idx].out[txin.prev_out_index] rescue false }
330
- return true if prev_txs.size == tx.in.size && missing.empty?
331
-
332
- missing.each {|i| store.log.warn { "prev out #{i.prev_out.reverse_hth}:#{i.prev_out_index} missing" } }
333
- missing.map {|i| [i.prev_out.reverse_hth, i.prev_out_index] }
334
- end
335
-
336
- # TODO: validate coinbase maturity
337
-
338
- # check that all input signatures are valid
339
- def signatures
340
- sigs = tx.in.map.with_index {|txin, idx| tx.verify_input_signature(idx, prev_txs[idx], (@block ? @block.time : 0)) }
341
- sigs.all? || sigs.map.with_index {|s, i| s ? nil : i }.compact
342
- end
343
-
344
- # check that none of the prev_outs are already spent in the main chain or in the current block
345
- def not_spent
346
- # if we received cached spents, use it
347
- return block_validator.spent_outs_txins.empty? if block_validator
348
-
349
- # find all spent txouts
350
- next_ins = store.get_txins_for_txouts(tx.in.map.with_index {|txin, idx| [txin.prev_out.reverse_hth, txin.prev_out_index] })
351
-
352
- # no txouts found spending these txins, we can safely return true
353
- return true if next_ins.empty?
354
-
355
- # there were some txouts spending these txins, verify that they are not on the main chain
356
- next_ins.select! {|i| i.get_tx.blk_id } # blk_id is only set for tx in the main chain
357
- return true if next_ins.empty?
358
-
359
- # now we know some txouts are already spent, return tx_idxs for debugging purposes
360
- return next_ins.map {|i| i.get_prev_out.tx_idx }
361
- end
362
-
363
- # check that the total input value doesn't exceed MAX_MONEY
364
- def input_values
365
- total_in < Bitcoin::network[:max_money] || [total_in, Bitcoin::network[:max_money]]
366
- end
367
-
368
- # check that the total output value doesn't exceed the total input value
369
- def output_sum
370
- total_in >= total_out || [total_out, total_in]
371
- end
372
-
373
- # empty prev txs cache
374
- def clear_cache
375
- @prev_txs = nil
376
- @total_in = nil
377
- @total_out = nil
378
- end
379
-
380
- # collect prev_txs needed to verify the inputs of this tx.
381
- # only returns tx that are in a block in the main chain or the current block.
382
- def prev_txs
383
- @prev_txs ||= tx.in.map {|i|
384
- prev_tx = block_validator ? block_validator.prev_txs_hash[i.prev_out.reverse_hth] : store.get_tx(i.prev_out.reverse_hth)
385
- next prev_tx if prev_tx && prev_tx.blk_id # blk_id is set only if it's in the main chain
386
- @block.tx.find {|t| t.binary_hash == i.prev_out } if @block
387
- }.compact
388
- end
389
-
390
-
391
- def total_in
392
- @total_in ||= tx.in.each_with_index.inject(0){|acc,(input,idx)| acc + prev_txs[idx].out[input.prev_out_index].value }
393
- end
394
-
395
- def total_out
396
- @total_out ||= tx.out.inject(0){|acc,output| acc + output.value }
397
- end
398
-
399
- end
400
- end
@@ -1,33 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- module Bitcoin::Wallet
4
-
5
- # select unspent txouts to be used by the Wallet when creating a new transaction
6
- class SimpleCoinSelector
7
-
8
- # create coinselector with given +txouts+
9
- def initialize txouts
10
- @txouts = txouts
11
- end
12
-
13
- # select txouts needed to spend +value+ btc (base units)
14
- def select(value)
15
- txouts = []
16
- @txouts.each do |txout|
17
- begin
18
- next if txout.get_next_in
19
- next if Bitcoin.namecoin? && txout.type.to_s =~ /^name_/
20
- next unless txout.get_address
21
- next unless txout.get_tx.get_block
22
- txouts << txout
23
- return txouts if txouts.map(&:value).inject(:+) >= value
24
- rescue
25
- p $!
26
- end
27
- end
28
- nil
29
- end
30
-
31
- end
32
-
33
- end
@@ -1,77 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- module Bitcoin::Wallet
4
-
5
- # Deterministic key generator as described in
6
- # https://bitcointalk.org/index.php?topic=11665.0.
7
- #
8
- # Takes a seed and generates an arbitrary amount of keys.
9
- # Protects against brute-force attacks by requiring the
10
- # key hash to fit a difficulty target, much like the block chain.
11
- class KeyGenerator
12
-
13
- # difficulty target (0x0000FFFF00000000000000000000000000000000000000000000000000000000)
14
- DEFAULT_TARGET = 0x0000FFFF00000000000000000000000000000000000000000000000000000000
15
-
16
- attr_accessor :seed, :nonce, :target
17
-
18
- # Initialize key generator with optional +seed+ and +nonce+ and +target+.
19
- # [seed] the seed data for the keygenerator (default: random)
20
- # [nonce] the nonce required to satisfy the target (default: computed)
21
- # [target] custom difficulty target (default: DEFAULT_TARGET)
22
- #
23
- # Example:
24
- # g = KeyGenerator.new # random seed, computed nonce, default target
25
- # KeyGenerator.new(g.seed)
26
- # KeyGenerator.new(g.seed, g.nonce)
27
- # g.get_key(0) #=> <Bitcoin::Key>
28
- #
29
- # Note: When initializing without seed, you should obviously save the
30
- # seed once it is generated. Saving the nonce is optional; it only saves time.
31
- def initialize seed = nil, nonce = nil, target = nil
32
- @seed = seed || OpenSSL::Random.random_bytes(64)
33
- @target = target || DEFAULT_TARGET
34
- @nonce = check_nonce(nonce)
35
- end
36
-
37
- # get key number +n+ from chain
38
- def get_key(n = 0)
39
- key = get_hash(@seed, @nonce)
40
- (n + 1).times { key = sha256(key) }
41
- key
42
- Bitcoin::Key.new(key.unpack("H*")[0])
43
- end
44
-
45
- # find a nonce that leads to the privkey satisfying the target
46
- def find_nonce
47
- n = 0
48
- n += 1 while !check_target(get_hash(@seed, n))
49
- n
50
- end
51
-
52
- protected
53
-
54
- # check the nonce; compute if missing, raise if invalid.
55
- def check_nonce(nonce)
56
- return find_nonce unless nonce
57
- # check_target(get_hash(@seed, nonce)) ? nonce : find_nonce
58
- raise ArgumentError, "Nonce invalid." unless check_target(get_hash(@seed, nonce))
59
- nonce
60
- end
61
-
62
- # check if given +hash+ satisfies the difficulty target
63
- def check_target(hash)
64
- hash.unpack("H*")[0].to_i(16) < @target
65
- end
66
-
67
- # compute a single SHA256 hash for +d+.
68
- def sha256(d); Digest::SHA256.digest(d); end
69
-
70
- # get the hash corresponding to +seed+ and +n+.
71
- def get_hash(seed, n)
72
- sha256( sha256(seed) + sha256(n.to_s) )
73
- end
74
-
75
- end
76
-
77
- end