bsv-sdk 0.2.1 → 0.3.1
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.
- checksums.yaml +4 -4
- data/lib/bsv/network/arc.rb +11 -2
- data/lib/bsv/network/broadcast_response.rb +1 -2
- data/lib/bsv/primitives/bsm.rb +2 -6
- data/lib/bsv/primitives/curve.rb +1 -2
- data/lib/bsv/primitives/encrypted_message.rb +100 -0
- data/lib/bsv/primitives/extended_key.rb +1 -2
- data/lib/bsv/primitives/key_shares.rb +83 -0
- data/lib/bsv/primitives/mnemonic.rb +1 -3
- data/lib/bsv/primitives/point_in_finite_field.rb +72 -0
- data/lib/bsv/primitives/polynomial.rb +95 -0
- data/lib/bsv/primitives/private_key.rb +100 -3
- data/lib/bsv/primitives/signed_message.rb +104 -0
- data/lib/bsv/primitives/symmetric_key.rb +128 -0
- data/lib/bsv/primitives.rb +18 -12
- data/lib/bsv/script/interpreter/interpreter.rb +1 -3
- data/lib/bsv/script/interpreter/operations/bitwise.rb +1 -3
- data/lib/bsv/script/interpreter/operations/crypto.rb +3 -9
- data/lib/bsv/script/interpreter/operations/flow_control.rb +2 -6
- data/lib/bsv/script/interpreter/operations/splice.rb +1 -3
- data/lib/bsv/script/interpreter/script_number.rb +2 -7
- data/lib/bsv/script/script.rb +252 -1
- data/lib/bsv/transaction/beef.rb +1 -4
- data/lib/bsv/transaction/transaction.rb +123 -45
- data/lib/bsv/transaction/transaction_input.rb +1 -2
- data/lib/bsv/transaction/transaction_output.rb +1 -2
- data/lib/bsv/transaction/var_int.rb +4 -16
- data/lib/bsv/transaction.rb +14 -14
- data/lib/bsv/version.rb +1 -1
- data/lib/bsv/wallet_interface/chain_provider.rb +37 -0
- data/lib/bsv/wallet_interface/errors/invalid_hmac_error.rb +11 -0
- data/lib/bsv/wallet_interface/errors/invalid_parameter_error.rb +14 -0
- data/lib/bsv/wallet_interface/errors/invalid_signature_error.rb +11 -0
- data/lib/bsv/wallet_interface/errors/unsupported_action_error.rb +11 -0
- data/lib/bsv/wallet_interface/errors/wallet_error.rb +14 -0
- data/lib/bsv/wallet_interface/interface.rb +384 -0
- data/lib/bsv/wallet_interface/key_deriver.rb +144 -0
- data/lib/bsv/wallet_interface/memory_store.rb +130 -0
- data/lib/bsv/wallet_interface/null_chain_provider.rb +22 -0
- data/lib/bsv/wallet_interface/proto_wallet.rb +361 -0
- data/lib/bsv/wallet_interface/storage_adapter.rb +55 -0
- data/lib/bsv/wallet_interface/validators.rb +126 -0
- data/lib/bsv/wallet_interface/version.rb +7 -0
- data/lib/bsv/wallet_interface/wallet_client.rb +748 -0
- data/lib/bsv/wallet_interface.rb +27 -0
- data/lib/bsv-wallet.rb +4 -0
- metadata +26 -3
- /data/{LICENCE → LICENSE} +0 -0
|
@@ -19,6 +19,19 @@ module BSV
|
|
|
19
19
|
# Estimated size of an unsigned P2PKH input in bytes.
|
|
20
20
|
UNSIGNED_P2PKH_INPUT_SIZE = 148
|
|
21
21
|
|
|
22
|
+
# Lookup table for benford_number calculation.
|
|
23
|
+
# we want float values for log10(1 + (1.0 / i)) for the 9 integers 0 < i < 10
|
|
24
|
+
# in ruby this becomes: (1..9).to_a.collect{|d| Math.log10(1 + (1.0 / d)) }
|
|
25
|
+
LOG10_RECIPROCAL_D_VALUES_1TO9 = [0.3010299956639812,
|
|
26
|
+
0.17609125905568124,
|
|
27
|
+
0.12493873660829993,
|
|
28
|
+
0.09691001300805642,
|
|
29
|
+
0.07918124604762482,
|
|
30
|
+
0.06694678963061322,
|
|
31
|
+
0.05799194697768673,
|
|
32
|
+
0.05115252244738129,
|
|
33
|
+
0.04575749056067514].freeze
|
|
34
|
+
|
|
22
35
|
# @return [Integer] transaction version number
|
|
23
36
|
attr_reader :version
|
|
24
37
|
|
|
@@ -149,8 +162,7 @@ module BSV
|
|
|
149
162
|
end
|
|
150
163
|
|
|
151
164
|
if data.bytesize < offset + 4
|
|
152
|
-
raise ArgumentError,
|
|
153
|
-
"truncated transaction: need 4 bytes for lock_time at offset #{offset}, got #{data.bytesize - offset}"
|
|
165
|
+
raise ArgumentError, "truncated transaction: need 4 bytes for lock_time at offset #{offset}, got #{data.bytesize - offset}"
|
|
154
166
|
end
|
|
155
167
|
|
|
156
168
|
tx.instance_variable_set(:@lock_time, data.byteslice(offset, 4).unpack1('V'))
|
|
@@ -171,10 +183,7 @@ module BSV
|
|
|
171
183
|
# @return [Transaction] the parsed transaction with source data on inputs
|
|
172
184
|
# @raise [ArgumentError] if the EF marker is invalid
|
|
173
185
|
def self.from_ef(data)
|
|
174
|
-
if data.bytesize < 10
|
|
175
|
-
raise ArgumentError,
|
|
176
|
-
"truncated EF transaction: need at least 10 bytes, got #{data.bytesize}"
|
|
177
|
-
end
|
|
186
|
+
raise ArgumentError, "truncated EF transaction: need at least 10 bytes, got #{data.bytesize}" if data.bytesize < 10
|
|
178
187
|
|
|
179
188
|
offset = 0
|
|
180
189
|
|
|
@@ -197,8 +206,7 @@ module BSV
|
|
|
197
206
|
|
|
198
207
|
if data.bytesize < offset + 8
|
|
199
208
|
remaining = data.bytesize - offset
|
|
200
|
-
raise ArgumentError,
|
|
201
|
-
"truncated EF input: need 8 bytes for source_satoshis at offset #{offset}, got #{remaining}"
|
|
209
|
+
raise ArgumentError, "truncated EF input: need 8 bytes for source_satoshis at offset #{offset}, got #{remaining}"
|
|
202
210
|
end
|
|
203
211
|
|
|
204
212
|
input.source_satoshis = data.byteslice(offset, 8).unpack1('Q<')
|
|
@@ -222,8 +230,7 @@ module BSV
|
|
|
222
230
|
|
|
223
231
|
if data.bytesize < offset + 4
|
|
224
232
|
remaining = data.bytesize - offset
|
|
225
|
-
raise ArgumentError,
|
|
226
|
-
"truncated EF transaction: need 4 bytes for lock_time at offset #{offset}, got #{remaining}"
|
|
233
|
+
raise ArgumentError, "truncated EF transaction: need 4 bytes for lock_time at offset #{offset}, got #{remaining}"
|
|
227
234
|
end
|
|
228
235
|
|
|
229
236
|
tx.instance_variable_set(:@lock_time, data.byteslice(offset, 4).unpack1('V'))
|
|
@@ -246,8 +253,7 @@ module BSV
|
|
|
246
253
|
# @return [Array(Transaction, Integer)] the transaction and bytes consumed
|
|
247
254
|
def self.from_binary_with_offset(data, offset = 0)
|
|
248
255
|
if data.bytesize < offset + 10
|
|
249
|
-
raise ArgumentError,
|
|
250
|
-
"truncated transaction: need at least 10 bytes at offset #{offset}, got #{data.bytesize - offset}"
|
|
256
|
+
raise ArgumentError, "truncated transaction: need at least 10 bytes at offset #{offset}, got #{data.bytesize - offset}"
|
|
251
257
|
end
|
|
252
258
|
|
|
253
259
|
start = offset
|
|
@@ -274,8 +280,7 @@ module BSV
|
|
|
274
280
|
end
|
|
275
281
|
|
|
276
282
|
if data.bytesize < offset + 4
|
|
277
|
-
raise ArgumentError,
|
|
278
|
-
"truncated transaction: need 4 bytes for lock_time at offset #{offset}, got #{data.bytesize - offset}"
|
|
283
|
+
raise ArgumentError, "truncated transaction: need 4 bytes for lock_time at offset #{offset}, got #{data.bytesize - offset}"
|
|
279
284
|
end
|
|
280
285
|
|
|
281
286
|
tx.instance_variable_set(:@lock_time, data.byteslice(offset, 4).unpack1('V'))
|
|
@@ -557,10 +562,7 @@ module BSV
|
|
|
557
562
|
# @return [Integer] total input value in satoshis
|
|
558
563
|
def total_input_satoshis
|
|
559
564
|
@inputs.each_with_index do |input, idx|
|
|
560
|
-
if input.source_satoshis.nil?
|
|
561
|
-
raise ArgumentError,
|
|
562
|
-
"input #{idx} has nil source_satoshis — set it before computing totals"
|
|
563
|
-
end
|
|
565
|
+
raise ArgumentError, "input #{idx} has nil source_satoshis — set it before computing totals" if input.source_satoshis.nil?
|
|
564
566
|
end
|
|
565
567
|
@inputs.sum(&:source_satoshis)
|
|
566
568
|
end
|
|
@@ -611,15 +613,29 @@ module BSV
|
|
|
611
613
|
# Accepts a {FeeModel} instance, a numeric fee in satoshis, or nil
|
|
612
614
|
# (defaults to {FeeModels::SatoshisPerKilobyte} at 50 sat/kB).
|
|
613
615
|
#
|
|
614
|
-
# After computing the fee, distributes remaining satoshis
|
|
615
|
-
#
|
|
616
|
-
#
|
|
616
|
+
# After computing the fee, distributes remaining satoshis across outputs
|
|
617
|
+
# marked as change. The distribution strategy is controlled by the
|
|
618
|
+
# +change_distribution:+ keyword argument:
|
|
619
|
+
#
|
|
620
|
+
# - +:equal+ (default) — divides change equally across all change outputs,
|
|
621
|
+
# matching TS SDK default behaviour.
|
|
622
|
+
# - +:random+ — Benford-inspired distribution that biases amounts towards
|
|
623
|
+
# the lower end of the available range, improving privacy by producing
|
|
624
|
+
# varied change amounts.
|
|
625
|
+
#
|
|
626
|
+
# If insufficient change remains, all change outputs are removed.
|
|
617
627
|
#
|
|
618
628
|
# @param model_or_fee [FeeModel, Integer, nil] fee model, fixed fee, or nil for default
|
|
629
|
+
# @param change_distribution [Symbol] +:equal+ or +:random+ (default: +:equal+)
|
|
619
630
|
# @return [self] for chaining
|
|
620
|
-
|
|
631
|
+
# @raise [ArgumentError] if +change_distribution+ is not +:random+ or +:equal+
|
|
632
|
+
def fee(model_or_fee = nil, change_distribution: :equal)
|
|
633
|
+
unless %i[random equal].include?(change_distribution)
|
|
634
|
+
raise ArgumentError, "invalid change_distribution #{change_distribution.inspect}; expected :random or :equal"
|
|
635
|
+
end
|
|
636
|
+
|
|
621
637
|
fee_sats = compute_fee_sats(model_or_fee)
|
|
622
|
-
distribute_change(fee_sats)
|
|
638
|
+
distribute_change(fee_sats, change_distribution)
|
|
623
639
|
self
|
|
624
640
|
end
|
|
625
641
|
|
|
@@ -627,18 +643,9 @@ module BSV
|
|
|
627
643
|
|
|
628
644
|
def verify_input_requirements(tx, input, index)
|
|
629
645
|
tx_id = tx.txid_hex
|
|
630
|
-
if input.unlocking_script.nil?
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
end
|
|
634
|
-
if input.source_locking_script.nil?
|
|
635
|
-
raise ArgumentError,
|
|
636
|
-
"input #{index} of transaction #{tx_id} has no source locking script"
|
|
637
|
-
end
|
|
638
|
-
return unless input.source_satoshis.nil?
|
|
639
|
-
|
|
640
|
-
raise ArgumentError,
|
|
641
|
-
"input #{index} of transaction #{tx_id} has no source satoshis"
|
|
646
|
+
raise ArgumentError, "input #{index} of transaction #{tx_id} has no unlocking script" if input.unlocking_script.nil?
|
|
647
|
+
raise ArgumentError, "input #{index} of transaction #{tx_id} has no source locking script" if input.source_locking_script.nil?
|
|
648
|
+
raise ArgumentError, "input #{index} of transaction #{tx_id} has no source satoshis" if input.source_satoshis.nil?
|
|
642
649
|
end
|
|
643
650
|
|
|
644
651
|
def verify_fee(fee_model)
|
|
@@ -647,8 +654,7 @@ module BSV
|
|
|
647
654
|
return if actual_fee >= required_fee
|
|
648
655
|
|
|
649
656
|
raise VerificationError.new(:insufficient_fee,
|
|
650
|
-
"insufficient fee: transaction pays #{actual_fee} sat "
|
|
651
|
-
"but fee model requires #{required_fee} sat")
|
|
657
|
+
"insufficient fee: transaction pays #{actual_fee} sat but fee model requires #{required_fee} sat")
|
|
652
658
|
end
|
|
653
659
|
|
|
654
660
|
def verify_output_constraint(tx)
|
|
@@ -657,8 +663,7 @@ module BSV
|
|
|
657
663
|
return if output_total <= input_total
|
|
658
664
|
|
|
659
665
|
raise VerificationError.new(:output_overflow,
|
|
660
|
-
"outputs (#{output_total}) exceed inputs (#{input_total}) "
|
|
661
|
-
"for transaction #{tx.txid_hex}")
|
|
666
|
+
"outputs (#{output_total}) exceed inputs (#{input_total}) for transaction #{tx.txid_hex}")
|
|
662
667
|
end
|
|
663
668
|
|
|
664
669
|
ZERO_HASH = "\x00".b * 32
|
|
@@ -731,7 +736,7 @@ module BSV
|
|
|
731
736
|
end
|
|
732
737
|
end
|
|
733
738
|
|
|
734
|
-
def distribute_change(fee_sats)
|
|
739
|
+
def distribute_change(fee_sats, change_distribution)
|
|
735
740
|
change_outputs = @outputs.select(&:change)
|
|
736
741
|
return if change_outputs.empty?
|
|
737
742
|
|
|
@@ -741,14 +746,87 @@ module BSV
|
|
|
741
746
|
|
|
742
747
|
if available <= change_outputs.length
|
|
743
748
|
@outputs.reject!(&:change)
|
|
749
|
+
return
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
if change_distribution == :random
|
|
753
|
+
distribute_random_change(available, change_outputs)
|
|
744
754
|
else
|
|
745
|
-
|
|
746
|
-
remainder = available % change_outputs.length
|
|
747
|
-
change_outputs.each_with_index do |output, i|
|
|
748
|
-
output.satoshis = per_output + (i < remainder ? 1 : 0)
|
|
749
|
-
end
|
|
755
|
+
distribute_equal_change(available, change_outputs)
|
|
750
756
|
end
|
|
751
757
|
end
|
|
758
|
+
|
|
759
|
+
def distribute_equal_change(available, change_outputs)
|
|
760
|
+
per_output = available / change_outputs.length
|
|
761
|
+
remainder = available % change_outputs.length
|
|
762
|
+
change_outputs.each_with_index do |output, i|
|
|
763
|
+
output.satoshis = per_output + (i < remainder ? 1 : 0)
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# Distribute change using a Benford-inspired algorithm that biases amounts
|
|
768
|
+
# towards the lower end of the available range.
|
|
769
|
+
#
|
|
770
|
+
# Algorithm:
|
|
771
|
+
# 1. Reserve 1 satoshi per change output as a minimum guarantee.
|
|
772
|
+
# 2. For each output except the last, take a Benford-scaled portion of the
|
|
773
|
+
# remaining pool and add it to that output's base amount.
|
|
774
|
+
# 3. The last change output receives only its 1 sat base.
|
|
775
|
+
# 4. Any remainder (from floor rounding) is assigned to the last transaction
|
|
776
|
+
# output, matching TS SDK behaviour.
|
|
777
|
+
#
|
|
778
|
+
# @param available [Integer] total satoshis to distribute
|
|
779
|
+
# @param change_outputs [Array<TransactionOutput>] outputs flagged as change
|
|
780
|
+
# @return [void]
|
|
781
|
+
def distribute_random_change(available, change_outputs)
|
|
782
|
+
n = change_outputs.length
|
|
783
|
+
|
|
784
|
+
# Initialise each output with a 1-sat base and reserve that pool
|
|
785
|
+
amounts = Array.new(n, 1)
|
|
786
|
+
pool = available - n
|
|
787
|
+
distributed = n
|
|
788
|
+
|
|
789
|
+
# Allocate Benford-scaled portions to all outputs except the last
|
|
790
|
+
(n - 1).times do |i|
|
|
791
|
+
portion = benford_number(0, pool)
|
|
792
|
+
amounts[i] += portion
|
|
793
|
+
distributed += portion
|
|
794
|
+
pool -= portion
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
# Assign computed amounts to change outputs
|
|
798
|
+
change_outputs.each_with_index do |output, i|
|
|
799
|
+
output.satoshis = amounts[i]
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
# Assign any remainder (floor-rounding loss) to the last transaction output
|
|
803
|
+
remainder = available - distributed
|
|
804
|
+
return unless remainder.positive?
|
|
805
|
+
|
|
806
|
+
last_output = @outputs.last
|
|
807
|
+
last_output.satoshis = (last_output.satoshis || 0) + remainder
|
|
808
|
+
end
|
|
809
|
+
|
|
810
|
+
# Generate a Benford-inspired integer in the range [min, max).
|
|
811
|
+
#
|
|
812
|
+
# Randomly selects a scale factor that biases the result towards the lower end of
|
|
813
|
+
# the range, based on the Benford distribution of leading digits.
|
|
814
|
+
#
|
|
815
|
+
# Reference ts SDK implementation
|
|
816
|
+
# Math.floor(min + ((max - min) * Math.log10(1 + 1 / d)) / Math.log10(10))
|
|
817
|
+
#
|
|
818
|
+
# We simplify:
|
|
819
|
+
# - log10(10) = 1, divide by 1 is a no-op, removed it
|
|
820
|
+
# - pre-calculated the 9 possible values to a look-up table LOG10_RECIPROCAL_D_VALUES_1TO9
|
|
821
|
+
# - rearrange to "start at min, add a scaled portion of the range"
|
|
822
|
+
#
|
|
823
|
+
# @param min [Integer] lower bound (inclusive)
|
|
824
|
+
# @param max [Integer] upper bound (exclusive)
|
|
825
|
+
# @return [Integer] Benford-distributed integer
|
|
826
|
+
def benford_number(min, max)
|
|
827
|
+
scale_factor = LOG10_RECIPROCAL_D_VALUES_1TO9[Random.rand(9)] # Array indexing starts at 0
|
|
828
|
+
(min + (scale_factor * (max - min))).floor
|
|
829
|
+
end
|
|
752
830
|
end
|
|
753
831
|
end
|
|
754
832
|
end
|
|
@@ -74,9 +74,8 @@ module BSV
|
|
|
74
74
|
offset += vi_size
|
|
75
75
|
|
|
76
76
|
if data.bytesize < offset + script_len
|
|
77
|
-
remaining = data.bytesize - offset
|
|
78
77
|
raise ArgumentError,
|
|
79
|
-
"truncated input: need #{script_len} bytes for script at offset #{offset}, got #{
|
|
78
|
+
"truncated input: need #{script_len} bytes for script at offset #{offset}, got #{data.bytesize - offset}"
|
|
80
79
|
end
|
|
81
80
|
|
|
82
81
|
unlocking_script = (BSV::Script::Script.from_binary(data.byteslice(offset, script_len)) if script_len.positive?)
|
|
@@ -52,9 +52,8 @@ module BSV
|
|
|
52
52
|
offset += vi_size
|
|
53
53
|
|
|
54
54
|
if data.bytesize < offset + script_len
|
|
55
|
-
remaining = data.bytesize - offset
|
|
56
55
|
raise ArgumentError,
|
|
57
|
-
"truncated output: need #{script_len} bytes for script at offset #{offset}, got #{
|
|
56
|
+
"truncated output: need #{script_len} bytes for script at offset #{offset}, got #{data.bytesize - offset}"
|
|
58
57
|
end
|
|
59
58
|
|
|
60
59
|
script_bytes = data.byteslice(offset, script_len)
|
|
@@ -32,10 +32,7 @@ module BSV
|
|
|
32
32
|
# @param offset [Integer] byte offset to start reading from
|
|
33
33
|
# @return [Array(Integer, Integer)] the decoded value and number of bytes consumed
|
|
34
34
|
def decode(data, offset = 0)
|
|
35
|
-
if offset >= data.bytesize
|
|
36
|
-
raise ArgumentError,
|
|
37
|
-
"truncated varint: need 1 byte at offset #{offset}, got end of data"
|
|
38
|
-
end
|
|
35
|
+
raise ArgumentError, "truncated varint: need 1 byte at offset #{offset}, got end of data" if offset >= data.bytesize
|
|
39
36
|
|
|
40
37
|
first = data.getbyte(offset)
|
|
41
38
|
|
|
@@ -43,24 +40,15 @@ module BSV
|
|
|
43
40
|
when 0..0xFC
|
|
44
41
|
[first, 1]
|
|
45
42
|
when 0xFD
|
|
46
|
-
if data.bytesize < offset + 3
|
|
47
|
-
raise ArgumentError,
|
|
48
|
-
"truncated varint: need 3 bytes at offset #{offset}, got #{data.bytesize - offset}"
|
|
49
|
-
end
|
|
43
|
+
raise ArgumentError, "truncated varint: need 3 bytes at offset #{offset}, got #{data.bytesize - offset}" if data.bytesize < offset + 3
|
|
50
44
|
|
|
51
45
|
[data.byteslice(offset + 1, 2).unpack1('v'), 3]
|
|
52
46
|
when 0xFE
|
|
53
|
-
if data.bytesize < offset + 5
|
|
54
|
-
raise ArgumentError,
|
|
55
|
-
"truncated varint: need 5 bytes at offset #{offset}, got #{data.bytesize - offset}"
|
|
56
|
-
end
|
|
47
|
+
raise ArgumentError, "truncated varint: need 5 bytes at offset #{offset}, got #{data.bytesize - offset}" if data.bytesize < offset + 5
|
|
57
48
|
|
|
58
49
|
[data.byteslice(offset + 1, 4).unpack1('V'), 5]
|
|
59
50
|
when 0xFF
|
|
60
|
-
if data.bytesize < offset + 9
|
|
61
|
-
raise ArgumentError,
|
|
62
|
-
"truncated varint: need 9 bytes at offset #{offset}, got #{data.bytesize - offset}"
|
|
63
|
-
end
|
|
51
|
+
raise ArgumentError, "truncated varint: need 9 bytes at offset #{offset}, got #{data.bytesize - offset}" if data.bytesize < offset + 9
|
|
64
52
|
|
|
65
53
|
[data.byteslice(offset + 1, 8).unpack1('Q<'), 9]
|
|
66
54
|
end
|
data/lib/bsv/transaction.rb
CHANGED
|
@@ -8,19 +8,19 @@ module BSV
|
|
|
8
8
|
# {Transaction::MerklePath} for BRC-74 merkle proofs, and
|
|
9
9
|
# {Transaction::Sighash} constants for BIP-143 sighash computation.
|
|
10
10
|
module Transaction
|
|
11
|
-
autoload :VarInt,
|
|
12
|
-
autoload :TransactionOutput,
|
|
13
|
-
autoload :TransactionInput,
|
|
14
|
-
autoload :Sighash,
|
|
15
|
-
autoload :MerklePath,
|
|
16
|
-
autoload :FeeModel,
|
|
17
|
-
autoload :FeeModels,
|
|
18
|
-
autoload :VerificationError,
|
|
19
|
-
autoload :ChainTracker,
|
|
20
|
-
autoload :ChainTrackers,
|
|
21
|
-
autoload :Beef,
|
|
22
|
-
autoload :UnlockingScriptTemplate,
|
|
23
|
-
autoload :P2PKH,
|
|
24
|
-
autoload :Transaction,
|
|
11
|
+
autoload :VarInt, 'bsv/transaction/var_int'
|
|
12
|
+
autoload :TransactionOutput, 'bsv/transaction/transaction_output'
|
|
13
|
+
autoload :TransactionInput, 'bsv/transaction/transaction_input'
|
|
14
|
+
autoload :Sighash, 'bsv/transaction/sighash'
|
|
15
|
+
autoload :MerklePath, 'bsv/transaction/merkle_path'
|
|
16
|
+
autoload :FeeModel, 'bsv/transaction/fee_model'
|
|
17
|
+
autoload :FeeModels, 'bsv/transaction/fee_models'
|
|
18
|
+
autoload :VerificationError, 'bsv/transaction/verification_error'
|
|
19
|
+
autoload :ChainTracker, 'bsv/transaction/chain_tracker'
|
|
20
|
+
autoload :ChainTrackers, 'bsv/transaction/chain_trackers'
|
|
21
|
+
autoload :Beef, 'bsv/transaction/beef'
|
|
22
|
+
autoload :UnlockingScriptTemplate, 'bsv/transaction/unlocking_script_template'
|
|
23
|
+
autoload :P2PKH, 'bsv/transaction/p2pkh'
|
|
24
|
+
autoload :Transaction, 'bsv/transaction/transaction'
|
|
25
25
|
end
|
|
26
26
|
end
|
data/lib/bsv/version.rb
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
# Duck-typed interface for blockchain data providers.
|
|
6
|
+
#
|
|
7
|
+
# Include this module in chain provider adapters and override all methods.
|
|
8
|
+
# The default implementations raise NotImplementedError.
|
|
9
|
+
#
|
|
10
|
+
# @example Custom provider
|
|
11
|
+
# class MyChainProvider
|
|
12
|
+
# include BSV::Wallet::ChainProvider
|
|
13
|
+
#
|
|
14
|
+
# def get_height
|
|
15
|
+
# # query your node/API
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# def get_header(height)
|
|
19
|
+
# # return 80-byte hex block header
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
module ChainProvider
|
|
23
|
+
# Returns the current blockchain height.
|
|
24
|
+
# @return [Integer]
|
|
25
|
+
def get_height
|
|
26
|
+
raise NotImplementedError, "#{self.class}#get_height not implemented"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns the block header at the given height.
|
|
30
|
+
# @param _height [Integer] block height
|
|
31
|
+
# @return [String] 80-byte hex-encoded block header
|
|
32
|
+
def get_header(_height)
|
|
33
|
+
raise NotImplementedError, "#{self.class}#get_header not implemented"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
class InvalidParameterError < WalletError
|
|
6
|
+
attr_reader :parameter
|
|
7
|
+
|
|
8
|
+
def initialize(parameter, must_be = 'valid')
|
|
9
|
+
@parameter = parameter
|
|
10
|
+
super("The #{parameter} parameter must be #{must_be}", 6)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|