bsv-sdk 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -0
  3. data/README.md +4 -2
  4. data/lib/bsv/kv_store/entry.rb +15 -0
  5. data/lib/bsv/kv_store/global.rb +210 -0
  6. data/lib/bsv/kv_store/interpreter.rb +109 -0
  7. data/lib/bsv/kv_store/token.rb +10 -0
  8. data/lib/bsv/kv_store.rb +10 -0
  9. data/lib/bsv/mcp/tools/helpers.rb +3 -3
  10. data/lib/bsv/overlay/admin_token_template.rb +2 -2
  11. data/lib/bsv/overlay/historian.rb +118 -0
  12. data/lib/bsv/overlay/topic_broadcaster.rb +1 -1
  13. data/lib/bsv/overlay.rb +1 -0
  14. data/lib/bsv/primitives/digest.rb +107 -13
  15. data/lib/bsv/primitives/ecies.rb +12 -3
  16. data/lib/bsv/registry/client.rb +43 -1
  17. data/lib/bsv/script/bip276.rb +143 -0
  18. data/lib/bsv/script/interpreter/error.rb +2 -0
  19. data/lib/bsv/script/interpreter/interpreter.rb +226 -7
  20. data/lib/bsv/script/interpreter/operations/flow_control.rb +30 -13
  21. data/lib/bsv/script/push_drop_template.rb +2 -2
  22. data/lib/bsv/script/script.rb +21 -2
  23. data/lib/bsv/script.rb +1 -0
  24. data/lib/bsv/storage/downloader.rb +174 -0
  25. data/lib/bsv/storage/errors.rb +8 -0
  26. data/lib/bsv/storage/utils.rb +90 -0
  27. data/lib/bsv/storage.rb +16 -0
  28. data/lib/bsv/transaction/beef.rb +168 -14
  29. data/lib/bsv/transaction/beef_party.rb +119 -0
  30. data/lib/bsv/transaction/chain_tracker.rb +1 -1
  31. data/lib/bsv/transaction/fee_model.rb +1 -1
  32. data/lib/bsv/transaction/fee_models/live_policy.rb +1 -1
  33. data/lib/bsv/transaction/fee_models/satoshis_per_kilobyte.rb +1 -1
  34. data/lib/bsv/transaction/merkle_path.rb +1 -1
  35. data/lib/bsv/transaction/p2pkh.rb +1 -1
  36. data/lib/bsv/transaction/transaction_input.rb +78 -14
  37. data/lib/bsv/transaction/transaction_output.rb +46 -6
  38. data/lib/bsv/transaction/tx.rb +370 -39
  39. data/lib/bsv/transaction/unlocking_script_template.rb +2 -2
  40. data/lib/bsv/transaction.rb +1 -0
  41. data/lib/bsv/version.rb +1 -1
  42. data/lib/bsv-sdk.rb +2 -0
  43. metadata +13 -2
  44. data/lib/bsv/secp256k1_native.bundle +0 -0
@@ -14,19 +14,42 @@ module BSV
14
14
  # @return [Integer] index of the output within the previous transaction
15
15
  attr_reader :prev_tx_out_index
16
16
 
17
- # @return [Integer] sequence number (default: 0xFFFFFFFF)
18
- attr_accessor :sequence
19
-
20
- # @return [Script::Script, nil] the unlocking script (set after signing)
21
- attr_accessor :unlocking_script
17
+ # @!attribute [rw] sequence
18
+ # @return [Integer] sequence number (default: 0xFFFFFFFF)
19
+ # @note Setting this invalidates the owning Tx's wire cache and the
20
+ # hash_sequence component of the sighash cache. See
21
+ # {file:docs/reference/sighash-cache.md}.
22
+ attr_reader :sequence
23
+
24
+ # @!attribute [rw] unlocking_script
25
+ # @return [Script::Script, nil] the unlocking script (set after signing)
26
+ # @note Setting this invalidates the owning Tx's wire cache only.
27
+ # The unlocking script does not enter the BIP-143 preimage, so the
28
+ # sighash component caches are not touched. See
29
+ # {file:docs/reference/sighash-cache.md}.
30
+ attr_reader :unlocking_script
22
31
 
23
32
  # @return [Integer, nil] satoshi value of the source output (needed for sighash)
33
+ # @note Enters the BIP-143 preimage at step 6 but no current cache layer
34
+ # memoises the per-input preimage, so no invalidator is required. If a
35
+ # future change adds preimage or per-input digest memoisation, add a
36
+ # setter override here that invalidates the relevant cache slice. See
37
+ # {file:docs/reference/sighash-cache.md}.
24
38
  attr_accessor :source_satoshis
25
39
 
26
40
  # @return [Script::Script, nil] locking script of the source output (needed for sighash)
41
+ # @note Enters the BIP-143 preimage as scriptCode (step 5) when no
42
+ # subscript override is supplied. Same caveat as {#source_satoshis}:
43
+ # no current cache layer depends on this field, but a future preimage
44
+ # cache would need a setter override here. See
45
+ # {file:docs/reference/sighash-cache.md}.
27
46
  attr_accessor :source_locking_script
28
47
 
29
- # @return [Tx, nil] the full source transaction (for BEEF wiring)
48
+ # @return [Transaction::Tx, nil] the full source transaction (for BEEF wiring)
49
+ # @note Source data is lazily resolved from this Tx during {Tx#verify}
50
+ # and {Tx#sighash_preimage}. Mutation of this field after resolution
51
+ # has occurred has no effect on caches because no current cache layer
52
+ # depends on resolved source data.
30
53
  attr_accessor :source_transaction
31
54
 
32
55
  # @return [UnlockingScriptTemplate, nil] template for deferred signing
@@ -38,23 +61,60 @@ module BSV
38
61
  # @param sequence [Integer] sequence number
39
62
  def initialize(prev_wtxid:, prev_tx_out_index:, unlocking_script: nil, sequence: 0xFFFFFFFF)
40
63
  BSV::Primitives::Hex.validate_wtxid!(prev_wtxid, name: 'prev_wtxid')
41
- @prev_wtxid = prev_wtxid.b
64
+ # Defensively copy + freeze so external mutation of the caller's String
65
+ # cannot stale the cached outpoint_binary / to_binary.
66
+ @prev_wtxid = prev_wtxid.b.dup.freeze
42
67
  @prev_tx_out_index = prev_tx_out_index
43
68
  @unlocking_script = unlocking_script
44
69
  @sequence = sequence
70
+ @owning_tx = nil
45
71
  BSV.logger&.debug { "[TransactionInput] prev_wtxid set: #{dtxid_hex}:#{@prev_tx_out_index}" }
46
72
  end
47
73
 
74
+ # Called by +#dup+ and +#clone+. Clears the owning-Tx backref so that the
75
+ # cloned input does not belong to any transaction until it is explicitly
76
+ # added via +Tx#add_input+.
77
+ def initialize_copy(other)
78
+ super
79
+ @owning_tx = nil
80
+ end
81
+
82
+ # Sets the sequence number and invalidates the L1 binary memo and any
83
+ # owning-Tx slice caches that incorporate sequence (BIP-143 preimage
84
+ # and wire format).
85
+ #
86
+ # @param value [Integer] new sequence number
87
+ def sequence=(value)
88
+ @sequence = value
89
+ @to_binary = nil
90
+ @owning_tx&.send(:invalidate_sequence_components_cache)
91
+ @owning_tx&.send(:invalidate_wire_cache)
92
+ end
93
+
94
+ # Sets the unlocking script and invalidates the L1 binary memo and the
95
+ # owning-Tx wire cache. Unlocking script does not enter the BIP-143
96
+ # preimage, so the sequence/outputs components caches are not touched.
97
+ #
98
+ # @param value [Script::Script, nil] new unlocking script
99
+ def unlocking_script=(value)
100
+ @unlocking_script = value
101
+ @to_binary = nil
102
+ @owning_tx&.send(:invalidate_wire_cache)
103
+ end
104
+
48
105
  # Serialise the input to its binary wire format.
49
106
  #
107
+ # @note Memoised; see {file:docs/reference/sighash-cache.md} for the invalidation contract.
50
108
  # @return [String] binary input (outpoint + varint + script + sequence)
51
109
  def to_binary
52
- script_bytes = @unlocking_script ? @unlocking_script.to_binary : ''.b
53
- @prev_wtxid +
54
- [@prev_tx_out_index].pack('V') +
55
- VarInt.encode(script_bytes.bytesize) +
56
- script_bytes +
57
- [@sequence].pack('V')
110
+ @to_binary ||= begin
111
+ script_bytes = @unlocking_script ? @unlocking_script.to_binary : ''.b
112
+ (@prev_wtxid +
113
+ [@prev_tx_out_index].pack('V') +
114
+ VarInt.encode(script_bytes.bytesize) +
115
+ script_bytes +
116
+ [@sequence].pack('V')).freeze
117
+ end
58
118
  end
59
119
 
60
120
  # Deserialise a transaction input from binary data.
@@ -113,9 +173,13 @@ module BSV
113
173
 
114
174
  # Serialise the outpoint (prev_wtxid + output index) as binary.
115
175
  #
176
+ # Memoised: outpoint components are +attr_reader+ only so the value is
177
+ # immutable after construction. Returns a frozen binary string.
178
+ #
179
+ # @note Memoised; see {file:docs/reference/sighash-cache.md} for the invalidation contract.
116
180
  # @return [String] 36-byte outpoint
117
181
  def outpoint_binary
118
- @prev_wtxid + [@prev_tx_out_index].pack('V')
182
+ @outpoint_binary ||= (@prev_wtxid + [@prev_tx_out_index].pack('V')).freeze
119
183
  end
120
184
 
121
185
  # The previous transaction ID in display-order hex.
@@ -8,11 +8,17 @@ module BSV
8
8
  # Outputs are consumed by transaction inputs that provide matching
9
9
  # unlocking scripts.
10
10
  class TransactionOutput
11
- # @return [Integer] the output value in satoshis
12
- attr_accessor :satoshis
11
+ # @!attribute [rw] satoshis
12
+ # @return [Integer] the output value in satoshis
13
+ # @note Setting this invalidates the owning Tx's outputs-components
14
+ # and wire caches. See {file:docs/reference/sighash-cache.md}.
15
+ attr_reader :satoshis
13
16
 
14
- # @return [Script::Script] the locking script (spending conditions)
15
- attr_accessor :locking_script
17
+ # @!attribute [rw] locking_script
18
+ # @return [Script::Script] the locking script (spending conditions)
19
+ # @note Setting this invalidates the owning Tx's outputs-components
20
+ # and wire caches. See {file:docs/reference/sighash-cache.md}.
21
+ attr_reader :locking_script
16
22
 
17
23
  # @return [Boolean] whether this output receives change
18
24
  attr_accessor :change
@@ -24,14 +30,48 @@ module BSV
24
30
  @satoshis = satoshis
25
31
  @locking_script = locking_script
26
32
  @change = change
33
+ @owning_tx = nil
34
+ end
35
+
36
+ # Called by +#dup+ and +#clone+. Clears the owning-Tx backref so that the
37
+ # cloned output does not belong to any transaction until it is explicitly
38
+ # added via +Tx#add_output+.
39
+ def initialize_copy(other)
40
+ super
41
+ @owning_tx = nil
42
+ end
43
+
44
+ # Sets the satoshi value and invalidates the L1 binary memo and the
45
+ # owning-Tx outputs-components and wire caches.
46
+ #
47
+ # @param value [Integer] new satoshi value
48
+ def satoshis=(value)
49
+ @satoshis = value
50
+ @to_binary = nil
51
+ @owning_tx&.send(:invalidate_outputs_components_cache)
52
+ @owning_tx&.send(:invalidate_wire_cache)
53
+ end
54
+
55
+ # Sets the locking script and invalidates the L1 binary memo and the
56
+ # owning-Tx outputs-components and wire caches.
57
+ #
58
+ # @param value [Script::Script] new locking script
59
+ def locking_script=(value)
60
+ @locking_script = value
61
+ @to_binary = nil
62
+ @owning_tx&.send(:invalidate_outputs_components_cache)
63
+ @owning_tx&.send(:invalidate_wire_cache)
27
64
  end
28
65
 
29
66
  # Serialise the output to its binary wire format.
30
67
  #
68
+ # @note Memoised; see {file:docs/reference/sighash-cache.md} for the invalidation contract.
31
69
  # @return [String] binary output (8-byte LE satoshis + varint + script)
32
70
  def to_binary
33
- script_bytes = @locking_script.to_binary
34
- [satoshis].pack('Q<') + VarInt.encode(script_bytes.bytesize) + script_bytes
71
+ @to_binary ||= begin
72
+ script_bytes = @locking_script.to_binary
73
+ ([@satoshis].pack('Q<') + VarInt.encode(script_bytes.bytesize) + script_bytes).freeze
74
+ end
35
75
  end
36
76
 
37
77
  # Deserialise a transaction output from binary data.