bitcoin-ruby 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +2 -2
- data/COPYING +1 -1
- data/Gemfile +5 -11
- data/README.rdoc +11 -5
- data/Rakefile +5 -0
- data/bin/bitcoin_node +11 -29
- data/bin/bitcoin_node_cli +81 -0
- data/bin/bitcoin_wallet +9 -6
- data/doc/NODE.rdoc +79 -26
- data/examples/bbe_verify_tx.rb +1 -1
- data/examples/index_nhash.rb +24 -0
- data/examples/reindex_p2sh_addrs.rb +44 -0
- data/lib/bitcoin.rb +135 -20
- data/lib/bitcoin/builder.rb +233 -63
- data/lib/bitcoin/key.rb +89 -16
- data/lib/bitcoin/litecoin.rb +13 -11
- data/lib/bitcoin/namecoin.rb +5 -4
- data/lib/bitcoin/network/command_client.rb +23 -13
- data/lib/bitcoin/network/command_handler.rb +336 -131
- data/lib/bitcoin/network/connection_handler.rb +14 -13
- data/lib/bitcoin/network/node.rb +61 -20
- data/lib/bitcoin/protocol.rb +5 -1
- data/lib/bitcoin/protocol/block.rb +15 -3
- data/lib/bitcoin/protocol/parser.rb +3 -3
- data/lib/bitcoin/protocol/tx.rb +82 -20
- data/lib/bitcoin/protocol/txin.rb +7 -0
- data/lib/bitcoin/protocol/txout.rb +12 -9
- data/lib/bitcoin/script.rb +329 -75
- data/lib/bitcoin/storage/dummy/dummy_store.rb +23 -4
- data/lib/bitcoin/storage/models.rb +6 -11
- data/lib/bitcoin/storage/sequel/migrations/005_change_tx_hash_to_bytea.rb +14 -0
- data/lib/bitcoin/storage/sequel/migrations/006_add_tx_nhash.rb +31 -0
- data/lib/bitcoin/storage/sequel/migrations/007_add_prev_out_index_index.rb +16 -0
- data/lib/bitcoin/storage/sequel/migrations/008_add_txin_p2sh_type.rb +31 -0
- data/lib/bitcoin/storage/sequel/migrations/009_add_addrs_type.rb +56 -0
- data/lib/bitcoin/storage/sequel/sequel_store.rb +168 -70
- data/lib/bitcoin/storage/storage.rb +161 -97
- data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +1 -1
- data/lib/bitcoin/storage/utxo/migrations/004_add_addrs_type.rb +14 -0
- data/lib/bitcoin/storage/utxo/utxo_store.rb +25 -12
- data/lib/bitcoin/validation.rb +87 -56
- data/lib/bitcoin/version.rb +1 -1
- data/spec/bitcoin/bitcoin_spec.rb +38 -0
- data/spec/bitcoin/builder_spec.rb +177 -0
- data/spec/bitcoin/fixtures/litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json +259 -0
- data/spec/bitcoin/fixtures/rawblock-testnet-265322.bin +0 -0
- data/spec/bitcoin/fixtures/tx-0295028ef826b2a188409cb905b631faebb9bb3cdf14510571c5f4bd8591338f.json +64 -0
- data/spec/bitcoin/fixtures/tx-03339a725007a279484fb6f5361f522dd1cf4d0923d30e6b973290dba4275f92.json +64 -0
- data/spec/bitcoin/fixtures/tx-0ce7e5238fbdb6c086cf1b384b21b827e91cc23f360417265874a5a0d86ce367.json +64 -0
- data/spec/bitcoin/fixtures/tx-0ef34c49f630aea17df0080728b0fc67bf5f87fbda936934a4b11b4a69d7821e.json +64 -0
- data/spec/bitcoin/fixtures/tx-1129d2a8bd5bb3a81e54dc96a90f1f6b2544575748caa17243470935c5dd91b7.json +28 -0
- data/spec/bitcoin/fixtures/tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json +23 -0
- data/spec/bitcoin/fixtures/tx-1a4f3b9dc4494aeedeb39f30dd37e60541b2abe3ed4977992017cc0ad4f44956.json +64 -0
- data/spec/bitcoin/fixtures/tx-1f9191dcf2b1844ca28c6ef4b969e1d5fab70a5e3c56b7007949e55851cb0c4f.json +64 -0
- data/spec/bitcoin/fixtures/tx-22cd5fef23684d7b304e119bedffde6f54538d3d54a5bfa237e20dc2d9b4b5ad.json +64 -0
- data/spec/bitcoin/fixtures/tx-2958fb00b4fd6fe0353503b886eb9a193d502f4fd5fc042d5e03216ba918bbd6.json +64 -0
- data/spec/bitcoin/fixtures/tx-29f277145749ad6efbed3ae6ce301f8d33c585ec26b7c044ad93c2f866e9e942.json +64 -0
- data/spec/bitcoin/fixtures/tx-2c5e5376c20e9cc78d0fb771730e5d840cc2096eff0ef045b599fe92475ace1c.json +28 -0
- data/spec/bitcoin/fixtures/tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json +30 -0
- data/spec/bitcoin/fixtures/tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json +23 -0
- data/spec/bitcoin/fixtures/tx-345bed8785c3282a264ffb0dbee61cde54854f10e16f1b3e75b7f2d9f62946f2.json +64 -0
- data/spec/bitcoin/fixtures/tx-39ba7440b7103557560cc8ce258009936796485aaf8b478e66ab4cb97c66e31b.json +32 -0
- data/spec/bitcoin/fixtures/tx-3a04d57a833367f1655cc5ec3beb587888ef4977a86caa8c8ad4ba7cc717eae7.json +64 -0
- data/spec/bitcoin/fixtures/tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json +38 -0
- data/spec/bitcoin/fixtures/tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json +23 -0
- data/spec/bitcoin/fixtures/tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json +30 -0
- data/spec/bitcoin/fixtures/tx-62d9a565bd7b5344c5352e3e9e5f40fa4bbd467fa19c87357216ec8777ba1cce.json +64 -0
- data/spec/bitcoin/fixtures/tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json +23 -0
- data/spec/bitcoin/fixtures/tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json +27 -0
- data/spec/bitcoin/fixtures/tx-6aaf18b9f1283b939d8e5d40ff5f8a435229f4178372659cc3a0bce4e262bf78.json +28 -0
- data/spec/bitcoin/fixtures/tx-6b48bba6f6d2286d7ec0883c0fc3085955090813a4c94980466611c798b868cc.json +64 -0
- data/spec/bitcoin/fixtures/tx-70cfbc6690f9ab46712db44e3079ac227962b2771a9341d4233d898b521619ef.json +40 -0
- data/spec/bitcoin/fixtures/tx-7a1a9db42f065f75110fcdb1bc415549c8ef7670417ba1d35a67f1b8adc562c1.json +64 -0
- data/spec/bitcoin/fixtures/tx-9a768fc7d0c4bdc86e25154357ef7c0063ca21310e5740a2f12f90b7455184a7.json +64 -0
- data/spec/bitcoin/fixtures/tx-9cad8d523a0694f2509d092c39cebc8046adae62b4e4297102d568191d9478d8.json +64 -0
- data/spec/bitcoin/fixtures/tx-9e052eb694bd7e15906433f064dff0161a12fd325c1124537766377004023c6f.json +64 -0
- data/spec/bitcoin/fixtures/tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json +23 -0
- data/spec/bitcoin/fixtures/tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json +23 -0
- data/spec/bitcoin/fixtures/tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json +27 -0
- data/spec/bitcoin/fixtures/tx-ad4bcf3241e5d2ad140564e20db3567d41594cf4c2012433fe46a2b70e0d87b8.json +64 -0
- data/spec/bitcoin/fixtures/tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json +27 -0
- data/spec/bitcoin/fixtures/tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json +28 -0
- data/spec/bitcoin/fixtures/tx-bbca0628c42cb8bf7c3f4b2ad688fa56da5308dd2a10255da89fb1f46e6e413d.json +36 -0
- data/spec/bitcoin/fixtures/tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json +23 -0
- data/spec/bitcoin/fixtures/tx-c192b74844e4837a34c4a5a97b438f1c111405b01b99e2d12b7c96d07fc74c04.json +28 -0
- data/spec/bitcoin/fixtures/tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json +406 -0
- data/spec/bitcoin/fixtures/tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json +35 -0
- data/spec/bitcoin/fixtures/tx-fee1b9b85531c8fb6cd7831f83490c7f2aa768b6eefe29854ef5e89ce7b9ecb1.json +64 -0
- data/spec/bitcoin/fixtures/txscript-invalid-too-many-sigops-followed-by-invalid-pushdata.bin +1 -0
- data/spec/bitcoin/helpers/fake_blockchain.rb +183 -0
- data/spec/bitcoin/key_spec.rb +79 -8
- data/spec/bitcoin/namecoin_spec.rb +1 -1
- data/spec/bitcoin/node/command_api_spec.rb +373 -86
- data/spec/bitcoin/performance/storage_spec.rb +41 -0
- data/spec/bitcoin/protocol/addr_spec.rb +7 -5
- data/spec/bitcoin/protocol/aux_pow_spec.rb +1 -0
- data/spec/bitcoin/protocol/block_spec.rb +6 -0
- data/spec/bitcoin/protocol/tx_spec.rb +184 -1
- data/spec/bitcoin/protocol/txin_spec.rb +27 -0
- data/spec/bitcoin/protocol/txout_spec.rb +27 -0
- data/spec/bitcoin/script/opcodes_spec.rb +74 -3
- data/spec/bitcoin/script/script_spec.rb +271 -0
- data/spec/bitcoin/spec_helper.rb +34 -6
- data/spec/bitcoin/storage/models_spec.rb +104 -0
- data/spec/bitcoin/storage/reorg_spec.rb +42 -11
- data/spec/bitcoin/storage/storage_spec.rb +58 -15
- data/spec/bitcoin/storage/validation_spec.rb +44 -14
- data/spec/bitcoin/wallet/keygenerator_spec.rb +6 -3
- data/spec/bitcoin/wallet/keystore_spec.rb +3 -3
- data/spec/bitcoin/wallet/wallet_spec.rb +87 -89
- metadata +117 -11
data/examples/bbe_verify_tx.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift( File.expand_path("../../lib", __FILE__) )
|
4
|
+
require 'bitcoin'
|
5
|
+
|
6
|
+
Bitcoin.network = :testnet3
|
7
|
+
@store = Bitcoin::Storage.sequel(:db => "postgres://mhanne:password@localhost:5434/testnet3_full")
|
8
|
+
|
9
|
+
#@store.db.execute "DROP INDEX tx_nhash_index"
|
10
|
+
|
11
|
+
def process_block blk
|
12
|
+
print "\r#{blk.hash} - #{blk.depth}"
|
13
|
+
blk.tx.each do |tx|
|
14
|
+
@store.db[:tx].where(hash: tx.hash.htb.blob).update(nhash: tx.nhash.htb.blob)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
blk = @store.get_block_by_depth(0)
|
19
|
+
process_block(blk)
|
20
|
+
while blk = blk.get_next_block
|
21
|
+
process_block(blk)
|
22
|
+
end
|
23
|
+
|
24
|
+
@store.db.execute "CREATE INDEX tx_nhash_index ON tx (nhash)"
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift( File.expand_path("../../lib", __FILE__) )
|
4
|
+
require 'bitcoin'
|
5
|
+
|
6
|
+
Bitcoin.network = :testnet3
|
7
|
+
@store = Bitcoin::Storage.sequel(:db => "postgres://mhanne:password@localhost:5434/testnet3_full")
|
8
|
+
# @store = Bitcoin::Storage.sequel(:db => "postgres:/testnet3")
|
9
|
+
|
10
|
+
puts "move namecoin types up by one to make room for op_return"
|
11
|
+
if Bitcoin.network_name == :namecoin
|
12
|
+
@store.db.run "UPDATE txout SET type = 8 WHERE type = 7"
|
13
|
+
@store.db.run "UPDATE txout SET type = 7 WHERE type = 6"
|
14
|
+
@store.db.run "UPDATE txout SET type = 6 WHERE type = 5"
|
15
|
+
end
|
16
|
+
|
17
|
+
puts "create missing p2sh output <-> address mappings"
|
18
|
+
@store.db[:txout].where(type: 4).each do |txout|
|
19
|
+
script = Bitcoin::Script.new(txout[:pk_script])
|
20
|
+
if addr = @store.db[:addr][hash160: script.get_hash160]
|
21
|
+
addr_id = addr[:id]
|
22
|
+
else
|
23
|
+
addr_id = @store.db[:addr].insert(hash160: script.get_hash160)
|
24
|
+
end
|
25
|
+
|
26
|
+
if addr_txout = @store.db[:addr_txout][addr_id: addr_id, txout_id: txout[:id]]
|
27
|
+
# mapping already exists
|
28
|
+
print "e"
|
29
|
+
else
|
30
|
+
print "C"
|
31
|
+
@store.db[:addr_txout].insert(addr_id: addr_id, txout_id: txout[:id])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
puts
|
36
|
+
puts "scan all txouts of unknown type and check if they are op_returns"
|
37
|
+
@store.db[:txout].where(type: 0).each do |txout|
|
38
|
+
if Bitcoin::Script.new(txout[:pk_script]).is_op_return?
|
39
|
+
print "C"
|
40
|
+
@store.db[:txout].where(id: txout[:id]).update(type: 5)
|
41
|
+
else
|
42
|
+
print "s"
|
43
|
+
end
|
44
|
+
end
|
data/lib/bitcoin.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
require 'digest/sha2'
|
5
5
|
require 'digest/rmd160'
|
6
6
|
require 'openssl'
|
7
|
-
|
7
|
+
require 'securerandom'
|
8
8
|
|
9
9
|
module Bitcoin
|
10
10
|
|
@@ -21,6 +21,7 @@ module Bitcoin
|
|
21
21
|
autoload :Validation, 'bitcoin/validation'
|
22
22
|
|
23
23
|
autoload :Namecoin, 'bitcoin/namecoin'
|
24
|
+
autoload :Litecoin, 'bitcoin/litecoin'
|
24
25
|
|
25
26
|
module Network
|
26
27
|
autoload :ConnectionHandler, 'bitcoin/network/connection_handler'
|
@@ -128,6 +129,11 @@ module Bitcoin
|
|
128
129
|
hash160_to_address( hash160(pubkey) )
|
129
130
|
end
|
130
131
|
|
132
|
+
def pubkeys_to_p2sh_multisig_address(m, *pubkeys)
|
133
|
+
redeem_script = Bitcoin::Script.to_p2sh_multisig_script(m, *pubkeys).last
|
134
|
+
return Bitcoin.hash160_to_p2sh_address(Bitcoin.hash160(redeem_script.hth)), redeem_script
|
135
|
+
end
|
136
|
+
|
131
137
|
def int_to_base58(int_val, leading_zero_bytes=0)
|
132
138
|
alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
133
139
|
base58_val, base = '', alpha.size
|
@@ -228,6 +234,23 @@ module Bitcoin
|
|
228
234
|
bitcoin_hash(h)
|
229
235
|
end
|
230
236
|
|
237
|
+
def litecoin_hash(hex)
|
238
|
+
bytes = [hex].pack("H*").reverse
|
239
|
+
begin
|
240
|
+
require "scrypt" unless defined?(::SCrypt)
|
241
|
+
hash = SCrypt::Engine.__sc_crypt(bytes, bytes, 1024, 1, 1, 32)
|
242
|
+
rescue LoadError
|
243
|
+
hash = Litecoin::Scrypt.scrypt_1024_1_1_256_sp(bytes)
|
244
|
+
end
|
245
|
+
hash.reverse.unpack("H*")[0]
|
246
|
+
end
|
247
|
+
|
248
|
+
def block_scrypt_hash(prev_block, mrkl_root, time, bits, nonce, ver)
|
249
|
+
h = "%08x%08x%08x%064s%064s%08x" %
|
250
|
+
[nonce, bits, time, mrkl_root, prev_block, ver]
|
251
|
+
litecoin_hash(h)
|
252
|
+
end
|
253
|
+
|
231
254
|
# get merkle tree for given +tx+ list.
|
232
255
|
def hash_mrkl_tree(tx)
|
233
256
|
return [nil] if tx != tx.uniq
|
@@ -306,13 +329,11 @@ module Bitcoin
|
|
306
329
|
raise "malformed signature" unless signature.bytesize == 65
|
307
330
|
pubkey = Bitcoin::OpenSSL_EC.recover_compact(hash, signature)
|
308
331
|
pubkey_to_address(pubkey) == address if pubkey
|
309
|
-
rescue
|
332
|
+
rescue => ex
|
310
333
|
p [ex.message, ex.backtrace]; false
|
311
334
|
end
|
312
335
|
|
313
336
|
|
314
|
-
RETARGET_INTERVAL = 2016
|
315
|
-
|
316
337
|
# block count when the next retarget will take place.
|
317
338
|
def block_next_retarget(block_height)
|
318
339
|
(block_height + (RETARGET_INTERVAL-block_height.divmod(RETARGET_INTERVAL).last)) - 1
|
@@ -409,7 +430,8 @@ module Bitcoin
|
|
409
430
|
@network = :bitcoin
|
410
431
|
|
411
432
|
def self.network
|
412
|
-
|
433
|
+
# Store the copy of network options so we can modify them in tests without breaking the defaults
|
434
|
+
@network_options ||= NETWORKS[@network].dup
|
413
435
|
end
|
414
436
|
|
415
437
|
def self.network_name
|
@@ -420,8 +442,9 @@ module Bitcoin
|
|
420
442
|
@network_project
|
421
443
|
end
|
422
444
|
|
423
|
-
def self.network=
|
445
|
+
def self.network=(name)
|
424
446
|
raise "Network descriptor '#{name}' not found." unless NETWORKS[name.to_sym]
|
447
|
+
@network_options = nil # clear cached parameters
|
425
448
|
@network = name.to_sym
|
426
449
|
@network_project = network[:project] rescue nil
|
427
450
|
Bitcoin::Namecoin.load if namecoin?
|
@@ -433,13 +456,39 @@ module Bitcoin
|
|
433
456
|
end
|
434
457
|
|
435
458
|
|
436
|
-
|
437
|
-
COIN = 100_000_000
|
459
|
+
# maximum size of a block (in bytes)
|
438
460
|
MAX_BLOCK_SIZE = 1_000_000
|
461
|
+
|
462
|
+
# soft limit for new blocks
|
439
463
|
MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2
|
440
|
-
|
464
|
+
|
465
|
+
# maximum number of signature operations in a block
|
466
|
+
MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE / 50
|
467
|
+
|
468
|
+
# maximum number of orphan transactions to be kept in memory
|
441
469
|
MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100
|
442
470
|
|
471
|
+
# Threshold for lock_time: below this value it is interpreted as block number, otherwise as UNIX timestamp.
|
472
|
+
LOCKTIME_THRESHOLD = 500000000 # Tue Nov 5 00:53:20 1985 UTC
|
473
|
+
|
474
|
+
# maximum integer value
|
475
|
+
UINT32_MAX = 0xffffffff
|
476
|
+
INT_MAX = 0xffffffff # deprecated name, left here for compatibility with existing users.
|
477
|
+
|
478
|
+
# number of confirmations required before coinbase tx can be spent
|
479
|
+
COINBASE_MATURITY = 100
|
480
|
+
|
481
|
+
# interval (in blocks) for difficulty retarget
|
482
|
+
RETARGET_INTERVAL = 2016
|
483
|
+
RETARGET = 2016 # deprecated constant
|
484
|
+
|
485
|
+
|
486
|
+
# interval (in blocks) for mining reward reduction
|
487
|
+
REWARD_DROP = 210_000
|
488
|
+
|
489
|
+
CENT = 1_000_000
|
490
|
+
COIN = 100_000_000
|
491
|
+
|
443
492
|
MIN_FEE_MODE = [ :block, :relay, :send ]
|
444
493
|
|
445
494
|
NETWORKS = {
|
@@ -454,10 +503,14 @@ module Bitcoin
|
|
454
503
|
:protocol_version => 70001,
|
455
504
|
:coinbase_maturity => 100,
|
456
505
|
:retarget_interval => 2016,
|
457
|
-
:retarget_time
|
506
|
+
:retarget_time => 1209600, # 2 weeks
|
507
|
+
:target_spacing => 600, # block interval
|
458
508
|
:max_money => 21_000_000 * COIN,
|
459
509
|
:min_tx_fee => 10_000,
|
460
510
|
:min_relay_tx_fee => 10_000,
|
511
|
+
:free_tx_bytes => 1_000,
|
512
|
+
:dust => CENT,
|
513
|
+
:per_dust_fee => false,
|
461
514
|
:dns_seeds => [
|
462
515
|
"seed.bitcoin.sipa.be",
|
463
516
|
"dnsseed.bluematt.me",
|
@@ -484,9 +537,38 @@ module Bitcoin
|
|
484
537
|
210000 => "000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e",
|
485
538
|
216116 => "00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e",
|
486
539
|
225430 => "00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932",
|
540
|
+
290000 => "0000000000000000fa0b2badd05db0178623ebf8dd081fe7eb874c26e27d0b3b",
|
541
|
+
300000 => "000000000000000082ccf8f1557c5d40b21edabb18d2d691cfbf87118bac7254",
|
542
|
+
305000 => "0000000000000000142bb90561e1a907d500bf534a6727a63a92af5b6abc6160",
|
487
543
|
}
|
488
544
|
},
|
489
545
|
|
546
|
+
:regtest => {
|
547
|
+
:project => :bitcoin,
|
548
|
+
:magic_head => "\xFA\xBF\xB5\xDA",
|
549
|
+
:address_version => "6f",
|
550
|
+
:p2sh_version => "c4",
|
551
|
+
:privkey_version => "ef",
|
552
|
+
:default_port => 18444,
|
553
|
+
:max_money => 21_000_000 * COIN,
|
554
|
+
:dns_seeds => [ ],
|
555
|
+
:genesis_hash => "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206",
|
556
|
+
:proof_of_work_limit => (1<<255) - 1,
|
557
|
+
:alert_pubkeys => ["04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"],
|
558
|
+
:known_nodes => [],
|
559
|
+
:checkpoints => {},
|
560
|
+
:coinbase_maturity => 100,
|
561
|
+
:retarget_interval => 2016,
|
562
|
+
:retarget_time => 1209600, # 2 weeks
|
563
|
+
:target_spacing => 600, # block interval
|
564
|
+
:max_money => 21_000_000 * COIN,
|
565
|
+
:min_tx_fee => 10_000,
|
566
|
+
:min_relay_tx_fee => 10_000,
|
567
|
+
:free_tx_bytes => 1_000,
|
568
|
+
:dust => CENT,
|
569
|
+
:per_dust_fee => false,
|
570
|
+
},
|
571
|
+
|
490
572
|
:testnet => {
|
491
573
|
:project => :bitcoin,
|
492
574
|
:magic_head => "\xFA\xBF\xB5\xDA",
|
@@ -504,9 +586,13 @@ module Bitcoin
|
|
504
586
|
:coinbase_maturity => 100,
|
505
587
|
:retarget_interval => 2016,
|
506
588
|
:retarget_time => 1209600, # 2 weeks
|
589
|
+
:target_spacing => 600, # block interval
|
507
590
|
:max_money => 21_000_000 * COIN,
|
508
591
|
:min_tx_fee => 10_000,
|
509
592
|
:min_relay_tx_fee => 10_000,
|
593
|
+
:free_tx_bytes => 1_000,
|
594
|
+
:dust => CENT,
|
595
|
+
:per_dust_fee => false,
|
510
596
|
},
|
511
597
|
|
512
598
|
:testnet3 => {
|
@@ -520,21 +606,28 @@ module Bitcoin
|
|
520
606
|
:coinbase_maturity => 100,
|
521
607
|
:retarget_interval => 2016,
|
522
608
|
:retarget_time => 1209600, # 2 weeks
|
609
|
+
:target_spacing => 600, # block interval
|
523
610
|
:max_money => 21_000_000 * COIN,
|
524
611
|
:min_tx_fee => 10_000,
|
612
|
+
:no_difficulty => true, # no good. add right testnet3 difficulty calculation instead
|
525
613
|
:min_relay_tx_fee => 10_000,
|
614
|
+
:free_tx_bytes => 1_000,
|
615
|
+
:dust => CENT,
|
616
|
+
:per_dust_fee => false,
|
526
617
|
:dns_seeds => [
|
527
618
|
"testnet-seed.bitcoin.petertodd.org",
|
528
619
|
"testnet-seed.bluematt.me",
|
529
620
|
],
|
530
621
|
:genesis_hash => "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943",
|
531
|
-
:proof_of_work_limit =>
|
622
|
+
:proof_of_work_limit => 0x1d00ffff,
|
532
623
|
:alert_pubkeys => ["04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"],
|
533
624
|
:known_nodes => [],
|
534
625
|
:checkpoints => {
|
535
626
|
# 542 contains invalid transaction
|
536
627
|
542 => "0000000083c1f82cf72c6724f7a317325806384b06408bce7a4327f418dfd5ad",
|
537
628
|
71018 => "000000000010dd93dc55541116b2744eb8f4c3b706df6e8512d231a03fb9e435",
|
629
|
+
200000 => "0000000000287bffd321963ef05feab753ebe274e1d78b2fd4e2bfe9ad3aa6f2",
|
630
|
+
250000 => "0000000005910c146e4e8d71e8aa6617393738a9794b43cf113076dbaf08460b",
|
538
631
|
}
|
539
632
|
},
|
540
633
|
|
@@ -545,13 +638,16 @@ module Bitcoin
|
|
545
638
|
:p2sh_version => "05",
|
546
639
|
:privkey_version => "b0",
|
547
640
|
:default_port => 9333,
|
548
|
-
:protocol_version =>
|
641
|
+
:protocol_version => 70002,
|
549
642
|
:max_money => 84_000_000 * COIN,
|
550
|
-
:min_tx_fee =>
|
643
|
+
:min_tx_fee => 100_000, # 0.001 LTC
|
644
|
+
:min_relay_tx_fee => 100_000, # 0.001 LTC
|
645
|
+
:free_tx_bytes => 5_000,
|
646
|
+
:dust => CENT / 10,
|
647
|
+
:per_dust_fee => true,
|
551
648
|
:coinbase_maturity => 100,
|
552
649
|
:retarget_interval => 2016,
|
553
650
|
:retarget_time => 302400, # 3.5 days
|
554
|
-
:min_relay_tx_fee => 1_000_000,
|
555
651
|
:dns_seeds => [
|
556
652
|
"dnsseed.litecointools.com",
|
557
653
|
"dnsseed.litecoinpool.org",
|
@@ -561,7 +657,7 @@ module Bitcoin
|
|
561
657
|
],
|
562
658
|
:genesis_hash => "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2",
|
563
659
|
:proof_of_work_limit => 0,
|
564
|
-
:alert_pubkeys => [],
|
660
|
+
:alert_pubkeys => ["040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9"],
|
565
661
|
:known_nodes => [],
|
566
662
|
:checkpoints => {
|
567
663
|
1 => "80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f",
|
@@ -578,6 +674,9 @@ module Bitcoin
|
|
578
674
|
179620 => "2ad9c65c990ac00426d18e446e0fd7be2ffa69e9a7dcb28358a50b2b78b9f709",
|
579
675
|
240000 => "7140d1c4b4c2157ca217ee7636f24c9c73db39c4590c4e6eab2e3ea1555088aa",
|
580
676
|
383640 => "2b6809f094a9215bafc65eb3f110a35127a34be94b7d0590a096c3f126c6f364",
|
677
|
+
409004 => "487518d663d9f1fa08611d9395ad74d982b667fbdc0e77e9cf39b4f1355908a3",
|
678
|
+
456000 => "bf34f71cc6366cd487930d06be22f897e34ca6a40501ac7d401be32456372004",
|
679
|
+
541794 => "1cbccbe6920e7c258bbce1f26211084efb19764aa3224bec3f4320d77d6a2fd2",
|
581
680
|
}
|
582
681
|
},
|
583
682
|
|
@@ -588,22 +687,28 @@ module Bitcoin
|
|
588
687
|
:p2sh_version => "c4",
|
589
688
|
:privkey_version => "ef",
|
590
689
|
:default_port => 19333,
|
591
|
-
:protocol_version =>
|
592
|
-
:min_tx_fee =>
|
593
|
-
:min_relay_tx_fee =>
|
690
|
+
:protocol_version => 70002,
|
691
|
+
:min_tx_fee => 100_000, # 0.001 LTC
|
692
|
+
:min_relay_tx_fee => 100_000, # 0.001 LTC
|
693
|
+
:dust => CENT / 10,
|
694
|
+
:per_dust_fee => true,
|
695
|
+
:free_tx_bytes => 5_000,
|
594
696
|
:coinbase_maturity => 100,
|
595
697
|
:retarget_interval => 2016,
|
596
698
|
:retarget_time => 302400, # 3.5 days
|
597
699
|
:max_money => 84_000_000 * COIN,
|
598
700
|
:dns_seeds => [
|
599
701
|
"testnet-seed.litecointools.com",
|
702
|
+
"testnet-seed.ltc.xurious.com",
|
600
703
|
"testnet-seed.weminemnc.com",
|
601
704
|
],
|
602
705
|
:genesis_hash => "f5ae71e26c74beacc88382716aced69cddf3dffff24f384e1808905e0188f68f",
|
603
706
|
:proof_of_work_limit => 0,
|
604
|
-
:alert_pubkeys => [],
|
707
|
+
:alert_pubkeys => ["04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"],
|
605
708
|
:known_nodes => [],
|
606
|
-
:checkpoints => {
|
709
|
+
:checkpoints => {
|
710
|
+
546 => "a0fea99a6897f531600c8ae53367b126824fd6a847b2b2b73817a95b8e27e602",
|
711
|
+
}
|
607
712
|
},
|
608
713
|
|
609
714
|
|
@@ -618,6 +723,9 @@ module Bitcoin
|
|
618
723
|
:max_money => 21_000_000 * COIN,
|
619
724
|
:min_tx_fee => 50_000,
|
620
725
|
:min_relay_tx_fee => 10_000,
|
726
|
+
:free_tx_bytes => 1_000,
|
727
|
+
:dust => CENT,
|
728
|
+
:per_dust_fee => false,
|
621
729
|
:dns_seeds => [ "seed.freico.in", "fledge.freico.in" ],
|
622
730
|
:genesis_hash => "000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c",
|
623
731
|
:proof_of_work_limit => 0,
|
@@ -638,6 +746,9 @@ module Bitcoin
|
|
638
746
|
:max_money => 21_000_000 * COIN,
|
639
747
|
:min_tx_fee => 50_000,
|
640
748
|
:min_relay_tx_fee => 10_000,
|
749
|
+
:free_tx_bytes => 1_000,
|
750
|
+
:dust => CENT,
|
751
|
+
:per_dust_fee => true,
|
641
752
|
:dns_seeds => [],
|
642
753
|
:genesis_hash => "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770",
|
643
754
|
:proof_of_work_limit => 0x1d00ffff,
|
@@ -648,6 +759,7 @@ module Bitcoin
|
|
648
759
|
19200 => "d8a7c3e01e1e95bcee015e6fcc7583a2ca60b79e5a3aa0a171eddd344ada903d",
|
649
760
|
24000 => "425ab0983cf04f43f346a4ca53049d0dc2db952c0a68eb0b55c3bb64108d5371",
|
650
761
|
97778 => "7553b1e43da01cfcda4335de1caf623e941d43894bd81c2af27b6582f9d83c6f",
|
762
|
+
165000 => "823d7a54ebab04d14c4ba3508f6b5f25977406f4d389539eac0174d52c6b4b62",
|
651
763
|
}
|
652
764
|
},
|
653
765
|
|
@@ -659,6 +771,9 @@ module Bitcoin
|
|
659
771
|
:protocol_version => 35000,
|
660
772
|
:min_tx_fee => 50_000,
|
661
773
|
:min_relay_tx_fee => 10_000,
|
774
|
+
:free_tx_bytes => 1_000,
|
775
|
+
:dust => CENT,
|
776
|
+
:per_dust_fee => true,
|
662
777
|
:max_money => 21_000_000 * COIN,
|
663
778
|
:dns_seeds => [],
|
664
779
|
:genesis_hash => "00000001f8ab0d14bceaeb50d163b0bef15aecf62b87bd5f5c864d37f201db97",
|
data/lib/bitcoin/builder.rb
CHANGED
@@ -18,10 +18,10 @@ module Bitcoin
|
|
18
18
|
|
19
19
|
# build a Bitcoin::Protocol::Tx.
|
20
20
|
# see TxBuilder for details.
|
21
|
-
def build_tx
|
21
|
+
def build_tx opts = {}
|
22
22
|
c = TxBuilder.new
|
23
23
|
yield c
|
24
|
-
c.tx
|
24
|
+
c.tx opts
|
25
25
|
end
|
26
26
|
alias :tx :build_tx
|
27
27
|
|
@@ -40,13 +40,12 @@ module Bitcoin
|
|
40
40
|
# t.input {|i| i.coinbase }
|
41
41
|
# t.output do |o|
|
42
42
|
# o.value 5000000000;
|
43
|
-
# o.
|
44
|
-
# s.type :address
|
45
|
-
# s.recipient Bitcoin::Key.generate.addr
|
46
|
-
# end
|
43
|
+
# o.to Bitcoin::Key.generate.addr
|
47
44
|
# end
|
48
45
|
# end
|
49
46
|
# end
|
47
|
+
#
|
48
|
+
# See Bitcoin::Builder::TxBuilder for details on building transactions.
|
50
49
|
class BlockBuilder
|
51
50
|
|
52
51
|
def initialize
|
@@ -69,10 +68,10 @@ module Bitcoin
|
|
69
68
|
end
|
70
69
|
|
71
70
|
# add transactions to the block (see TxBuilder).
|
72
|
-
def tx
|
73
|
-
c = TxBuilder.new
|
74
|
-
|
75
|
-
|
71
|
+
def tx tx = nil
|
72
|
+
tx ||= ( c = TxBuilder.new; yield c; c.tx )
|
73
|
+
@block.tx << tx
|
74
|
+
tx
|
76
75
|
end
|
77
76
|
|
78
77
|
# create the block according to values specified via DSL.
|
@@ -117,18 +116,20 @@ module Bitcoin
|
|
117
116
|
# DSL to create Bitcoin::Protocol::Tx used by Builder#build_tx.
|
118
117
|
# tx = tx do |t|
|
119
118
|
# t.input do |i|
|
120
|
-
# i.prev_out prev_tx
|
121
|
-
# i.
|
122
|
-
# i.signature_key key # Bitcoin::Key used to sign the input
|
119
|
+
# i.prev_out prev_tx, 0
|
120
|
+
# i.signature_key key
|
123
121
|
# end
|
124
122
|
# t.output do |o|
|
125
123
|
# o.value 12345 # 0.00012345 BTC
|
126
|
-
# o.
|
124
|
+
# o.to key.addr
|
127
125
|
# end
|
128
126
|
# end
|
129
127
|
#
|
130
|
-
#
|
131
|
-
#
|
128
|
+
# Signs every input that has a signature key and where the previous outputs
|
129
|
+
# pk_script is known. If unable to sign, the resulting txin will include
|
130
|
+
# the #sig_hash that needs to be signed.
|
131
|
+
#
|
132
|
+
# See TxInBuilder and TxOutBuilder for details on how to build in/outputs.
|
132
133
|
class TxBuilder
|
133
134
|
|
134
135
|
def initialize
|
@@ -161,64 +162,202 @@ module Bitcoin
|
|
161
162
|
@outs << c
|
162
163
|
end
|
163
164
|
|
164
|
-
#
|
165
|
-
#
|
165
|
+
# Create the transaction according to values specified via DSL.
|
166
|
+
# Sign each input that has a signature key specified. If there is
|
166
167
|
# no key, store the sig_hash in the input, so it can easily be
|
167
168
|
# signed later.
|
168
|
-
|
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
|
+
if opts[:change_address] && !opts[:input_value]
|
177
|
+
raise "Must give 'input_value' when auto-generating change output!"
|
178
|
+
end
|
169
179
|
@ins.each {|i| @tx.add_in(i.txin) }
|
170
180
|
@outs.each {|o| @tx.add_out(o.txout) }
|
181
|
+
|
182
|
+
if opts[:change_address]
|
183
|
+
output_value = @tx.out.map(&:value).inject(:+)
|
184
|
+
change_value = opts[:input_value] - output_value
|
185
|
+
if opts[:leave_fee]
|
186
|
+
if change_value >= @tx.minimum_block_fee
|
187
|
+
change_value -= @tx.minimum_block_fee
|
188
|
+
else
|
189
|
+
change_value = 0
|
190
|
+
end
|
191
|
+
end
|
192
|
+
if change_value > 0
|
193
|
+
script = Script.to_address_script(opts[:change_address])
|
194
|
+
@tx.add_out(P::TxOut.new(change_value, script))
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
171
198
|
@ins.each_with_index do |inc, i|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
199
|
+
sign_input(i, inc)
|
200
|
+
end
|
201
|
+
|
202
|
+
# run our tx through an encode/decode cycle to make sure that the binary format is sane
|
203
|
+
raise "Payload Error" unless P::Tx.new(@tx.to_payload).to_payload == @tx.to_payload
|
204
|
+
@tx.instance_eval do
|
205
|
+
@payload = to_payload
|
206
|
+
@hash = hash_from_payload(@payload)
|
207
|
+
end
|
208
|
+
|
209
|
+
@tx
|
210
|
+
end
|
211
|
+
|
212
|
+
# coinbase inputs don't need to be signed, they only include the given +coinbase_data+
|
213
|
+
def include_coinbase_data i, inc
|
214
|
+
script_sig = [inc.coinbase_data].pack("H*")
|
215
|
+
@tx.in[i].script_sig_length = script_sig.bytesize
|
216
|
+
@tx.in[i].script_sig = script_sig
|
217
|
+
end
|
218
|
+
|
219
|
+
def sig_hash_and_all_keys_exist?(inc, sig_script)
|
220
|
+
return false unless @sig_hash && inc.has_keys?
|
221
|
+
script = Bitcoin::Script.new(sig_script)
|
222
|
+
return true if script.is_hash160? || script.is_pubkey?
|
223
|
+
if script.is_multisig?
|
224
|
+
return inc.has_multiple_keys? && inc.key.size >= script.get_signatures_required
|
225
|
+
end
|
226
|
+
raise "Script type must be hash160, pubkey or multisig"
|
227
|
+
end
|
228
|
+
|
229
|
+
def add_empty_script_sig_to_input(i)
|
230
|
+
@tx.in[i].script_sig_length = 0
|
231
|
+
@tx.in[i].script_sig = ""
|
232
|
+
# add the sig_hash that needs to be signed, so it can be passed on to a signing device
|
233
|
+
@tx.in[i].sig_hash = @sig_hash
|
234
|
+
# add the address the sig_hash needs to be signed with as a convenience for the signing device
|
235
|
+
@tx.in[i].sig_address = Script.new(@prev_script).get_address if @prev_script
|
236
|
+
end
|
237
|
+
|
238
|
+
def get_script_sig(inc)
|
239
|
+
if inc.has_multiple_keys?
|
240
|
+
# multiple keys given, generate signature for each one
|
241
|
+
sigs = inc.sign(@sig_hash)
|
242
|
+
if redeem_script = inc.instance_eval { @redeem_script }
|
243
|
+
# when a redeem_script was specified, assume we spend a p2sh multisig script
|
244
|
+
script_sig = Script.to_p2sh_multisig_script_sig(redeem_script, sigs)
|
245
|
+
else
|
246
|
+
# when no redeem_script is given, do a regular multisig spend
|
247
|
+
script_sig = Script.to_multisig_script_sig(*sigs)
|
177
248
|
end
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
249
|
+
else
|
250
|
+
# only one key given, generate signature and script_sig
|
251
|
+
sig = inc.sign(@sig_hash)
|
252
|
+
script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack("H*"))
|
253
|
+
end
|
254
|
+
return script_sig
|
255
|
+
end
|
256
|
+
|
257
|
+
# Sign input number +i+ with data from given +inc+ object (a TxInBuilder).
|
258
|
+
def sign_input i, inc
|
259
|
+
if @tx.in[i].coinbase?
|
260
|
+
include_coinbase_data(i, inc)
|
261
|
+
else
|
262
|
+
@prev_script = inc.instance_variable_get(:@prev_out_script)
|
263
|
+
|
264
|
+
# get the signature script; use +redeem_script+ if given
|
265
|
+
# (indicates spending a p2sh output), otherwise use the prev_script
|
266
|
+
sig_script = inc.instance_eval { @redeem_script }
|
267
|
+
sig_script ||= @prev_script
|
268
|
+
|
269
|
+
# when a sig_script was found, generate the sig_hash to be signed
|
270
|
+
@sig_hash = @tx.signature_hash_for_input(i, sig_script) if sig_script
|
271
|
+
|
272
|
+
# when there is a sig_hash and one or more signature_keys were specified
|
273
|
+
if sig_hash_and_all_keys_exist?(inc, sig_script)
|
274
|
+
# add the script_sig to the txin
|
275
|
+
@tx.in[i].script_sig = get_script_sig(inc)
|
276
|
+
|
277
|
+
# double-check that the script_sig is valid to spend the given prev_script
|
278
|
+
raise "Signature error" if @prev_script && !@tx.verify_input_signature(i, @prev_script)
|
279
|
+
elsif inc.has_multiple_keys?
|
280
|
+
raise "Keys missing for multisig signing"
|
186
281
|
else
|
187
|
-
|
188
|
-
|
189
|
-
@tx.in[i].sig_hash = @sig_hash
|
190
|
-
@tx.in[i].sig_address = Script.new(prev_tx.out[@tx.in[i].prev_out_index].pk_script).get_address
|
282
|
+
# no sig_hash, add an empty script_sig.
|
283
|
+
add_empty_script_sig_to_input(i)
|
191
284
|
end
|
192
285
|
end
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
286
|
+
end
|
287
|
+
|
288
|
+
# Randomize the outputs using SecureRandom
|
289
|
+
def randomize_outputs
|
290
|
+
@outs.sort_by!{ SecureRandom.random_bytes(4).unpack("I")[0] }
|
198
291
|
end
|
199
292
|
end
|
200
293
|
|
201
|
-
#
|
294
|
+
# Create a Bitcoin::Protocol::TxIn used by TxBuilder#input.
|
295
|
+
#
|
296
|
+
# Inputs need the transaction hash and the index of the output they spend.
|
297
|
+
# You can pass either the transaction, or just its hash (in hex form).
|
298
|
+
# To sign the input, builder also needs the pk_script of the previous output.
|
299
|
+
# If you specify a tx hash instead of the whole tx, you need to specify the
|
300
|
+
# output script separately.
|
301
|
+
#
|
302
|
+
# t.input do |i|
|
303
|
+
# i.prev_out prev_tx # previous transaction
|
304
|
+
# i.prev_out_index 0 # index of previous output
|
305
|
+
# i.signature_key key # Bitcoin::Key used to sign the input
|
306
|
+
# end
|
307
|
+
#
|
308
|
+
# t.input {|i| i.prev_out prev_tx, 0 }
|
202
309
|
#
|
203
|
-
#
|
310
|
+
# If you want to spend a p2sh output, you also need to specify the +redeem_script+.
|
311
|
+
#
|
312
|
+
# t.input do |i|
|
313
|
+
# i.prev_out prev_tx, 0
|
314
|
+
# i.redeem_script prev_out.redeem_script
|
315
|
+
# end
|
316
|
+
#
|
317
|
+
# If you want to spend a multisig output, just provide an array of keys to #signature_key.
|
204
318
|
class TxInBuilder
|
205
|
-
attr_reader :key, :coinbase_data
|
319
|
+
attr_reader :prev_tx, :prev_script, :redeem_script, :key, :coinbase_data
|
206
320
|
|
207
321
|
def initialize
|
208
322
|
@txin = P::TxIn.new
|
323
|
+
@prev_out_hash = "\x00" * 32
|
324
|
+
@prev_out_index = 0
|
209
325
|
end
|
210
326
|
|
211
|
-
#
|
212
|
-
|
213
|
-
|
327
|
+
# Previous transaction that contains the output we want to use.
|
328
|
+
# You can either pass the transaction, or just the tx hash.
|
329
|
+
# If you pass only the hash, you need to pass the previous outputs
|
330
|
+
# +script+ separately if you want the txin to be signed.
|
331
|
+
def prev_out tx, idx = nil, script = nil
|
332
|
+
if tx.is_a?(Bitcoin::P::Tx)
|
333
|
+
@prev_tx = tx
|
334
|
+
@prev_out_hash = tx.binary_hash
|
335
|
+
@prev_out_script = tx.out[idx].pk_script if idx
|
336
|
+
else
|
337
|
+
@prev_out_hash = tx.htb.reverse
|
338
|
+
end
|
339
|
+
@prev_out_script = script if script
|
340
|
+
@prev_out_index = idx if idx
|
214
341
|
end
|
215
342
|
|
216
|
-
#
|
343
|
+
# Index of the output in the #prev_out transaction.
|
217
344
|
def prev_out_index i
|
218
345
|
@prev_out_index = i
|
346
|
+
@prev_out_script = @prev_tx.out[i].pk_script if @prev_tx
|
219
347
|
end
|
220
348
|
|
221
|
-
#
|
349
|
+
# Previous output's +pk_script+. Needed when only the tx hash is specified as #prev_out.
|
350
|
+
def prev_out_script script
|
351
|
+
@prev_out_script = script
|
352
|
+
end
|
353
|
+
|
354
|
+
# Redeem script for P2SH output. To spend from a P2SH output, you need to provide
|
355
|
+
# the script with a hash matching the P2SH address.
|
356
|
+
def redeem_script script
|
357
|
+
@redeem_script = script
|
358
|
+
end
|
359
|
+
|
360
|
+
# Specify sequence. This is usually not needed.
|
222
361
|
def sequence s
|
223
362
|
@sequence = s
|
224
363
|
end
|
@@ -229,44 +368,70 @@ module Bitcoin
|
|
229
368
|
@key = key
|
230
369
|
end
|
231
370
|
|
232
|
-
#
|
371
|
+
# Specify that this is a coinbase input. Optionally set +data+.
|
372
|
+
# If this is set, no other options need to be given.
|
233
373
|
def coinbase data = nil
|
234
374
|
@coinbase_data = data || OpenSSL::Random.random_bytes(32)
|
235
|
-
@
|
375
|
+
@prev_out_hash = "\x00" * 32
|
236
376
|
@prev_out_index = 4294967295
|
237
377
|
end
|
238
378
|
|
239
|
-
#
|
379
|
+
# Create the txin according to specified values
|
240
380
|
def txin
|
241
|
-
@txin.prev_out =
|
381
|
+
@txin.prev_out = @prev_out_hash
|
242
382
|
@txin.prev_out_index = @prev_out_index
|
243
383
|
@txin.sequence = @sequence || "\xff\xff\xff\xff"
|
244
384
|
@txin
|
245
385
|
end
|
386
|
+
|
387
|
+
def has_multiple_keys?
|
388
|
+
@key.is_a?(Array)
|
389
|
+
end
|
390
|
+
|
391
|
+
def has_keys?
|
392
|
+
@key && (has_multiple_keys? ? @key.all?(&:priv) : @key.priv)
|
393
|
+
end
|
394
|
+
|
395
|
+
def sign(sig_hash)
|
396
|
+
if has_multiple_keys?
|
397
|
+
@key.map {|k| k.sign(sig_hash) }
|
398
|
+
else
|
399
|
+
@key.sign(sig_hash)
|
400
|
+
end
|
401
|
+
end
|
246
402
|
end
|
247
403
|
|
248
|
-
#
|
404
|
+
# Create a Bitcoin::Script used by TxOutBuilder#script.
|
249
405
|
class ScriptBuilder
|
250
|
-
attr_reader :script
|
406
|
+
attr_reader :script, :redeem_script
|
251
407
|
|
252
408
|
def initialize
|
253
409
|
@type = :address
|
254
410
|
@script = nil
|
255
411
|
end
|
256
412
|
|
257
|
-
#
|
413
|
+
# Script type (:pubkey, :address/hash160, :multisig).
|
414
|
+
# Defaults to :address.
|
258
415
|
def type type
|
259
416
|
@type = type.to_sym
|
260
417
|
end
|
261
418
|
|
262
|
-
#
|
263
|
-
#
|
419
|
+
# Recipient(s) of the script.
|
420
|
+
# Depending on the #type, this should be an address, a hash160 pubkey,
|
421
|
+
# or an array of multisig pubkeys.
|
264
422
|
def recipient *data
|
265
|
-
@script = Script.send("to_#{@type}_script", *data)
|
423
|
+
@script, @redeem_script = *Script.send("to_#{@type}_script", *data)
|
266
424
|
end
|
267
425
|
end
|
268
426
|
|
269
|
-
#
|
427
|
+
# Create a Bitcoin::Protocol::TxOut used by TxBuilder#output.
|
428
|
+
#
|
429
|
+
# t.output {|o| o.value 12345; o.to address }
|
430
|
+
#
|
431
|
+
# t.output do |o|
|
432
|
+
# o.value 12345
|
433
|
+
# o.script {|s| s.recipient address }
|
434
|
+
# end
|
270
435
|
class TxOutBuilder
|
271
436
|
attr_reader :txout
|
272
437
|
|
@@ -274,16 +439,21 @@ module Bitcoin
|
|
274
439
|
@txout = P::TxOut.new
|
275
440
|
end
|
276
441
|
|
277
|
-
#
|
442
|
+
# Set output value (in base units / "satoshis")
|
278
443
|
def value value
|
279
444
|
@txout.value = value
|
280
445
|
end
|
281
446
|
|
282
|
-
#
|
447
|
+
# Set recipient address and script type (defaults to :address).
|
448
|
+
def to recipient, type = :address
|
449
|
+
@txout.pk_script, @txout.redeem_script = *Bitcoin::Script.send("to_#{type}_script", *recipient)
|
450
|
+
end
|
451
|
+
|
452
|
+
# Add a script to the output (see ScriptBuilder).
|
283
453
|
def script &block
|
284
454
|
c = ScriptBuilder.new
|
285
455
|
yield c
|
286
|
-
@txout.pk_script = c.script
|
456
|
+
@txout.pk_script, @txout.redeem_script = c.script, c.redeem_script
|
287
457
|
end
|
288
458
|
|
289
459
|
end
|