Class: Bitcoin::PSBT::Input
Overview
Class for PSBTs which contain per-input information
Instance Attribute Summary collapse
-
#final_script_sig ⇒ Object
Returns the value of attribute final_script_sig.
-
#final_script_witness ⇒ Object
Returns the value of attribute final_script_witness.
-
#hd_key_paths ⇒ Object
Returns the value of attribute hd_key_paths.
-
#non_witness_utxo ⇒ Object
Bitcoin::Tx.
-
#partial_sigs ⇒ Object
Returns the value of attribute partial_sigs.
-
#redeem_script ⇒ Object
Returns the value of attribute redeem_script.
-
#sighash_type ⇒ Object
Returns the value of attribute sighash_type.
-
#unknowns ⇒ Object
Returns the value of attribute unknowns.
-
#witness_script ⇒ Object
Returns the value of attribute witness_script.
-
#witness_utxo ⇒ Object
Bitcoin::TxOut.
Class Method Summary collapse
-
.parse_from_buf(buf) ⇒ Bitcoin::PSBTInput
parse PSBT input data form buffer.
Instance Method Summary collapse
-
#add_sig(pubkey, sig) ⇒ Object
add signature as partial sig.
-
#finalize! ⇒ Bitcoin::PSBT::Input
finalize input.
-
#initialize(non_witness_utxo: nil, witness_utxo: nil) ⇒ Input
constructor
A new instance of Input.
-
#merge(psbi) ⇒ Bitcoin::PSBT::Input
merge two PSBT inputs to create one PSBT.
-
#sane? ⇒ Boolean
Sanity check.
- #to_payload ⇒ Object
Constructor Details
#initialize(non_witness_utxo: nil, witness_utxo: nil) ⇒ Input
Returns a new instance of Input.
19 20 21 22 23 24 25 |
# File 'lib/bitcoin/psbt/input.rb', line 19 def initialize(non_witness_utxo: nil, witness_utxo: nil) @non_witness_utxo = non_witness_utxo @witness_utxo = witness_utxo @partial_sigs = {} @hd_key_paths = {} @unknowns = {} end |
Instance Attribute Details
#final_script_sig ⇒ Object
Returns the value of attribute final_script_sig.
12 13 14 |
# File 'lib/bitcoin/psbt/input.rb', line 12 def final_script_sig @final_script_sig end |
#final_script_witness ⇒ Object
Returns the value of attribute final_script_witness.
13 14 15 |
# File 'lib/bitcoin/psbt/input.rb', line 13 def final_script_witness @final_script_witness end |
#hd_key_paths ⇒ Object
Returns the value of attribute hd_key_paths.
14 15 16 |
# File 'lib/bitcoin/psbt/input.rb', line 14 def hd_key_paths @hd_key_paths end |
#non_witness_utxo ⇒ Object
Bitcoin::Tx
8 9 10 |
# File 'lib/bitcoin/psbt/input.rb', line 8 def non_witness_utxo @non_witness_utxo end |
#partial_sigs ⇒ Object
Returns the value of attribute partial_sigs.
15 16 17 |
# File 'lib/bitcoin/psbt/input.rb', line 15 def partial_sigs @partial_sigs end |
#redeem_script ⇒ Object
Returns the value of attribute redeem_script.
10 11 12 |
# File 'lib/bitcoin/psbt/input.rb', line 10 def redeem_script @redeem_script end |
#sighash_type ⇒ Object
Returns the value of attribute sighash_type.
16 17 18 |
# File 'lib/bitcoin/psbt/input.rb', line 16 def sighash_type @sighash_type end |
#unknowns ⇒ Object
Returns the value of attribute unknowns.
17 18 19 |
# File 'lib/bitcoin/psbt/input.rb', line 17 def unknowns @unknowns end |
#witness_script ⇒ Object
Returns the value of attribute witness_script.
11 12 13 |
# File 'lib/bitcoin/psbt/input.rb', line 11 def witness_script @witness_script end |
#witness_utxo ⇒ Object
Bitcoin::TxOut
9 10 11 |
# File 'lib/bitcoin/psbt/input.rb', line 9 def witness_utxo @witness_utxo end |
Class Method Details
.parse_from_buf(buf) ⇒ Bitcoin::PSBTInput
parse PSBT input data form buffer.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/bitcoin/psbt/input.rb', line 30 def self.parse_from_buf(buf) input = self.new until buf.eof? key_len = Bitcoin.unpack_var_int_from_io(buf) break if key_len == 0 key_type = buf.read(1).unpack('C').first key = buf.read(key_len - 1) value = buf.read(Bitcoin.unpack_var_int_from_io(buf)) case key_type when PSBT_IN_TYPES[:non_witness_utxo] raise ArgumentError, 'Duplicate Key, input non-witness utxo already provided.' if input.non_witness_utxo input.non_witness_utxo = Bitcoin::Tx.parse_from_payload(value) when PSBT_IN_TYPES[:witness_utxo] raise ArgumentError, 'Duplicate Key, input witness utxo already provided.' if input.witness_utxo input.witness_utxo = Bitcoin::TxOut.parse_from_payload(value) when PSBT_IN_TYPES[:partial_sig] if key.size != Bitcoin::Key::PUBLIC_KEY_SIZE && key.size != Bitcoin::Key::COMPRESSED_PUBLIC_KEY_SIZE raise ArgumentError, 'Size of key was not the expected size for the type partial signature pubkey.' end pubkey = Bitcoin::Key.new(pubkey: key.bth) raise ArgumentError, 'Invalid pubkey.' unless pubkey.fully_valid_pubkey? raise ArgumentError, 'Duplicate Key, input partial signature for pubkey already provided.' if input.partial_sigs[pubkey.pubkey] input.partial_sigs[pubkey.pubkey] = value when PSBT_IN_TYPES[:sighash] raise ArgumentError 'Duplicate Key, input sighash type already provided.' if input.sighash_type input.sighash_type = value.unpack('I').first when PSBT_IN_TYPES[:redeem_script] raise ArgumentError, 'Duplicate Key, input redeemScript already provided.' if input.redeem_script input.redeem_script = Bitcoin::Script.parse_from_payload(value) when PSBT_IN_TYPES[:witness_script] raise ArgumentError, 'Duplicate Key, input witnessScript already provided.' if input.witness_script input.witness_script = Bitcoin::Script.parse_from_payload(value) when PSBT_IN_TYPES[:bip32_derivation] raise ArgumentError, 'Duplicate Key, pubkey derivation path already provided.' if input.hd_key_paths[key.bth] input.hd_key_paths[key.bth] = Bitcoin::PSBT::HDKeyPath.parse_from_payload(key, value) when PSBT_IN_TYPES[:script_sig] raise ArgumentError, 'Duplicate Key, input final scriptSig already provided.' if input.final_script_sig input.final_script_sig = Bitcoin::Script.parse_from_payload(value) when PSBT_IN_TYPES[:script_witness] raise ArgumentError, 'Duplicate Key, input final scriptWitness already provided.' if input.final_script_witness input.final_script_witness = Bitcoin::ScriptWitness.parse_from_payload(value) else unknown_key = ([key_type].pack('C') + key).bth raise ArgumentError, 'Duplicate Key, key for unknown value already provided.' if input.unknowns[unknown_key] input.unknowns[unknown_key] = value end end input end |
Instance Method Details
#add_sig(pubkey, sig) ⇒ Object
add signature as partial sig.
110 111 112 113 114 |
# File 'lib/bitcoin/psbt/input.rb', line 110 def add_sig(pubkey, sig) raise ArgumentError, 'The sighash in signature is invalid.' unless sig.unpack('C*')[-1] == sighash_type raise ArgumentError, 'Duplicate Key, input partial signature for pubkey already provided.' if partial_sigs[pubkey] partial_sigs[pubkey] = sig end |
#finalize! ⇒ Bitcoin::PSBT::Input
finalize input. TODO This feature is experimental and support only multisig.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/bitcoin/psbt/input.rb', line 141 def finalize! if non_witness_utxo self.final_script_sig = Bitcoin::Script.new << Bitcoin::Opcodes::OP_0 if redeem_script.multisig? partial_sigs.values.each {|sig|final_script_sig << sig.bth} final_script_sig << redeem_script.to_payload.bth self.partial_sigs = {} self.hd_key_paths = {} self.redeem_script = nil self.sighash_type = nil else if redeem_script self.final_script_sig = Bitcoin::Script.parse_from_payload(Bitcoin::Script.pack_pushdata(redeem_script.to_payload)) self.redeem_script = nil end if witness_script self.final_script_witness = Bitcoin::ScriptWitness.new final_script_witness.stack << '' if witness_script.multisig? partial_sigs.values.each {|sig| final_script_witness.stack << sig} final_script_witness.stack << witness_script.to_payload self.witness_script = nil end self.sighash_type = nil self.partial_sigs = {} self.hd_key_paths = {} end self end |
#merge(psbi) ⇒ Bitcoin::PSBT::Input
merge two PSBT inputs to create one PSBT.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/bitcoin/psbt/input.rb', line 119 def merge(psbi) raise ArgumentError, 'The argument psbt must be an instance of Bitcoin::PSBT::Input.' unless psbi.is_a?(Bitcoin::PSBT::Input) raise ArgumentError, 'The Partially Signed Input\'s non_witness_utxo are different.' unless non_witness_utxo == psbi.non_witness_utxo raise ArgumentError, 'The Partially Signed Input\'s witness_utxo are different.' unless witness_utxo == psbi.witness_utxo raise ArgumentError, 'The Partially Signed Input\'s sighash_type are different.' unless sighash_type == psbi.sighash_type raise ArgumentError, 'The Partially Signed Input\'s redeem_script are different.' unless redeem_script == psbi.redeem_script raise ArgumentError, 'The Partially Signed Input\'s witness_script are different.' unless witness_script == psbi.witness_script combined = Bitcoin::PSBT::Input.new(non_witness_utxo: non_witness_utxo, witness_utxo: witness_utxo) combined.unknowns = unknowns.merge(psbi.unknowns) combined.redeem_script = redeem_script combined.witness_script = witness_script combined.sighash_type = sighash_type sigs = Hash[partial_sigs.merge(psbi.partial_sigs)] redeem_script.get_multisig_pubkeys.each{|pubkey|combined.partial_sigs[pubkey.bth] = sigs[pubkey.bth]} if redeem_script && redeem_script.multisig? witness_script.get_multisig_pubkeys.each{|pubkey|combined.partial_sigs[pubkey.bth] = sigs[pubkey.bth]} if witness_script && witness_script.multisig? combined.hd_key_paths = hd_key_paths.merge(psbi.hd_key_paths) combined end |
#sane? ⇒ Boolean
Sanity check
100 101 102 103 104 105 |
# File 'lib/bitcoin/psbt/input.rb', line 100 def sane? return false if non_witness_utxo && witness_utxo return false if witness_script && witness_utxo.nil? return false if final_script_witness && witness_utxo.nil? true end |
#to_payload ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/bitcoin/psbt/input.rb', line 81 def to_payload payload = '' payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:non_witness_utxo], value: non_witness_utxo.to_payload) if non_witness_utxo payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:witness_utxo], value: witness_utxo.to_payload) if witness_utxo if final_script_sig.nil? && final_script_witness.nil? payload << partial_sigs.map{|k, v|PSBT.serialize_to_vector(PSBT_IN_TYPES[:partial_sig], key: k.htb, value: v)}.join payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:sighash], value: [sighash_type].pack('I')) if sighash_type payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:redeem_script], value: redeem_script.to_payload) if redeem_script payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:witness_script], value: witness_script.to_payload) if witness_script payload << hd_key_paths.values.map(&:to_payload).join end payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:script_sig], value: final_script_sig.to_payload) if final_script_sig payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:script_witness], value: final_script_witness.to_payload) if final_script_witness payload << unknowns.map {|k,v|Bitcoin.pack_var_int(k.htb.bytesize) << k.htb << Bitcoin.pack_var_int(v.bytesize) << v}.join payload << PSBT_SEPARATOR.to_even_length_hex.htb payload end |