bitcoin-ruby 0.0.5 → 0.0.6
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.
- 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
|