bitcoin-ruby 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +2 -7
  4. data/COPYING +1 -1
  5. data/Gemfile +2 -6
  6. data/Gemfile.lock +34 -0
  7. data/README.rdoc +16 -68
  8. data/Rakefile +3 -6
  9. data/bin/bitcoin_shell +0 -1
  10. data/{concept-examples/blockchain-pow.rb → examples/concept-blockchain-pow.rb} +0 -0
  11. data/lib/bitcoin.rb +350 -296
  12. data/lib/bitcoin/builder.rb +3 -1
  13. data/lib/bitcoin/connection.rb +2 -1
  14. data/lib/bitcoin/contracthash.rb +76 -0
  15. data/lib/bitcoin/dogecoin.rb +97 -0
  16. data/lib/bitcoin/ffi/bitcoinconsensus.rb +74 -0
  17. data/lib/bitcoin/ffi/openssl.rb +98 -2
  18. data/lib/bitcoin/ffi/secp256k1.rb +144 -0
  19. data/lib/bitcoin/key.rb +12 -2
  20. data/lib/bitcoin/logger.rb +3 -12
  21. data/lib/bitcoin/protocol/block.rb +3 -9
  22. data/lib/bitcoin/protocol/parser.rb +6 -2
  23. data/lib/bitcoin/protocol/tx.rb +44 -13
  24. data/lib/bitcoin/protocol/txin.rb +4 -2
  25. data/lib/bitcoin/protocol/txout.rb +2 -2
  26. data/lib/bitcoin/script.rb +212 -37
  27. data/lib/bitcoin/trezor/mnemonic.rb +130 -0
  28. data/lib/bitcoin/version.rb +1 -1
  29. data/spec/bitcoin/bitcoin_spec.rb +32 -3
  30. data/spec/bitcoin/builder_spec.rb +18 -0
  31. data/spec/bitcoin/contracthash_spec.rb +45 -0
  32. data/spec/bitcoin/dogecoin_spec.rb +176 -0
  33. data/spec/bitcoin/ffi_openssl.rb +45 -0
  34. data/spec/bitcoin/fixtures/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +24 -0
  35. data/spec/bitcoin/fixtures/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +24 -0
  36. data/spec/bitcoin/fixtures/coinbase-toshi.json +33 -0
  37. data/spec/bitcoin/fixtures/coinbase.json +24 -0
  38. data/spec/bitcoin/fixtures/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
  39. data/spec/bitcoin/fixtures/rawtx-01-toshi.json +46 -0
  40. data/spec/bitcoin/fixtures/rawtx-02-toshi.json +46 -0
  41. data/spec/bitcoin/fixtures/rawtx-03-toshi.json +73 -0
  42. data/spec/bitcoin/fixtures/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
  43. data/spec/bitcoin/fixtures/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
  44. data/spec/bitcoin/fixtures/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
  45. data/spec/bitcoin/fixtures/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
  46. data/spec/bitcoin/fixtures/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
  47. data/spec/bitcoin/fixtures/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
  48. data/spec/bitcoin/protocol/block_spec.rb +0 -22
  49. data/spec/bitcoin/protocol/tx_spec.rb +145 -2
  50. data/spec/bitcoin/script/script_spec.rb +282 -0
  51. data/spec/bitcoin/secp256k1_spec.rb +48 -0
  52. data/spec/bitcoin/spec_helper.rb +0 -51
  53. data/spec/bitcoin/trezor/mnemonic_spec.rb +161 -0
  54. metadata +48 -98
  55. data/bin/bitcoin_dns_seed +0 -130
  56. data/bin/bitcoin_gui +0 -80
  57. data/bin/bitcoin_node +0 -153
  58. data/bin/bitcoin_node_cli +0 -81
  59. data/bin/bitcoin_wallet +0 -402
  60. data/doc/CONFIG.rdoc +0 -66
  61. data/doc/EXAMPLES.rdoc +0 -13
  62. data/doc/NAMECOIN.rdoc +0 -34
  63. data/doc/NODE.rdoc +0 -225
  64. data/doc/STORAGE.rdoc +0 -33
  65. data/doc/WALLET.rdoc +0 -102
  66. data/examples/balance.rb +0 -66
  67. data/examples/forwarder.rb +0 -73
  68. data/examples/index_nhash.rb +0 -24
  69. data/examples/reindex_p2sh_addrs.rb +0 -44
  70. data/examples/relay_tx.rb +0 -22
  71. data/examples/verify_tx.rb +0 -57
  72. data/lib/bitcoin/config.rb +0 -58
  73. data/lib/bitcoin/gui/addr_view.rb +0 -44
  74. data/lib/bitcoin/gui/bitcoin-ruby.png +0 -0
  75. data/lib/bitcoin/gui/bitcoin-ruby.svg +0 -80
  76. data/lib/bitcoin/gui/conn_view.rb +0 -38
  77. data/lib/bitcoin/gui/connection.rb +0 -70
  78. data/lib/bitcoin/gui/em_gtk.rb +0 -30
  79. data/lib/bitcoin/gui/gui.builder +0 -1643
  80. data/lib/bitcoin/gui/gui.rb +0 -292
  81. data/lib/bitcoin/gui/helpers.rb +0 -115
  82. data/lib/bitcoin/gui/tree_view.rb +0 -84
  83. data/lib/bitcoin/gui/tx_view.rb +0 -69
  84. data/lib/bitcoin/namecoin.rb +0 -280
  85. data/lib/bitcoin/network/command_client.rb +0 -104
  86. data/lib/bitcoin/network/command_handler.rb +0 -570
  87. data/lib/bitcoin/network/connection_handler.rb +0 -387
  88. data/lib/bitcoin/network/node.rb +0 -565
  89. data/lib/bitcoin/storage/dummy/dummy_store.rb +0 -179
  90. data/lib/bitcoin/storage/models.rb +0 -171
  91. data/lib/bitcoin/storage/sequel/migrations.rb +0 -99
  92. data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +0 -52
  93. data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +0 -45
  94. data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +0 -18
  95. data/lib/bitcoin/storage/sequel/migrations/004_change_txin_prev_out_to_blob.rb +0 -18
  96. data/lib/bitcoin/storage/sequel/migrations/005_change_tx_hash_to_bytea.rb +0 -14
  97. data/lib/bitcoin/storage/sequel/migrations/006_add_tx_nhash.rb +0 -31
  98. data/lib/bitcoin/storage/sequel/migrations/007_add_prev_out_index_index.rb +0 -16
  99. data/lib/bitcoin/storage/sequel/migrations/008_add_txin_p2sh_type.rb +0 -31
  100. data/lib/bitcoin/storage/sequel/migrations/009_add_addrs_type.rb +0 -56
  101. data/lib/bitcoin/storage/sequel/sequel_store.rb +0 -551
  102. data/lib/bitcoin/storage/storage.rb +0 -517
  103. data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +0 -52
  104. data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +0 -18
  105. data/lib/bitcoin/storage/utxo/migrations/003_update_indices.rb +0 -14
  106. data/lib/bitcoin/storage/utxo/migrations/004_add_addrs_type.rb +0 -14
  107. data/lib/bitcoin/storage/utxo/utxo_store.rb +0 -374
  108. data/lib/bitcoin/validation.rb +0 -400
  109. data/lib/bitcoin/wallet/coinselector.rb +0 -33
  110. data/lib/bitcoin/wallet/keygenerator.rb +0 -77
  111. data/lib/bitcoin/wallet/keystore.rb +0 -207
  112. data/lib/bitcoin/wallet/txdp.rb +0 -118
  113. data/lib/bitcoin/wallet/wallet.rb +0 -281
  114. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
  115. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +0 -43
  116. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
  117. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +0 -67
  118. data/spec/bitcoin/namecoin_spec.rb +0 -182
  119. data/spec/bitcoin/node/command_api_spec.rb +0 -663
  120. data/spec/bitcoin/storage/models_spec.rb +0 -104
  121. data/spec/bitcoin/storage/reorg_spec.rb +0 -236
  122. data/spec/bitcoin/storage/storage_spec.rb +0 -387
  123. data/spec/bitcoin/storage/validation_spec.rb +0 -300
  124. data/spec/bitcoin/wallet/coinselector_spec.rb +0 -38
  125. data/spec/bitcoin/wallet/keygenerator_spec.rb +0 -69
  126. data/spec/bitcoin/wallet/keystore_spec.rb +0 -190
  127. data/spec/bitcoin/wallet/txdp_spec.rb +0 -76
  128. data/spec/bitcoin/wallet/wallet_spec.rb +0 -238
@@ -1,153 +0,0 @@
1
- #!/usr/bin/env ruby
2
- $:.unshift( File.expand_path("../../lib", __FILE__) )
3
-
4
- require 'bitcoin'
5
- require 'optparse'
6
- require 'fileutils'
7
- Bitcoin.require_dependency :eventmachine
8
- Bitcoin.require_dependency :json
9
-
10
- defaults = Bitcoin::Network::Node::DEFAULT_CONFIG
11
-
12
- options = Bitcoin::Config.load(defaults, :blockchain)
13
-
14
- optparse = OptionParser.new do |opts|
15
- opts.banner = "Usage: bitcoin_node [options]"
16
-
17
- opts.separator("\nAvailable options:\n")
18
-
19
- opts.on("-c", "--config FILE",
20
- "Config file (default: #{Bitcoin::Config::CONFIG_PATHS})") do |file|
21
- options = Bitcoin::Config.load_file(options, file, :blockchain)
22
- end
23
-
24
- opts.on("-n", "--network [NETWORK]",
25
- "User Network (default: #{options[:network]})") do |network|
26
- options[:network] = network
27
- end
28
-
29
- opts.on("--command [HOST:PORT]",
30
- "Command socket (default: #{options[:command].join(':')})") do |command|
31
- options[:command] = command.split(":")
32
- end
33
-
34
- opts.on("-l", "--listen [HOST:PORT]",
35
- "Listen address/port (default: #{options[:listen].join(':')})") do |listen|
36
- options[:listen] = listen.split(":")
37
- end
38
-
39
- opts.on("--connect [HOST:PORT]",
40
- "Hosts to connect to (default: #{options[:connect].map{|c|c.join(':')}.join(',')})") do |connect|
41
- connect.split(",").each do |host|
42
- options[:connect] << host.split(":")
43
- end
44
- end
45
-
46
- opts.on("-a", "--announce",
47
- "Announce our own address to the network, so we will get incoming connections.") do
48
- options[:announce] = true
49
- end
50
-
51
- opts.on("--external-port PORT",
52
- "Specify external port that can be used to reach this node (uses local port otherwise).") do |port|
53
- options[:external_port] = port.to_i
54
- end
55
-
56
- opts.on("-s", "--storage [BACKEND::CONFIG]",
57
- "Use storage backend (default: #{options[:storage]})") do |storage|
58
- options[:storage] = storage
59
- end
60
-
61
- opts.on("--skip-validation", "Skip validation of blocks and transactions") do
62
- options[:skip_validation] = true
63
- end
64
-
65
- opts.on("--check-blocks COUNT",
66
- "Check consistency of COUNT latest blocks; -1 for all (default: 1000)") do |check|
67
- options[:check_blocks] = check.to_i
68
- end
69
-
70
- opts.on("--ho", "--headers-only",
71
- "Download only block headers") do
72
- options[:headers_only] = true
73
- end
74
-
75
- opts.on("-d", "--dns", "Use DNS seeds (default)") do
76
- options[:dns] = true
77
- end
78
-
79
- opts.on("--nd", "--no-dns", "Don't use DNS seeds") do
80
- options[:dns] = false
81
- end
82
-
83
- opts.on("--epoll", "Enable epoll support") do
84
- options[:epoll] = true
85
- end
86
-
87
- opts.on("--epoll-limit [NUM]",
88
- "Increase socket descriptor limit to NUM") do |num|
89
- options[:epoll_limit] = num.to_i
90
- end
91
-
92
- opts.on("--epoll-user [NAME]",
93
- "Set effective user after increasing socket descriptor limit") do |user|
94
- options[:epoll_user] = user
95
- end
96
-
97
- opts.on("--mco", "--max-connections-out COUNT", "Maximum number of outgoing connections (default: #{options[:max][:connections_out]})") do |count|
98
- options[:max][:connections_out] = count.to_i
99
- end
100
-
101
- opts.on("--mci", "--max-connections-in COUNT", "Maximum number of incoming connections (default: #{options[:max][:connections_in]})") do |count|
102
- options[:max][:connections_in] = count.to_i
103
- end
104
-
105
- [:addr, :queue, :inv, :unconfirmed].each do |name|
106
- opts.on("--m#{name.to_s[0]}", "--max-#{name} [COUNT]",
107
- "Max #{name} (default: #{options[:max][name]})") do |count|
108
- options[:max][name] = count.to_i
109
- end
110
- end
111
-
112
- [:queue, :inv_queue, :blocks, :addrs, :connect].each do |name|
113
- opts.on("--i#{name.to_s[0]}", "--interval-#{name} [SECONDS]",
114
- "Interval for #{name} worker (default: #{options[:intervals][name]})") do |sec|
115
- options[:intervals][name] = sec.to_i
116
- end
117
- end
118
-
119
- [:network, :storage].each do |name|
120
- opts.on("--l#{name.to_s[0]}", "--log-#{name} [LEVEL]",
121
- "Log level for #{name} (default: #{options[:log][name]})") do |level|
122
- options[:log][name] = level.to_sym
123
- end
124
- end
125
-
126
- opts.on("--import DIR", "Import blk*.dat files from DIR") do |dir|
127
- options[:import] = dir
128
- end
129
-
130
- opts.on("-v", "--verbose", "Set all loggers to debug") do
131
- options[:log].each_key {|k| options[:log][k] = :debug }
132
- end
133
-
134
- opts.on("-q", "--quiet", "Set all loggers to warn") do
135
- options[:log].each_key {|k| options[:log][k] = :warn }
136
- end
137
-
138
- opts.on( '-h', '--help', 'Display this screen' ) do
139
- puts opts; exit
140
- end
141
- end
142
-
143
- optparse.parse!
144
-
145
- Bitcoin.network = options[:network]
146
- FileUtils.mkdir_p File.join(ENV['HOME'], ".bitcoin-ruby/#{Bitcoin.network_name}")
147
-
148
- if ARGV.any?
149
- system(File.join(File.dirname(__FILE__), "bitcoin_node_cli"), *ARGV)
150
- else
151
- node = Bitcoin::Network::Node.new(options)
152
- node.run
153
- end
@@ -1,81 +0,0 @@
1
- #!/usr/bin/env ruby
2
- $:.unshift( File.expand_path("../../lib", __FILE__) )
3
-
4
- require 'bitcoin'
5
- require 'optparse'
6
- require 'fileutils'
7
- Bitcoin.require_dependency :eventmachine
8
- Bitcoin.require_dependency :json
9
-
10
- defaults = Bitcoin::Network::Node::DEFAULT_CONFIG
11
-
12
- options = Bitcoin::Config.load(defaults, :blockchain)
13
-
14
- optparse = OptionParser.new do |opts|
15
- opts.banner = "Usage: bitcoin_node [options]"
16
-
17
- opts.separator("\nAvailable options:\n")
18
-
19
- opts.on("-c", "--config FILE",
20
- "Config file (default: #{Bitcoin::Config::CONFIG_PATHS})") do |file|
21
- options = Bitcoin::Config.load_file(options, file, :blockchain)
22
- end
23
-
24
- opts.on("-n", "--network [NETWORK]",
25
- "User Network (default: #{options[:network]})") do |network|
26
- options[:network] = network
27
- end
28
-
29
- opts.on("--command [HOST:PORT]",
30
- "Command socket (default: #{options[:command].join(':')})") do |command|
31
- options[:command] = command.split(":")
32
- end
33
-
34
- opts.on( '-h', '--help', 'Display this screen' ) do
35
- puts opts; exit
36
- end
37
- end
38
-
39
- optparse.parse!
40
-
41
- Bitcoin.network = options[:network]
42
- FileUtils.mkdir_p File.join(ENV['HOME'], ".bitcoin-ruby/#{Bitcoin.network_name}")
43
-
44
- EM.run do
45
- Bitcoin::Network::CommandClient.connect(*options[:command]) do
46
- on_response do |cmd, data|
47
- unless cmd == "monitor"
48
- puts JSON.pretty_generate data
49
- EM.stop
50
- end
51
- end
52
- on_block do |block, depth|
53
- hash = Bitcoin::P::Block.new(block['hex'].htb).to_hash.merge("depth" => block['depth'])
54
- puts JSON.pretty_generate(hash)
55
- end
56
- on_tx do |tx, confirmations|
57
- hash = Bitcoin::P::Tx.new(tx['hex'].htb).to_hash.merge("nhash" => tx['nhash'], "conf" => tx['conf'])
58
- puts JSON.pretty_generate(hash)
59
- end
60
- on_output do |data|
61
- puts JSON.pretty_generate(data)
62
- end
63
- on_connection do |data|
64
- p data
65
- end
66
- on_connected do
67
- cmd, params = ARGV.shift, Hash[ARGV.map {|a| a.split("=") }]
68
- case cmd
69
- when "create_tx"
70
- params["keys"] = JSON.parse(params["keys"])
71
- params["recipients"] = JSON.parse(params["recipients"])
72
- when "assemble_tx"
73
- params["sig_pubs"] = JSON.parse(params["sig_pubs"])
74
- when "monitor"
75
- params["addresses"] = JSON.parse(params["addresses"]) if params["addresses"]
76
- $stdout.sync = true
77
- end
78
- request(cmd, params)
79
- end
80
- end
81
- end
@@ -1,402 +0,0 @@
1
- #!/usr/bin/env ruby
2
- $:.unshift( File.expand_path("../../lib", __FILE__) )
3
-
4
- require 'bitcoin'
5
- require 'eventmachine'
6
- require 'optparse'
7
- require 'yaml'
8
-
9
- defaults = {
10
- :network => "testnet",
11
- :storage => nil,
12
- :keystore => nil,
13
- :command => "127.0.0.1:9999"
14
- }
15
- options = Bitcoin::Config.load(defaults, :wallet)
16
-
17
- optparse = OptionParser.new do |opts|
18
- opts.banner =
19
- "Usage: bitcoin_wallet [options] <command> [<command options>]\n"
20
-
21
- opts.separator("\nAvailable options:\n")
22
-
23
- opts.on("-c", "--config FILE",
24
- "Config file (default: #{Bitcoin::Config::CONFIG_PATHS})") do |file|
25
- options = Bitcoin::Config.load_file(options, file, :wallet)
26
- end
27
-
28
- opts.on("-n", "--network NETWORK",
29
- "User Network (default: #{options[:network]})") do |network|
30
- options[:network] = network
31
- end
32
-
33
- opts.on("-s", "--storage BACKEND::CONFIG",
34
- "Use storage backend (default: #{options[:storage]})") do |storage|
35
- options[:storage] = storage
36
- end
37
-
38
- opts.on("--command [HOST:PORT]",
39
- "Node command socket (default: #{options[:command]})") do |command|
40
- options[:command] = command
41
- end
42
-
43
- opts.on("-k", "--keystore [backend::<config>]",
44
- "Key store (default: #{options[:store]})") do |store|
45
- options[:keystore] = store.gsub("~", ENV['HOME'])
46
- end
47
-
48
- opts.on("-h", "--help", "Display this help") do
49
- puts opts; exit
50
- end
51
-
52
- opts.separator "\nAvailable commands:\n" +
53
- " balance [<addr>] - display balance for given addr or whole wallet\n" +
54
- " list <addr> - list transaction history for address\n" +
55
- " send <addr>:<amount>[,<addr>:<amount>...] [<fee>] - send transaction\n" +
56
- " new - generate new key and add to keystore\n" +
57
- " import <base58> - import key in base58 format\n" +
58
- " export <addr> - export key to base58 format\n" +
59
- " name_list - list names in the wallet\n" +
60
- " name_show <name> - display name information\n" +
61
- " name_history <name> - display name history\n" +
62
- " name_new <name> - reserve a name\n" +
63
- " name_firstupdate <name> <rand> <value> - register a name\n" +
64
- " name_update <name> <value> [<toaddress>] - update/transfer a name\n"
65
-
66
- end
67
-
68
- optparse.parse!
69
-
70
- cmd = ARGV.shift; cmdopts = ARGV
71
- unless cmd
72
- puts optparse; exit
73
- end
74
-
75
- Bitcoin.network = options[:network]
76
-
77
- options[:keystore] ||= "simple::file=~/.bitcoin-ruby/#{Bitcoin.network_name}/keys.json"
78
- backend, config = options[:keystore].split("::")
79
- config = Hash[config.split(",").map{|c| c.split("=")}]
80
- keystore = Bitcoin::Wallet.const_get("#{backend.capitalize}KeyStore").new(config)
81
- if backend == "deterministic" && !config["nonce"]
82
- puts "nonce: #{keystore.generator.nonce}"
83
- end
84
- #puts *keystore.get_keys.map(&:addr)
85
-
86
- options[:storage] ||= "sequel::sqlite://~/.bitcoin-ruby/#{Bitcoin.network_name}/blocks.db"
87
- backend, config = options[:storage].split("::")
88
- storage = Bitcoin::Storage.send(backend, :db => config)
89
-
90
- wallet = Bitcoin::Wallet::Wallet.new(storage, keystore, Bitcoin::Wallet::SimpleCoinSelector)
91
-
92
- def str_val(val, pre='')
93
- ("#{pre}%.8f" % (val / 1e8)).rjust(15)
94
- end
95
-
96
- def val_str(str)
97
- (str.to_f * 1e8).to_i
98
- end
99
-
100
- def send_transaction(storage, options, tx, ask = true)
101
- # puts tx.to_json
102
- if ask
103
- total = 0
104
- puts "Hash: #{tx.hash}"
105
- puts "inputs:"
106
- tx.in.each do |txin|
107
- prev_out = storage.get_txout_for_txin(txin)
108
- total += prev_out.value
109
- puts " #{prev_out.get_address} - #{str_val prev_out.value}"
110
- end
111
-
112
- puts "outputs:"
113
- tx.out.each do |txout|
114
- total -= txout.value
115
- script = Bitcoin::Script.new(txout.pk_script)
116
- print "#{str_val txout.value} "
117
- if script.is_pubkey?
118
- puts "#{script.get_pubkey} (pubkey)"
119
- elsif script.is_hash160?
120
- puts "#{script.get_address} (address)"
121
- elsif script.is_multisig?
122
- puts "#{script.get_addresses.join(' ')} (multisig)"
123
- elsif script.is_op_return?
124
- puts "#{script.get_op_return_data} (op_return)"
125
- elsif script.is_namecoin?
126
- puts "#{script.get_address} (#{script.type})"
127
- print " " * 16
128
- if script.is_name_new?
129
- puts "Name Hash: #{script.get_namecoin_hash}"
130
- else
131
- puts "#{script.get_namecoin_name}: #{script.get_namecoin_value}"
132
- end
133
- else
134
- puts "#{str_val txout.value} (unknown type)"
135
- end
136
- end
137
- puts "Fee: #{str_val total}"
138
-
139
- $stdout.sync = true
140
- print "Really send transaction? (y/N) " and $stdout.flush
141
- unless $stdin.gets.chomp.downcase == 'y'
142
- puts "Aborted."; exit
143
- end
144
- end
145
- EM.run do
146
- Bitcoin::Network::CommandClient.connect(*options[:command]) do
147
- on_connected do
148
- request(:relay_tx, tx.to_payload.hth)
149
- end
150
- on_relay_tx do |res|
151
- if res["success"]
152
- puts "Transaction #{tx.hash} relayed to approx. #{"%.2f" % res['propagation']['percent']}% of the network."
153
- else
154
- puts "Error relaying tx: #{res['error']}"
155
- end
156
- EM.stop
157
- end
158
- end
159
- end
160
- end
161
-
162
- case cmd
163
- when "balance"
164
- if cmdopts && cmdopts.size == 1
165
- addr = cmdopts[0]
166
- balance = storage.get_balance(Bitcoin.hash160_from_address(addr))
167
- puts "#{addr} balance: #{str_val balance}"
168
- else
169
- puts "Total balance: #{str_val wallet.get_balance}"
170
- end
171
-
172
- when "new"
173
- puts "Generated new key with address: #{wallet.get_new_addr}"
174
-
175
- when "add"
176
- key = {:label => ARGV[2]}
177
- case ARGV[0]
178
- when "pub"
179
- k = Bitcoin::Key.new(nil, ARGV[1])
180
- key[:key] = k
181
- key[:addr] = k.addr
182
- when "priv"
183
- k = Bitcoin::Key.new(ARGV[1], nil)
184
- k.regenerate_pubkey
185
- key[:key] = k
186
- key[:addr] = k.addr
187
- when "addr"
188
- key[:addr] = ARGV[1]
189
- else
190
- raise "unknown type #{ARGV[0]}"
191
- end
192
- wallet.add_key key
193
-
194
- when "label"
195
- wallet.label(ARGV[0], ARGV[1])
196
-
197
- when "flag"
198
- wallet.flag(ARGV[0], *ARGV[1].split("="))
199
-
200
- when "key"
201
- key = wallet.keystore.key(ARGV[0])
202
- puts "Label: #{key[:label]}"
203
- puts "Address: #{key[:addr]}"
204
- puts "Pubkey: #{key[:key].pub}"
205
- puts "Privkey: #{key[:key].priv}" if ARGV[1] == '-p'
206
- puts "Mine: #{key[:mine]}"
207
-
208
- when "import"
209
- if wallet.keystore.respond_to?(:import)
210
- addr = wallet.import_key(cmdopts[0])
211
- puts "Key for #{addr} imported."
212
- else
213
- puts "Keystore doesn't support importing."
214
- end
215
-
216
- when "rescan"
217
- wallet.rescan
218
-
219
- when "export"
220
- base58 = wallet.keystore.export(cmdopts[0])
221
- puts "Base58 encoded private key for #{cmdopts[0]}:"
222
- puts base58
223
-
224
- when "list"
225
- if cmdopts && cmdopts.size == 1
226
- depth = storage.get_depth
227
- total = 0
228
- key = wallet.keystore.key(cmdopts[0])
229
- storage.get_txouts_for_address(key[:addr]).each do |txout|
230
- total += txout.value
231
- tx = txout.get_tx
232
- blocks = depth - tx.get_block.depth rescue 0
233
- puts "#{tx.hash} | #{str_val txout.value, '+ '} | " +
234
- "#{str_val total} | #{blocks}"
235
- tx.in.map(&:get_prev_out).each do |prev_out|
236
- if prev_out
237
- puts " <- #{prev_out.get_address}"
238
- else
239
- puts " <- generation"
240
- end
241
- end
242
- puts
243
-
244
- if txin = txout.get_next_in
245
- tx = txin.get_tx
246
- total -= txout.value
247
- blocks = depth - tx.get_block.depth rescue 0
248
- puts "#{tx.hash} | #{str_val txout.value, '- '} | " +
249
- "#{str_val total} | #{blocks}"
250
- txin.get_tx.out.each do |out|
251
- if Bitcoin.namecoin? && out.type.to_s =~ /^name_/
252
- script = out.script
253
- puts " -> #{script.get_namecoin_name || script.get_namecoin_hash} (#{out.type})"
254
- else
255
- puts " -> #{out.get_addresses.join(', ') rescue 'unknown'}"
256
- end
257
- end
258
- puts
259
- end
260
- end
261
- puts "Total balance: #{str_val total}"
262
- else
263
- puts "Wallet addresses:"
264
- total = 0
265
- wallet.list.each do |key, balance|
266
- total += balance
267
- icon = key[:key] && key[:key].priv ? "P" : (key[:mine] ? "M" : " ")
268
- puts " #{icon} #{key[:label].to_s.ljust(10)} (#{key[:addr].to_s.ljust(34)}) - #{("%.8f" % (balance / 1e8)).rjust(15)}"
269
- end
270
- puts "Total balance: #{str_val wallet.get_balance}"
271
- end
272
-
273
- when "name_list"
274
- names = wallet.get_txouts.select {|o| [:name_firstupdate, :name_update].include?(o.type)}
275
- .map(&:get_namecoin_name).group_by(&:name).map {|n, l| l.sort_by(&:expires_in).last }.map {|name|
276
- { name: name.name, value: name.value, address: name.get_address, expires_in: name.expires_in } }
277
- puts JSON.pretty_generate(names)
278
-
279
- when "name_show"
280
- name = storage.name_show(cmdopts[0])
281
- puts name.to_json
282
-
283
- when "name_history"
284
- names = storage.name_history(cmdopts[0])
285
- puts JSON.pretty_generate(names)
286
-
287
- when "name_new"
288
- name = cmdopts[0]
289
- address = wallet.keystore.keys.sample[:key].addr
290
- @rand = nil
291
- def self.set_rand rand
292
- @rand = rand
293
- end
294
- tx = wallet.new_tx([[:name_new, self, name, address, 1000000]])
295
- (puts "Error creating tx."; exit) unless tx
296
- send_transaction(storage, options, tx, true)
297
- puts JSON.pretty_generate([tx.hash, @rand])
298
-
299
- when "name_firstupdate"
300
- name, rand, value = *cmdopts
301
- address = wallet.keystore.keys.sample[:key].addr
302
- tx = wallet.new_tx([[:name_firstupdate, name, rand, value, address, 1000000]])
303
- (puts "Error creating tx."; exit) unless tx
304
- send_transaction(storage, options, tx, true)
305
- puts tx.hash
306
-
307
- when "name_update"
308
- name, value, address = *cmdopts
309
- address ||= wallet.keystore.keys.sample[:key].addr
310
- tx = wallet.new_tx([[:name_update, name, value, address, 1000000]])
311
- (puts "Error creating tx."; exit) unless tx
312
- send_transaction(storage, options, tx, true)
313
- puts tx.hash
314
-
315
- when "send"
316
- to = cmdopts[0].split(',').map do |opts|
317
- o = opts.split(":")
318
- type, *addrs, value = *(o.size == 2 ? [:address, *o] : o)
319
- value = val_str(value)
320
- [type.to_sym, *addrs, value]
321
- end
322
- fee = val_str(cmdopts[1]) || 0
323
- value = val_str value
324
-
325
- unless wallet.get_balance >= (to.map{|t|t[-1]}.inject{|a,b|a+=b;a} + fee)
326
- puts "Insufficient funds."; exit
327
- end
328
-
329
- tx = wallet.new_tx(to, fee)
330
-
331
- if tx.is_a?(Bitcoin::Wallet::TxDP)
332
- puts "Transaction needs to be signed by additional keys."
333
- print "Filename to save TxDP: [./#{tx.id}.txdp] "
334
- $stdout.flush
335
- filename = $stdin.gets.strip
336
- filename = "./#{tx.id}.txdp" if filename == ""
337
- File.open(filename, "w") {|f| f.write(tx.serialize) }
338
- exit
339
- end
340
-
341
- (puts "Error creating tx."; exit) unless tx
342
-
343
- send_transaction(storage, options, tx)
344
-
345
- when "sign"
346
- txt = File.read(ARGV[0])
347
- txdp = Bitcoin::Wallet::TxDP.parse(txt)
348
- puts txdp.tx[0].to_json
349
-
350
- print "Really sign transaction? (y/N) " and $stdout.flush
351
- unless $stdin.gets.chomp.downcase == 'y'
352
- puts "Aborted."; exit
353
- end
354
-
355
- txdp.sign_inputs do |tx, prev_tx, i, addr|
356
- key = keystore.key(addr)[:key] rescue nil
357
- next nil unless key && !key.priv.nil?
358
- sig_hash = tx.signature_hash_for_input(i, prev_tx)
359
- sig = key.sign(sig_hash)
360
- script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [key.pub].pack("H*"))
361
- script_sig.unpack("H*")[0]
362
- end
363
- File.open(ARGV[0], "w") {|f| f.write txdp.serialize }
364
-
365
- when "relay"
366
- txt = File.read(ARGV[0])
367
- txdp = Bitcoin::Wallet::TxDP.parse(txt)
368
- tx = txdp.tx[0]
369
- puts tx.to_json
370
- txdp.inputs.each_with_index do |s, i|
371
- value, sigs = *s
372
- tx.in[i].script_sig = [sigs[0][1]].pack("H*")
373
- end
374
- tx.in.each_with_index do |txin, i|
375
- p txdp.tx.map(&:hash)
376
- prev_tx = storage.get_tx(txin.prev_out.reverse_hth)
377
- raise "prev tx #{txin.prev_out.reverse_hth} not found" unless prev_tx
378
- raise "signature error" unless tx.verify_input_signature(i, prev_tx)
379
- end
380
-
381
- $stdout.sync = true
382
- print "Really send transaction? (y/N) " and $stdout.flush
383
- unless $stdin.gets.chomp.downcase == 'y'
384
- puts "Aborted."; exit
385
- end
386
-
387
- EM.run do
388
- EM.connect(*options[:command]) do |conn|
389
- conn.send_data(["relay_tx", tx.to_payload.unpack("H*")[0]].to_json)
390
- def conn.receive_data(data)
391
- (@buf ||= BufferedTokenizer.new("\x00")).extract(data).each do |packet|
392
- res = JSON.load(packet)
393
- puts "Transaction relayed: #{res[1]["hash"]}"
394
- EM.stop
395
- end
396
- end
397
- end
398
- end
399
-
400
- else
401
- puts "Unknown command. See --help for available commands."
402
- end