bitcoin-ruby 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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