monacoin-ruby 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,125 @@
1
+ module Bitcoin
2
+ class BloomFilter
3
+ SEED_SHIFT = 0xfba4c795
4
+ BIT_MASK = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]
5
+
6
+ MAX_FILTER_SIZE = 36000
7
+ MAX_HASH_FUNCS = 50
8
+
9
+ # flags for filterload message
10
+ BLOOM_UPDATE_NONE = 0
11
+ BLOOM_UPDATE_ALL = 1
12
+ BLOOM_UPDATE_P2PUBKEY_ONLY = 2
13
+
14
+ attr_reader :filter, :nfunc, :tweak
15
+
16
+ def initialize(elements, fp_rate, tweak)
17
+ init_filter(elements, fp_rate)
18
+ @tweak = tweak
19
+ end
20
+
21
+ def add_data(data)
22
+ @nfunc.times.each do |fi|
23
+ idx = calc_index(data, fi)
24
+ i = idx / 8
25
+ @filter[i] = (@filter[i].ord | BIT_MASK[idx % 8]).chr
26
+ end
27
+ end
28
+
29
+ def contains?(data)
30
+ @nfunc.times.all? do |fi|
31
+ idx = calc_index(data, fi)
32
+ i = idx / 8
33
+ @filter[i].ord & BIT_MASK[idx % 8] != 0
34
+ end
35
+ end
36
+
37
+ def add_address(address)
38
+ add_data(Bitcoin.hash160_from_address(address).htb)
39
+ end
40
+
41
+ def add_outpoint(prev_tx_hash, prev_output)
42
+ add_data(prev_tx_hash.htb_reverse + [prev_output].pack('V'))
43
+ end
44
+
45
+ private
46
+
47
+ #
48
+ # calculate filter size and number of funcs.
49
+ # See: https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki
50
+ #
51
+ def init_filter(elements, fp_rate)
52
+ ln2 = Math.log(2)
53
+
54
+ # using #ceil instead of #floor may be better, but it's bitcoinj's way
55
+
56
+ calc_m = (-Math.log(fp_rate) * elements / ln2 / ln2 / 8).floor;
57
+ @filter_size = [1, [calc_m, MAX_FILTER_SIZE].min].max;
58
+ @filter = "\x00" * @filter_size
59
+
60
+ calc_k = (@filter_size * 8 * ln2 / elements).floor
61
+ @nfunc = [1, [calc_k, MAX_HASH_FUNCS].min].max
62
+ end
63
+
64
+ def rotate_left32(x, r)
65
+ return (x << r) | (x >> (32 - r))
66
+ end
67
+
68
+ #
69
+ # calculate MurmurHash3
70
+ # See: https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
71
+ #
72
+ def calc_index(data, hash_index)
73
+ object = data.bytes
74
+ h1 = (hash_index * SEED_SHIFT + @tweak) & 0xffffffff
75
+ c1 = 0xcc9e2d51
76
+ c2 = 0x1b873593
77
+
78
+ num_blocks = (object.length / 4) * 4
79
+ i = 0
80
+ # body
81
+ while i < num_blocks
82
+ k1 = (object[i] & 0xFF) |
83
+ ((object[i + 1] & 0xFF) << 8) |
84
+ ((object[i + 2] & 0xFF) << 16) |
85
+ ((object[i + 3] & 0xFF) << 24)
86
+
87
+ k1 *= c1; k1 &= 0xffffffff
88
+ k1 = rotate_left32(k1, 15)
89
+ k1 *= c2; k1 &= 0xffffffff
90
+
91
+ h1 ^= k1
92
+ h1 = rotate_left32(h1, 13)
93
+ h1 = (h1 * 5 + 0xe6546b64) & 0xffffffff
94
+
95
+ i += 4
96
+ end
97
+
98
+ k1 = 0
99
+ flg = object.length & 3
100
+ if flg >= 3
101
+ k1 ^= (object[num_blocks + 2] & 0xff) << 16
102
+ end
103
+ if flg >= 2
104
+ k1 ^= (object[num_blocks + 1] & 0xff) << 8
105
+ end
106
+ if flg >= 1
107
+ k1 ^= (object[num_blocks] & 0xff)
108
+ k1 *= c1; k1 &= 0xffffffff
109
+ k1 = rotate_left32(k1, 15)
110
+ k1 *= c2; k1 &= 0xffffffff
111
+ h1 ^= k1
112
+ end
113
+
114
+ # finalization
115
+ h1 ^= object.length
116
+ h1 ^= h1 >> 16
117
+ h1 *= 0x85ebca6b; h1 &= 0xffffffff
118
+ h1 ^= h1 >> 13
119
+ h1 *= 0xc2b2ae35; h1 &= 0xffffffff
120
+ h1 ^= h1 >> 16
121
+
122
+ return (h1 & 0xffffffff) % (@filter_size * 8)
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,494 @@
1
+ # encoding: ascii-8bit
2
+
3
+ module Bitcoin
4
+
5
+ # Optional DSL to help create blocks and transactions.
6
+ #
7
+ # see also BlockBuilder, TxBuilder, TxInBuilder, TxOutBuilder, ScriptBuilder
8
+ module Builder
9
+
10
+ # build a Bitcoin::Protocol::Block matching the given +target+.
11
+ # see BlockBuilder for details.
12
+ def build_block(target = "00".ljust(64, 'f'))
13
+ c = BlockBuilder.new
14
+ yield c
15
+ c.block(target)
16
+ end
17
+
18
+ # build a Bitcoin::Protocol::Tx.
19
+ # see TxBuilder for details.
20
+ def build_tx opts = {}
21
+ c = TxBuilder.new
22
+ yield c
23
+ c.tx opts
24
+ end
25
+
26
+ # build a Bitcoin::Script.
27
+ # see ScriptBuilder for details.
28
+ def script
29
+ c = ScriptBuilder.new
30
+ yield c
31
+ c.script
32
+ end
33
+
34
+ # DSL to create a Bitcoin::Protocol::Block used by Builder#create_block.
35
+ # block = blk("00".ljust(32, 'f')) do |b|
36
+ # b.prev_block "\x00"*32
37
+ # b.tx do |t|
38
+ # t.input {|i| i.coinbase }
39
+ # t.output do |o|
40
+ # o.value 5000000000;
41
+ # o.to Bitcoin::Key.generate.addr
42
+ # end
43
+ # end
44
+ # end
45
+ #
46
+ # See Bitcoin::Builder::TxBuilder for details on building transactions.
47
+ class BlockBuilder
48
+
49
+ def initialize
50
+ @block = P::Block.new(nil)
51
+ end
52
+
53
+ # specify block version. this is usually not necessary. defaults to 1.
54
+ def version v
55
+ @version = v
56
+ end
57
+
58
+ # set the hash of the previous block.
59
+ def prev_block hash
60
+ @prev_block = hash
61
+ end
62
+
63
+ # set the block timestamp (defaults to current time).
64
+ def time time
65
+ @time = time
66
+ end
67
+
68
+ # add transactions to the block (see TxBuilder).
69
+ def tx tx = nil
70
+ tx ||= ( c = TxBuilder.new; yield c; c.tx )
71
+ @block.tx << tx
72
+ tx
73
+ end
74
+
75
+ # create the block according to values specified via DSL.
76
+ def block target
77
+ @block.ver = @version || 1
78
+ @block.prev_block = @prev_block.htb.reverse
79
+ @block.mrkl_root = @mrkl_root
80
+ @block.time = @time || Time.now.to_i
81
+ @block.nonce = 0
82
+ @block.mrkl_root = Bitcoin.hash_mrkl_tree(@block.tx.map(&:hash)).last.htb.reverse
83
+ find_hash(target)
84
+ block = P::Block.new(@block.to_payload)
85
+ raise "Payload Error" unless block.to_payload == @block.to_payload
86
+ block
87
+ end
88
+
89
+ private
90
+
91
+ # increment nonce/time to find a block hash matching the +target+.
92
+ def find_hash target
93
+ @block.bits = Bitcoin.encode_compact_bits(target)
94
+ t = Time.now
95
+ @block.recalc_block_hash
96
+ until @block.hash.to_i(16) < target.to_i(16)
97
+ @block.nonce += 1
98
+ @block.recalc_block_hash
99
+ if @block.nonce == 100000
100
+ if t
101
+ tt = 1 / ((Time.now - t) / 100000) / 1000
102
+ print "\r%.2f khash/s" % tt
103
+ end
104
+ t = Time.now
105
+ @block.time = Time.now.to_i
106
+ @block.nonce = 0
107
+ $stdout.flush
108
+ end
109
+ end
110
+ end
111
+
112
+ end
113
+
114
+ # DSL to create Bitcoin::Protocol::Tx used by Builder#build_tx.
115
+ # tx = tx do |t|
116
+ # t.input do |i|
117
+ # i.prev_out prev_tx, 0
118
+ # i.signature_key key
119
+ # end
120
+ # t.output do |o|
121
+ # o.value 12345 # 0.00012345 BTC
122
+ # o.to key.addr
123
+ # end
124
+ # end
125
+ #
126
+ # Signs every input that has a signature key and where the previous outputs
127
+ # pk_script is known. If unable to sign, the resulting txin will include
128
+ # the #sig_hash that needs to be signed.
129
+ #
130
+ # See TxInBuilder and TxOutBuilder for details on how to build in/outputs.
131
+ class TxBuilder
132
+
133
+ def initialize
134
+ @tx = P::Tx.new(nil)
135
+ @tx.ver, @tx.lock_time = 1, 0
136
+ @ins, @outs = [], []
137
+ end
138
+
139
+ # specify tx version. this is usually not necessary. defaults to 1.
140
+ def version n
141
+ @tx.ver = n
142
+ end
143
+
144
+ # specify tx lock_time. this is usually not necessary. defaults to 0.
145
+ def lock_time n
146
+ @tx.lock_time = n
147
+ end
148
+
149
+ # add an input to the transaction (see TxInBuilder).
150
+ def input
151
+ c = TxInBuilder.new
152
+ yield c
153
+ @ins << c
154
+ end
155
+
156
+ # add an output to the transaction (see TxOutBuilder).
157
+ def output value = nil, recipient = nil, type = :address
158
+ c = TxOutBuilder.new
159
+ c.value(value) if value
160
+ c.to(recipient, type) if recipient
161
+ yield c if block_given?
162
+ @outs << c
163
+ end
164
+
165
+ # Create the transaction according to values specified via DSL.
166
+ # Sign each input that has a signature key specified. If there is
167
+ # no key, store the sig_hash in the input, so it can easily be
168
+ # signed later.
169
+ #
170
+ # When :change_address and :input_value options are given, it will
171
+ # automatically create a change output sending the remaining funds
172
+ # to the given address. The :leave_fee option can be used in this
173
+ # case to specify a tx fee that should be left unclaimed by the
174
+ # change output.
175
+ def tx opts = {}
176
+ return @tx if @tx.hash
177
+
178
+ if opts[:change_address] && !opts[:input_value]
179
+ raise "Must give 'input_value' when auto-generating change output!"
180
+ end
181
+ @ins.each {|i| @tx.add_in(i.txin) }
182
+ @outs.each {|o| @tx.add_out(o.txout) }
183
+ if opts[:change_address]
184
+ output_value = @tx.out.map(&:value).inject(:+) || 0
185
+ change_value = opts[:input_value] - output_value
186
+ if opts[:leave_fee]
187
+ fee = @tx.minimum_block_fee + (opts[:extra_fee] || 0)
188
+ if change_value >= fee
189
+ change_value -= fee
190
+ else
191
+ change_value = 0
192
+ end
193
+ end
194
+ if change_value > 0
195
+ script = Script.to_address_script(opts[:change_address])
196
+ @tx.add_out(P::TxOut.new(change_value, script))
197
+ end
198
+ end
199
+
200
+ @ins.each_with_index do |inc, i|
201
+ sign_input(i, inc)
202
+ end
203
+
204
+ # run our tx through an encode/decode cycle to make sure that the binary format is sane
205
+ raise "Payload Error" unless P::Tx.new(@tx.to_witness_payload).to_payload == @tx.to_payload
206
+ @tx.instance_eval do
207
+ @payload = to_payload
208
+ @hash = hash_from_payload(@payload)
209
+ end
210
+
211
+ @tx
212
+ end
213
+
214
+ # coinbase inputs don't need to be signed, they only include the given +coinbase_data+
215
+ def include_coinbase_data i, inc
216
+ script_sig = [inc.coinbase_data].pack("H*")
217
+ @tx.in[i].script_sig_length = script_sig.bytesize
218
+ @tx.in[i].script_sig = script_sig
219
+ end
220
+
221
+ def sig_hash_and_all_keys_exist?(inc, sig_script)
222
+ return false unless @sig_hash && inc.has_keys?
223
+ script = Bitcoin::Script.new(sig_script)
224
+ return true if script.is_hash160? || script.is_pubkey? || script.is_witness_v0_keyhash? || (Bitcoin.namecoin? && script.is_namecoin?)
225
+ if script.is_multisig?
226
+ return inc.has_multiple_keys? && inc.key.size >= script.get_signatures_required
227
+ end
228
+ raise "Script type must be hash160, pubkey, p2wpkh or multisig"
229
+ end
230
+
231
+ def add_empty_script_sig_to_input(i)
232
+ @tx.in[i].script_sig_length = 0
233
+ @tx.in[i].script_sig = ""
234
+ # add the sig_hash that needs to be signed, so it can be passed on to a signing device
235
+ @tx.in[i].sig_hash = @sig_hash
236
+ # add the address the sig_hash needs to be signed with as a convenience for the signing device
237
+ @tx.in[i].sig_address = Script.new(@prev_script).get_address if @prev_script
238
+ end
239
+
240
+ def get_script_sig(inc)
241
+ if inc.has_multiple_keys?
242
+ # multiple keys given, generate signature for each one
243
+ sigs = inc.sign(@sig_hash)
244
+ if redeem_script = inc.instance_eval { @redeem_script }
245
+ # when a redeem_script was specified, assume we spend a p2sh multisig script
246
+ script_sig = Script.to_p2sh_multisig_script_sig(redeem_script, sigs)
247
+ else
248
+ # when no redeem_script is given, do a regular multisig spend
249
+ script_sig = Script.to_multisig_script_sig(*sigs)
250
+ end
251
+ else
252
+ # only one key given, generate signature and script_sig
253
+ sig = inc.sign(@sig_hash)
254
+ script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack("H*"))
255
+ end
256
+ return script_sig
257
+ end
258
+
259
+ # Sign input number +i+ with data from given +inc+ object (a TxInBuilder).
260
+ def sign_input i, inc
261
+ if @tx.in[i].coinbase?
262
+ include_coinbase_data(i, inc)
263
+ else
264
+ @prev_script = inc.instance_variable_get(:@prev_out_script)
265
+
266
+ # get the signature script; use +redeem_script+ if given
267
+ # (indicates spending a p2sh output), otherwise use the prev_script
268
+ sig_script = inc.instance_eval { @redeem_script }
269
+ sig_script ||= @prev_script
270
+
271
+ # when a sig_script was found, generate the sig_hash to be signed
272
+ if sig_script
273
+ script = Script.new(sig_script)
274
+ if script.is_witness_v0_keyhash?
275
+ @sig_hash = @tx.signature_hash_for_witness_input(i, sig_script, inc.value)
276
+ else
277
+ @sig_hash = @tx.signature_hash_for_input(i, sig_script)
278
+ end
279
+ end
280
+
281
+ # when there is a sig_hash and one or more signature_keys were specified
282
+ if sig_hash_and_all_keys_exist?(inc, sig_script)
283
+ # add the script_sig to the txin
284
+ if script.is_witness_v0_keyhash? # for p2wpkh
285
+ @tx.in[i].script_witness.stack << inc.sign(@sig_hash) + [Script::SIGHASH_TYPE[:all]].pack("C")
286
+ @tx.in[i].script_witness.stack << inc.key.pub.htb
287
+ else
288
+ @tx.in[i].script_sig = get_script_sig(inc)
289
+ end
290
+ # double-check that the script_sig is valid to spend the given prev_script
291
+ raise "Signature error" if @prev_script && !@tx.verify_input_signature(i, @prev_script)
292
+ elsif inc.has_multiple_keys?
293
+ raise "Keys missing for multisig signing"
294
+ else
295
+ # no sig_hash, add an empty script_sig.
296
+ add_empty_script_sig_to_input(i)
297
+ end
298
+ end
299
+ end
300
+
301
+ # Randomize the outputs using SecureRandom
302
+ def randomize_outputs
303
+ @outs.sort_by!{ SecureRandom.random_bytes(4).unpack("I")[0] }
304
+ end
305
+ end
306
+
307
+ # Create a Bitcoin::Protocol::TxIn used by TxBuilder#input.
308
+ #
309
+ # Inputs need the transaction hash and the index of the output they spend.
310
+ # You can pass either the transaction, or just its hash (in hex form).
311
+ # To sign the input, builder also needs the pk_script of the previous output.
312
+ # If you specify a tx hash instead of the whole tx, you need to specify the
313
+ # output script separately.
314
+ #
315
+ # t.input do |i|
316
+ # i.prev_out prev_tx # previous transaction
317
+ # i.prev_out_index 0 # index of previous output
318
+ # i.signature_key key # Bitcoin::Key used to sign the input
319
+ # end
320
+ #
321
+ # t.input {|i| i.prev_out prev_tx, 0 }
322
+ #
323
+ # If you want to spend a p2sh output, you also need to specify the +redeem_script+.
324
+ #
325
+ # t.input do |i|
326
+ # i.prev_out prev_tx, 0
327
+ # i.redeem_script prev_out.redeem_script
328
+ # end
329
+ #
330
+ # If you want to spend a multisig output, just provide an array of keys to #signature_key.
331
+ class TxInBuilder
332
+ attr_reader :prev_tx, :prev_script, :redeem_script, :key, :coinbase_data, :prev_out_value
333
+
334
+ def initialize
335
+ @txin = P::TxIn.new
336
+ @prev_out_hash = "\x00" * 32
337
+ @prev_out_index = 0
338
+ end
339
+
340
+ # Previous transaction that contains the output we want to use.
341
+ # You can either pass the transaction, or just the tx hash.
342
+ # If you pass only the hash, you need to pass the previous outputs
343
+ # +script+ separately if you want the txin to be signed.
344
+ def prev_out tx, idx = nil, script = nil, prev_value = nil
345
+ if tx.is_a?(Bitcoin::P::Tx)
346
+ @prev_tx = tx
347
+ @prev_out_hash = tx.binary_hash
348
+ @prev_out_script = tx.out[idx].pk_script if idx
349
+ else
350
+ @prev_out_hash = tx.htb.reverse
351
+ end
352
+ @prev_out_script = script if script
353
+ @prev_out_index = idx if idx
354
+ @prev_out_value = prev_value if prev_value
355
+ end
356
+
357
+ # Index of the output in the #prev_out transaction.
358
+ def prev_out_index i
359
+ @prev_out_index = i
360
+ @prev_out_script = @prev_tx.out[i].pk_script if @prev_tx
361
+ end
362
+
363
+ # Previous output's +pk_script+. Needed when only the tx hash is specified as #prev_out.
364
+ def prev_out_script script
365
+ @prev_out_script = script
366
+ end
367
+
368
+ # Previous output's +value+. Needed when only spend segwit utxo.
369
+ def prev_out_value value
370
+ @prev_out_value = value
371
+ end
372
+
373
+ def value
374
+ @prev_out_value
375
+ end
376
+
377
+ # Redeem script for P2SH output. To spend from a P2SH output, you need to provide
378
+ # the script with a hash matching the P2SH address.
379
+ def redeem_script script
380
+ @redeem_script = script
381
+ end
382
+
383
+ # Specify sequence. This is usually not needed.
384
+ def sequence s
385
+ @sequence = s
386
+ end
387
+
388
+ # Bitcoin::Key used to sign the signature_hash for the input.
389
+ # see Bitcoin::Script.signature_hash_for_input and Bitcoin::Key.sign.
390
+ def signature_key key
391
+ @key = key
392
+ end
393
+
394
+ # Specify that this is a coinbase input. Optionally set +data+.
395
+ # If this is set, no other options need to be given.
396
+ def coinbase data = nil
397
+ @coinbase_data = data || OpenSSL::Random.random_bytes(32)
398
+ @prev_out_hash = "\x00" * 32
399
+ @prev_out_index = 4294967295
400
+ end
401
+
402
+ # Create the txin according to specified values
403
+ def txin
404
+ @txin.prev_out = @prev_out_hash
405
+ @txin.prev_out_index = @prev_out_index
406
+ @txin.sequence = @sequence || "\xff\xff\xff\xff"
407
+ @txin
408
+ end
409
+
410
+ def has_multiple_keys?
411
+ @key.is_a?(Array)
412
+ end
413
+
414
+ def has_keys?
415
+ @key && (has_multiple_keys? ? @key.all?(&:priv) : @key.priv)
416
+ end
417
+
418
+ def is_witness_v0_keyhash?
419
+ @prev_out_script && Script.new(@prev_out_script).is_witness_v0_keyhash?
420
+ end
421
+
422
+ def sign(sig_hash)
423
+ if has_multiple_keys?
424
+ @key.map {|k| k.sign(sig_hash) }
425
+ else
426
+ @key.sign(sig_hash)
427
+ end
428
+ end
429
+ end
430
+
431
+ # Create a Bitcoin::Script used by TxOutBuilder#script.
432
+ class ScriptBuilder
433
+ attr_reader :script, :redeem_script
434
+
435
+ def initialize
436
+ @type = :address
437
+ @script = nil
438
+ end
439
+
440
+ # Script type (:pubkey, :address/hash160, :multisig).
441
+ # Defaults to :address.
442
+ def type type
443
+ @type = type.to_sym
444
+ end
445
+
446
+ # Recipient(s) of the script.
447
+ # Depending on the #type, this should be an address, a hash160 pubkey,
448
+ # or an array of multisig pubkeys.
449
+ def recipient *data
450
+ @script, @redeem_script = *Script.send("to_#{@type}_script", *data)
451
+ end
452
+ end
453
+
454
+ # Create a Bitcoin::Protocol::TxOut used by TxBuilder#output.
455
+ #
456
+ # t.output 12345, address
457
+ # t.output 12345, p2sh_address, :script_hash
458
+ #
459
+ # t.output {|o| o.value 12345; o.to address }
460
+ #
461
+ # t.output do |o|
462
+ # o.value 12345
463
+ # o.script {|s| s.recipient address }
464
+ # end
465
+ #
466
+ # t.output {|o| o.to "deadbeef", :op_return }
467
+ class TxOutBuilder
468
+ attr_reader :txout
469
+
470
+ def initialize
471
+ @txout = P::TxOut.new(0)
472
+ end
473
+
474
+ # Set output value (in base units / "satoshis")
475
+ def value value
476
+ @txout.value = value
477
+ end
478
+
479
+ # Set recipient address and script type (defaults to :address).
480
+ def to recipient, type = :address
481
+ @txout.pk_script, @txout.redeem_script = *Bitcoin::Script.send("to_#{type}_script", *recipient)
482
+ end
483
+
484
+ # Add a script to the output (see ScriptBuilder).
485
+ def script &block
486
+ c = ScriptBuilder.new
487
+ yield c
488
+ @txout.pk_script, @txout.redeem_script = c.script, c.redeem_script
489
+ end
490
+
491
+ end
492
+
493
+ end
494
+ end