monacoin-ruby 0.1.2 → 0.1.3

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.
@@ -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