Commit 2a3743432bd2197d48ae0e2d6d9bc0aff5ae7650

Authored by Marius Hanne
1 parent 0929ad70da

spend multisig tx if all priv keys are in the wallet

Showing 4 changed files with 39 additions and 11 deletions Side-by-side Diff

... ... @@ -144,7 +144,7 @@
144 144 puts "#{tx.hash} | #{str_val txout.value, '- '} | " +
145 145 "#{str_val total} | #{blocks}"
146 146 txin.get_tx.out.each do |out|
147   - puts " -> #{out.get_address}"
  147 + puts " -> #{out.get_addresses.join(', ')}"
148 148 end
149 149 puts
150 150 end
... ... @@ -157,7 +157,7 @@
157 157 total += balance
158 158 puts " #{addr.ljust(34)} - #{("%.8f" % (balance / 1e8)).rjust(15)}"
159 159 end
160   - puts "Total balance: #{str_val total}"
  160 + puts "Total balance: #{str_val wallet.get_balance}"
161 161 end
162 162  
163 163 when "send"
lib/bitcoin/protocol/txout.rb
... ... @@ -13,8 +13,16 @@
13 13 end
14 14 end
15 15  
  16 + def hash
  17 + [@value, @pk_script].hash
  18 + end
  19 +
16 20 # compare to another txout
17 21 def ==(other)
  22 + @value == other.value && @pk_script == other.pk_script
  23 + end
  24 +
  25 + def eql?(other)
18 26 @value == other.value && @pk_script == other.pk_script
19 27 end
20 28  
lib/bitcoin/script.rb
... ... @@ -331,6 +331,14 @@
331 331 to_pubkey_script_sig(*a)
332 332 end
333 333  
  334 + def self.to_multisig_script_sig(*sigs)
  335 + from_string("0 #{sigs.map{|s|s.unpack('H*')[0]}.join(' ')}").raw
  336 + end
  337 +
  338 + def get_signatures_required
  339 + return false unless is_multisig?
  340 + @chunks[0] - 80
  341 + end
334 342  
335 343 ## OPCODES
336 344  
lib/bitcoin/wallet/wallet.rb
... ... @@ -11,7 +11,7 @@
11 11  
12 12 def get_txouts
13 13 @keystore.keys.map {|k|
14   - @storage.get_txouts_for_address(k.addr)}.flatten
  14 + @storage.get_txouts_for_address(k[:addr])}.flatten.uniq
15 15 end
16 16  
17 17 def get_balance
... ... @@ -25,7 +25,7 @@
25 25  
26 26 def list
27 27 @keystore.keys.map do |key|
28   - [key.addr, @storage.get_balance(Bitcoin.hash160_from_address(key.addr))]
  28 + [key[:addr], @storage.get_balance(Bitcoin.hash160_from_address(key[:addr]))]
29 29 end
30 30 end
31 31  
... ... @@ -58,7 +58,7 @@
58 58 script = Bitcoin::Script.to_address_script(addrs[0])
59 59 when :multisig
60 60 m, *addrs = addrs
61   - addrs.map!{|a| keystore.key(a).pub rescue raise("public key for #{a} not known")}
  61 + addrs.map!{|a| keystore.key(a)[:key].pub rescue raise("public key for #{a} not known")}
62 62 script = Bitcoin::Script.to_multisig_script(m, *addrs)
63 63 else
64 64 raise "unknown script type: #{type}"
65 65  
66 66  
... ... @@ -87,14 +87,26 @@
87 87 if pk_script.is_pubkey? || pk_script.is_hash160?
88 88 key = @keystore.key(prev_out.get_address)
89 89 sig_hash = tx.signature_hash_for_input(idx, prev_tx)
90   - sig = key.sign(sig_hash)
91   - script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [key.pub].pack("H*"))
92   - tx.in[idx].script_sig_length = script_sig.bytesize
93   - tx.in[idx].script_sig = script_sig
94   - raise "Signature error" unless tx.verify_input_signature(idx, prev_tx)
  90 + sig = key[:key].sign(sig_hash)
  91 + script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [key[:key].pub].pack("H*"))
95 92 elsif pk_script.is_multisig?
96   - # TODO
  93 + sigs = []
  94 + required_sigs = pk_script.get_signatures_required
  95 + pk_script.get_multisig_pubkeys.each do |pub|
  96 + break if sigs.size == required_sigs
  97 + key = @keystore.key(pub.unpack("H*")[0])[:key]
  98 + next unless key && key.priv
  99 + sig_hash = tx.signature_hash_for_input(idx, prev_tx)
  100 + sig = [key.sign(sig_hash), "\x01"].join
  101 + sigs << sig
  102 + end
  103 + raise "Need #{required_sigs} signatures, only have #{sigs.size} private keys" if sigs.size < required_sigs
  104 +
  105 + script_sig = Bitcoin::Script.to_multisig_script_sig(*sigs)
97 106 end
  107 + tx.in[idx].script_sig_length = script_sig.bytesize
  108 + tx.in[idx].script_sig = script_sig
  109 + raise "Signature error" unless tx.verify_input_signature(idx, prev_tx)
98 110 end
99 111  
100 112 Bitcoin::Protocol::Tx.new(tx.to_payload)