lib/bitcoin/builder.rb in bitcoin-ruby-0.0.10 vs lib/bitcoin/builder.rb in bitcoin-ruby-0.0.11
- old
+ new
@@ -200,11 +200,11 @@
@ins.each_with_index do |inc, i|
sign_input(i, inc)
end
# run our tx through an encode/decode cycle to make sure that the binary format is sane
- raise "Payload Error" unless P::Tx.new(@tx.to_payload).to_payload == @tx.to_payload
+ raise "Payload Error" unless P::Tx.new(@tx.to_witness_payload).to_payload == @tx.to_payload
@tx.instance_eval do
@payload = to_payload
@hash = hash_from_payload(@payload)
end
@@ -219,15 +219,15 @@
end
def sig_hash_and_all_keys_exist?(inc, sig_script)
return false unless @sig_hash && inc.has_keys?
script = Bitcoin::Script.new(sig_script)
- return true if script.is_hash160? || script.is_pubkey? || (Bitcoin.namecoin? && script.is_namecoin?)
+ return true if script.is_hash160? || script.is_pubkey? || script.is_witness_v0_keyhash? || (Bitcoin.namecoin? && script.is_namecoin?)
if script.is_multisig?
return inc.has_multiple_keys? && inc.key.size >= script.get_signatures_required
end
- raise "Script type must be hash160, pubkey or multisig"
+ raise "Script type must be hash160, pubkey, p2wpkh or multisig"
end
def add_empty_script_sig_to_input(i)
@tx.in[i].script_sig_length = 0
@tx.in[i].script_sig = ""
@@ -267,17 +267,28 @@
# (indicates spending a p2sh output), otherwise use the prev_script
sig_script = inc.instance_eval { @redeem_script }
sig_script ||= @prev_script
# when a sig_script was found, generate the sig_hash to be signed
- @sig_hash = @tx.signature_hash_for_input(i, sig_script) if sig_script
+ 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)
+ 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
- @tx.in[i].script_sig = get_script_sig(inc)
-
+ 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)
+ 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)
elsif inc.has_multiple_keys?
raise "Keys missing for multisig signing"
else
@@ -316,11 +327,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
+ attr_reader :prev_tx, :prev_script, :redeem_script, :key, :coinbase_data, :prev_out_value
def initialize
@txin = P::TxIn.new
@prev_out_hash = "\x00" * 32
@prev_out_index = 0
@@ -328,20 +339,21 @@
# 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
+ def prev_out tx, idx = nil, script = nil, prev_value = nil
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
@prev_out_hash = tx.htb.reverse
end
@prev_out_script = script if script
@prev_out_index = idx if idx
+ @prev_out_value = prev_value if prev_value
end
# Index of the output in the #prev_out transaction.
def prev_out_index i
@prev_out_index = i
@@ -351,10 +363,19 @@
# Previous output's +pk_script+. Needed when only the tx hash is specified as #prev_out.
def prev_out_script script
@prev_out_script = script
end
+ # Previous output's +value+. Needed when only spend segwit utxo.
+ def prev_out_value value
+ @prev_out_value = value
+ end
+
+ def value
+ @prev_out_value
+ end
+
# Redeem script for P2SH output. To spend from a P2SH output, you need to provide
# the script with a hash matching the P2SH address.
def redeem_script script
@redeem_script = script
end
@@ -392,10 +413,14 @@
def has_keys?
@key && (has_multiple_keys? ? @key.all?(&:priv) : @key.priv)
end
+ def is_witness_v0_keyhash?
+ @prev_out_script && Script.new(@prev_out_script).is_witness_v0_keyhash?
+ end
+
def sign(sig_hash)
if has_multiple_keys?
@key.map {|k| k.sign(sig_hash) }
else
@key.sign(sig_hash)
@@ -436,10 +461,10 @@
# t.output do |o|
# o.value 12345
# o.script {|s| s.recipient address }
# end
#
- # t.output {|o| o.to "deadbeef", OP_RETURN }
+ # t.output {|o| o.to "deadbeef", :op_return }
class TxOutBuilder
attr_reader :txout
def initialize
@txout = P::TxOut.new(0)