lib/bitcoin/builder.rb in bitcoin-ruby-0.0.14 vs lib/bitcoin/builder.rb in bitcoin-ruby-0.0.15

- old
+ new

@@ -235,11 +235,11 @@ @tx.in[i].sig_hash = @sig_hash # add the address the sig_hash needs to be signed with as a convenience for the signing device @tx.in[i].sig_address = Script.new(@prev_script).get_address if @prev_script end - def get_script_sig(inc) + def get_script_sig(inc, hash_type) if inc.has_multiple_keys? # multiple keys given, generate signature for each one sigs = inc.sign(@sig_hash) if redeem_script = inc.instance_eval { @redeem_script } # when a redeem_script was specified, assume we spend a p2sh multisig script @@ -249,11 +249,11 @@ script_sig = Script.to_multisig_script_sig(*sigs) end else # only one key given, generate signature and script_sig sig = inc.sign(@sig_hash) - script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack("H*")) + script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack("H*"), hash_type) end return script_sig end # Sign input number +i+ with data from given +inc+ object (a TxInBuilder). @@ -266,31 +266,48 @@ # get the signature script; use +redeem_script+ if given # (indicates spending a p2sh output), otherwise use the prev_script sig_script = inc.instance_eval { @redeem_script } sig_script ||= @prev_script + hash_type = if inc.prev_out_forkid + Script::SIGHASH_TYPE[:all] | Script::SIGHASH_TYPE[:forkid] + else + Script::SIGHASH_TYPE[:all] + end + # when a sig_script was found, generate the sig_hash to be signed if sig_script script = Script.new(sig_script) if script.is_witness_v0_keyhash? @sig_hash = @tx.signature_hash_for_witness_input(i, sig_script, inc.value) else - @sig_hash = @tx.signature_hash_for_input(i, sig_script) + @sig_hash = if inc.prev_out_forkid + @tx.signature_hash_for_input( + i, + sig_script, + hash_type, + inc.value, + inc.prev_out_forkid) + else + @tx.signature_hash_for_input(i, sig_script) + end end end # when there is a sig_hash and one or more signature_keys were specified if sig_hash_and_all_keys_exist?(inc, sig_script) # add the script_sig to the txin if script.is_witness_v0_keyhash? # for p2wpkh @tx.in[i].script_witness.stack << inc.sign(@sig_hash) + [Script::SIGHASH_TYPE[:all]].pack("C") @tx.in[i].script_witness.stack << inc.key.pub.htb else - @tx.in[i].script_sig = get_script_sig(inc) + @tx.in[i].script_sig = get_script_sig(inc, hash_type) end # double-check that the script_sig is valid to spend the given prev_script - raise "Signature error" if @prev_script && !@tx.verify_input_signature(i, @prev_script) + if @prev_script && !inc.prev_out_forkid && !@tx.verify_input_signature(i, @prev_script) + raise "Signature error" + end elsif inc.has_multiple_keys? raise "Keys missing for multisig signing" else # no sig_hash, add an empty script_sig. add_empty_script_sig_to_input(i) @@ -327,11 +344,11 @@ # i.redeem_script prev_out.redeem_script # end # # If you want to spend a multisig output, just provide an array of keys to #signature_key. class TxInBuilder - attr_reader :prev_tx, :prev_script, :redeem_script, :key, :coinbase_data, :prev_out_value + attr_reader :prev_tx, :prev_script, :redeem_script, :key, :coinbase_data, :prev_out_value, :prev_out_forkid def initialize @txin = P::TxIn.new @prev_out_hash = "\x00" * 32 @prev_out_index = 0 @@ -339,10 +356,11 @@ # Previous transaction that contains the output we want to use. # You can either pass the transaction, or just the tx hash. # If you pass only the hash, you need to pass the previous outputs # +script+ separately if you want the txin to be signed. - def prev_out tx, idx = nil, script = nil, prev_value = nil + def prev_out tx, idx = nil, script = nil, prev_value = nil, prev_forkid = nil + @prev_out_forkid = prev_forkid if tx.is_a?(Bitcoin::P::Tx) @prev_tx = tx @prev_out_hash = tx.binary_hash @prev_out_script = tx.out[idx].pk_script if idx else