bin/bitcoin_wallet in bitcoin-ruby-0.0.1 vs bin/bitcoin_wallet in bitcoin-ruby-0.0.2
- old
+ new
@@ -6,12 +6,12 @@
require 'optparse'
require 'yaml'
defaults = {
:network => "testnet",
- :storage => "dummy",
- :keystore => "simple::file=#{ENV['HOME']}/.bitcoin-ruby/keys.json",
+ :storage => nil,
+ :keystore => nil,
:command => "127.0.0.1:9999"
}
options = Bitcoin::Config.load(defaults, :wallet)
optparse = OptionParser.new do |opts|
@@ -53,11 +53,17 @@
" balance [<addr>] - display balance for given addr or whole wallet\n" +
" list <addr> - list transaction history for address\n" +
" send <addr>:<amount>[,<addr>:<amount>...] [<fee>] - send transaction\n" +
" new - generate new key and add to keystore\n" +
" import <base58> - import key in base58 format\n" +
- " export <addr> - export key to base58 format\n"
+ " export <addr> - export key to base58 format\n" +
+ " name_list - list names in the wallet\n" +
+ " name_show <name> - display name information\n" +
+ " name_history <name> - display name history\n" +
+ " name_new <name> - reserve a name\n" +
+ " name_firstupdate <name> <rand> <value> - register a name\n" +
+ " name_update <name> <value> [<toaddress>] - update/transfer a name\n"
end
optparse.parse!
@@ -65,32 +71,94 @@
unless cmd
exit puts optparse
end
Bitcoin.network = options[:network]
+
+options[:keystore] ||= "simple::file=~/.bitcoin-ruby/#{Bitcoin.network_name}/keys.json"
backend, config = options[:keystore].split("::")
config = Hash[config.split(",").map{|c| c.split("=")}]
keystore = Bitcoin::Wallet.const_get("#{backend.capitalize}KeyStore").new(config)
if backend == "deterministic" && !config["nonce"]
puts "nonce: #{keystore.generator.nonce}"
end
#puts *keystore.get_keys.map(&:addr)
+
+options[:storage] ||= "sequel::sqlite://~/.bitcoin-ruby/#{Bitcoin.network_name}/blocks.db"
backend, config = options[:storage].split("::")
storage = Bitcoin::Storage.send(backend, :db => config)
-
wallet = Bitcoin::Wallet::Wallet.new(storage, keystore, Bitcoin::Wallet::SimpleCoinSelector)
-
def str_val(val, pre='')
("#{pre}%.8f" % (val / 1e8)).rjust(15)
end
def val_str(str)
(str.to_f * 1e8).to_i
end
+def send_transaction(storage, options, tx, ask = true)
+ # puts tx.to_json
+ if ask
+ total = 0
+ puts "Hash: #{tx.hash}"
+ puts "inputs:"
+ tx.in.each do |txin|
+ prev_out = storage.get_txout_for_txin(txin)
+ total += prev_out.value
+ puts " #{prev_out.get_address} - #{str_val prev_out.value}"
+ end
+
+ puts "outputs:"
+ tx.out.each do |txout|
+ total -= txout.value
+ script = Bitcoin::Script.new(txout.pk_script)
+ print "#{str_val txout.value} "
+ if script.is_pubkey?
+ puts "#{script.get_pubkey} (pubkey)"
+ elsif script.is_hash160?
+ puts "#{script.get_address} (address)"
+ elsif script.is_multisig?
+ puts "#{script.get_addresses.join(' ')} (multisig)"
+ elsif script.is_namecoin?
+ puts "#{script.get_address} (#{script.type})"
+ print " " * 16
+ if script.is_name_new?
+ puts "Name Hash: #{script.get_namecoin_hash}"
+ else
+ puts "#{script.get_namecoin_name}: #{script.get_namecoin_value}"
+ end
+ else
+ puts "#{str_val txout.value} (unknown type)"
+ end
+ end
+ puts "Fee: #{str_val total}"
+
+ $stdout.sync = true
+ print "Really send transaction? (y/N) " and $stdout.flush
+ unless $stdin.gets.chomp.downcase == 'y'
+ puts "Aborted."; exit
+ end
+ end
+ EM.run do
+ Bitcoin::Network::CommandClient.connect(*options[:command].split(":")) do
+ on_connected do
+ request(:relay_tx, tx.to_payload.hth)
+ end
+ on_relay_tx do |res|
+ if res["success"]
+ puts "Transaction #{tx.hash} relayed to approx. #{"%.2f" % res['propagation']['percent']}% of the network."
+ else
+ puts "Error relaying tx: #{res['error']}"
+ end
+ EM.stop
+ end
+ end
+ end
+end
+
case cmd
when "balance"
if cmdopts && cmdopts.size == 1
addr = cmdopts[0]
balance = storage.get_balance(Bitcoin.hash160_from_address(addr))
@@ -133,19 +201,21 @@
puts "Address: #{key[:addr]}"
puts "Pubkey: #{key[:key].pub}"
puts "Privkey: #{key[:key].priv}" if ARGV[1] == '-p'
puts "Mine: #{key[:mine]}"
-
when "import"
if wallet.keystore.respond_to?(:import)
- addr = wallet.keystore.import(cmdopts[0])
+ addr = wallet.import_key(cmdopts[0])
puts "Key for #{addr} imported."
else
puts "Keystore doesn't support importing."
end
+when "rescan"
+ wallet.rescan
+
when "export"
base58 = wallet.keystore.export(cmdopts[0])
puts "Base58 encoded private key for #{cmdopts[0]}:"
puts base58
@@ -174,11 +244,16 @@
total -= txout.value
blocks = depth - tx.get_block.depth rescue 0
puts "#{tx.hash} | #{str_val txout.value, '- '} | " +
"#{str_val total} | #{blocks}"
txin.get_tx.out.each do |out|
- puts " -> #{out.get_addresses.join(', ')}"
+ if Bitcoin.namecoin? && out.type.to_s =~ /^name_/
+ script = out.script
+ puts " -> #{script.get_namecoin_name || script.get_namecoin_hash} (#{out.type})"
+ else
+ puts " -> #{out.get_addresses.join(', ') rescue 'unknown'}"
+ end
end
puts
end
end
puts "Total balance: #{str_val total}"
@@ -191,10 +266,52 @@
puts " #{icon} #{key[:label].to_s.ljust(10)} (#{key[:addr].to_s.ljust(34)}) - #{("%.8f" % (balance / 1e8)).rjust(15)}"
end
puts "Total balance: #{str_val wallet.get_balance}"
end
+when "name_list"
+ names = wallet.get_txouts.select {|o| [:name_firstupdate, :name_update].include?(o.type)}
+ .map(&:get_namecoin_name).group_by(&:name).map {|n, l| l.sort_by(&:expires_in).last }.map {|name|
+ { name: name.name, value: name.value, address: name.get_address, expires_in: name.expires_in } }
+ puts JSON.pretty_generate(names)
+
+when "name_show"
+ name = storage.name_show(cmdopts[0])
+ puts name.to_json
+
+when "name_history"
+ names = storage.name_history(cmdopts[0])
+ puts JSON.pretty_generate(names)
+
+when "name_new"
+ name = cmdopts[0]
+ address = wallet.keystore.keys.sample[:key].addr
+ @rand = nil
+ def self.set_rand rand
+ @rand = rand
+ end
+ tx = wallet.new_tx([[:name_new, self, name, address, 1000000]])
+ (puts "Error creating tx."; exit) unless tx
+ send_transaction(storage, options, tx, true)
+ puts JSON.pretty_generate([tx.hash, @rand])
+
+when "name_firstupdate"
+ name, rand, value = *cmdopts
+ address = wallet.keystore.keys.sample[:key].addr
+ tx = wallet.new_tx([[:name_firstupdate, name, rand, value, address, 1000000]])
+ (puts "Error creating tx."; exit) unless tx
+ send_transaction(storage, options, tx, true)
+ puts tx.hash
+
+when "name_update"
+ name, value, address = *cmdopts
+ address ||= wallet.keystore.keys.sample[:key].addr
+ tx = wallet.new_tx([[:name_update, name, value, address, 1000000]])
+ (puts "Error creating tx."; exit) unless tx
+ send_transaction(storage, options, tx, true)
+ puts tx.hash
+
when "send"
to = cmdopts[0].split(',').map do |pair|
type, *addrs, value = pair.split(":")
value = val_str(value)
[type.to_sym, *addrs, value]
@@ -215,56 +332,15 @@
filename = $stdin.gets.strip
filename = "./#{tx.id}.txdp" if filename == ""
File.open(filename, "w") {|f| f.write(tx.serialize) }
exit
end
-
- unless tx
- puts "Error creating tx."; exit
- end
- total = 0
- puts "Hash: #{tx.hash}"
- puts "inputs:"
- tx.in.each do |txin|
- prev_out = storage.get_txout_for_txin(txin)
- total += prev_out.value
- puts " #{prev_out.get_address} - #{str_val prev_out.value}"
- end
+ (puts "Error creating tx."; exit) unless tx
- puts "outputs:"
- tx.out.each do |txout|
- total -= txout.value
- script = Bitcoin::Script.new(txout.pk_script)
- if script.is_pubkey?
- puts "#{str_val txout.value} #{script.get_pubkey} (pubkey)"
- elsif script.is_hash160?
- puts "#{str_val txout.value} #{script.get_address} (address)"
- elsif script.is_multisig?
- puts "#{str_val txout.value} #{script.get_addresses.join(' ')} (multisig)"
- end
- end
- puts "Fee: #{str_val total}"
+ send_transaction(storage, options, tx)
- $stdout.sync = true
- print "Really send transaction? (y/N) " and $stdout.flush
- unless $stdin.gets.chomp.downcase == 'y'
- puts "Aborted."; exit
- end
-
- EM.run do
- Bitcoin::Network::CommandClient.connect(*options[:command].split(":")) do
- on_connected do
- request(:relay_tx, tx)
- end
- on_relay_tx do
- puts "Transaction #{tx.hash} relayed"
- EM.stop
- end
- end
- end
-
when "sign"
txt = File.read(ARGV[0])
txdp = Bitcoin::Wallet::TxDP.parse(txt)
puts txdp.tx[0].to_json
@@ -292,11 +368,11 @@
value, sigs = *s
tx.in[i].script_sig = [sigs[0][1]].pack("H*")
end
tx.in.each_with_index do |txin, i|
p txdp.tx.map(&:hash)
- prev_tx = storage.get_tx(txin.prev_out.reverse.unpack("H*")[0])
- raise "prev tx #{txin.prev_out.reverse.unpack("H*")[0]} not found" unless prev_tx
+ prev_tx = storage.get_tx(txin.prev_out.reverse_hth)
+ raise "prev tx #{txin.prev_out.reverse_hth} not found" unless prev_tx
raise "signature error" unless tx.verify_input_signature(i, prev_tx)
end
$stdout.sync = true
print "Really send transaction? (y/N) " and $stdout.flush