Class: BSV::Transaction::TransactionInput

Inherits:
Object
  • Object
show all
Defined in:
lib/bsv/transaction/transaction_input.rb

Overview

A transaction input referencing a previous output to spend.

Inputs identify the output being spent by its transaction ID and output index (the "outpoint"), and provide an unlocking script to satisfy the locking script conditions.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(prev_wtxid:, prev_tx_out_index:, unlocking_script: nil, sequence: 0xFFFFFFFF) ⇒ TransactionInput

Returns a new instance of TransactionInput.

Parameters:

  • prev_wtxid (String)

    32-byte wire-order transaction ID

  • prev_tx_out_index (Integer)

    output index in the previous transaction

  • unlocking_script (Script::Script, nil) (defaults to: nil)

    unlocking script (nil if unsigned)

  • sequence (Integer) (defaults to: 0xFFFFFFFF)

    sequence number



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/bsv/transaction/transaction_input.rb', line 62

def initialize(prev_wtxid:, prev_tx_out_index:, unlocking_script: nil, sequence: 0xFFFFFFFF)
  BSV::Primitives::Hex.validate_wtxid!(prev_wtxid, name: 'prev_wtxid')
  # Defensively copy + freeze so external mutation of the caller's String
  # cannot stale the cached outpoint_binary / to_binary.
  @prev_wtxid = prev_wtxid.b.dup.freeze
  @prev_tx_out_index = prev_tx_out_index
  @unlocking_script = unlocking_script
  @sequence = sequence
  @owning_tx = nil
  BSV.logger&.debug { "[TransactionInput] prev_wtxid set: #{dtxid_hex}:#{@prev_tx_out_index}" }
end

Instance Attribute Details

#prev_tx_out_indexInteger (readonly)

Returns index of the output within the previous transaction.

Returns:

  • (Integer)

    index of the output within the previous transaction



15
16
17
# File 'lib/bsv/transaction/transaction_input.rb', line 15

def prev_tx_out_index
  @prev_tx_out_index
end

#prev_wtxidString (readonly)

Returns 32-byte wire-order transaction ID of the output being spent.

Returns:

  • (String)

    32-byte wire-order transaction ID of the output being spent



12
13
14
# File 'lib/bsv/transaction/transaction_input.rb', line 12

def prev_wtxid
  @prev_wtxid
end

#sequenceObject

Returns the value of attribute sequence.



22
23
24
# File 'lib/bsv/transaction/transaction_input.rb', line 22

def sequence
  @sequence
end

#source_locking_scriptScript::Script?

Note:

Enters the BIP-143 preimage as scriptCode (step 5) when no subscript override is supplied. Same caveat as #source_satoshis: no current cache layer depends on this field, but a future preimage cache would need a setter override here. See sighash-cache.

Returns locking script of the source output (needed for sighash).

Returns:

  • (Script::Script, nil)

    locking script of the source output (needed for sighash)



46
47
48
# File 'lib/bsv/transaction/transaction_input.rb', line 46

def source_locking_script
  @source_locking_script
end

#source_satoshisInteger?

Note:

Enters the BIP-143 preimage at step 6 but no current cache layer memoises the per-input preimage, so no invalidator is required. If a future change adds preimage or per-input digest memoisation, add a setter override here that invalidates the relevant cache slice. See sighash-cache.

Returns satoshi value of the source output (needed for sighash).

Returns:

  • (Integer, nil)

    satoshi value of the source output (needed for sighash)



38
39
40
# File 'lib/bsv/transaction/transaction_input.rb', line 38

def source_satoshis
  @source_satoshis
end

#source_transactionTransaction::Tx?

Note:

Source data is lazily resolved from this Tx during BSV::Transaction::Tx#verify and BSV::Transaction::Tx#sighash_preimage. Mutation of this field after resolution has occurred has no effect on caches because no current cache layer depends on resolved source data.

Returns the full source transaction (for BEEF wiring).

Returns:



53
54
55
# File 'lib/bsv/transaction/transaction_input.rb', line 53

def source_transaction
  @source_transaction
end

#unlocking_scriptObject

Returns the value of attribute unlocking_script.



30
31
32
# File 'lib/bsv/transaction/transaction_input.rb', line 30

def unlocking_script
  @unlocking_script
end

#unlocking_script_templateUnlockingScriptTemplate?

Returns template for deferred signing.

Returns:



56
57
58
# File 'lib/bsv/transaction/transaction_input.rb', line 56

def unlocking_script_template
  @unlocking_script_template
end

Class Method Details

.from_binary(data, offset = 0) ⇒ Array(TransactionInput, Integer)

Deserialise a transaction input from binary data.

Parameters:

  • data (String)

    binary data

  • offset (Integer) (defaults to: 0)

    byte offset to start reading from

Returns:



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/bsv/transaction/transaction_input.rb', line 125

def self.from_binary(data, offset = 0)
  if data.bytesize < offset + 36
    raise ArgumentError,
          "truncated input: need 36 bytes for outpoint at offset #{offset}, got #{data.bytesize - offset}"
  end

  prev_wtxid = data.byteslice(offset, 32)
  prev_tx_out_index = data.byteslice(offset + 32, 4).unpack1('V')
  offset += 36

  script_len, vi_size = VarInt.decode(data, offset)
  offset += vi_size

  if data.bytesize < offset + script_len
    raise ArgumentError,
          "truncated input: need #{script_len} bytes for script at offset #{offset}, got #{data.bytesize - offset}"
  end

  unlocking_script = (BSV::Script::Script.from_binary(data.byteslice(offset, script_len)) if script_len.positive?)
  offset += script_len

  if data.bytesize < offset + 4
    raise ArgumentError,
          "truncated input: need 4 bytes for sequence at offset #{offset}, got #{data.bytesize - offset}"
  end

  sequence = data.byteslice(offset, 4).unpack1('V')

  total = 36 + vi_size + script_len + 4
  input = new(
    prev_wtxid: prev_wtxid,
    prev_tx_out_index: prev_tx_out_index,
    unlocking_script: unlocking_script,
    sequence: sequence
  )
  [input, total]
end

.wtxid_from_hex(hex) ⇒ String

Convert a display-order hex transaction ID to wire-order bytes.

Parameters:

  • hex (String)

    hex-encoded transaction ID (display order)

Returns:

  • (String)

    32-byte transaction ID in wire byte order



167
168
169
170
171
172
# File 'lib/bsv/transaction/transaction_input.rb', line 167

def self.wtxid_from_hex(hex)
  BSV::Primitives::Hex.validate_dtxid_hex!(hex, name: 'wtxid_from_hex input')
  wtxid = [hex].pack('H*').reverse
  BSV.logger&.debug { "[TransactionInput] wtxid_from_hex: #{hex} -> #{wtxid.bytesize}B wire-order" }
  wtxid
end

Instance Method Details

#dtxid_hexString

The previous transaction ID in display-order hex.

Returns:

  • (String)

    hex-encoded transaction ID (display order)



188
189
190
# File 'lib/bsv/transaction/transaction_input.rb', line 188

def dtxid_hex
  @prev_wtxid.reverse.unpack1('H*')
end

#initialize_copy(other) ⇒ Object

Called by #dup and #clone. Clears the owning-Tx backref so that the cloned input does not belong to any transaction until it is explicitly added via Tx#add_input.



77
78
79
80
# File 'lib/bsv/transaction/transaction_input.rb', line 77

def initialize_copy(other)
  super
  @owning_tx = nil
end

#outpoint_binaryString

Note:

Memoised; see sighash-cache for the invalidation contract.

Serialise the outpoint (prev_wtxid + output index) as binary.

Memoised: outpoint components are attr_reader only so the value is immutable after construction. Returns a frozen binary string.

Returns:

  • (String)

    36-byte outpoint



181
182
183
# File 'lib/bsv/transaction/transaction_input.rb', line 181

def outpoint_binary
  @outpoint_binary ||= (@prev_wtxid + [@prev_tx_out_index].pack('V')).freeze
end

#to_binaryString

Note:

Memoised; see sighash-cache for the invalidation contract.

Serialise the input to its binary wire format.

Returns:

  • (String)

    binary input (outpoint + varint + script + sequence)



109
110
111
112
113
114
115
116
117
118
# File 'lib/bsv/transaction/transaction_input.rb', line 109

def to_binary
  @to_binary ||= begin
    script_bytes = @unlocking_script ? @unlocking_script.to_binary : ''.b
    (@prev_wtxid +
      [@prev_tx_out_index].pack('V') +
      VarInt.encode(script_bytes.bytesize) +
      script_bytes +
      [@sequence].pack('V')).freeze
  end
end