bsv-sdk 0.19.1 → 0.22.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +89 -0
- data/README.md +2 -2
- data/lib/bsv/auth/transport.rb +1 -1
- data/lib/bsv/mcp/tools/broadcast_p2pkh.rb +5 -3
- data/lib/bsv/network/protocol.rb +4 -5
- data/lib/bsv/network/protocols/arc.rb +4 -30
- data/lib/bsv/network/protocols/arcade.rb +163 -0
- data/lib/bsv/network/protocols/chaintracks.rb +6 -3
- data/lib/bsv/network/protocols/jungle_bus.rb +6 -0
- data/lib/bsv/network/protocols.rb +1 -0
- data/lib/bsv/network/provider.rb +7 -9
- data/lib/bsv/network/providers/gorilla_pool.rb +18 -18
- data/lib/bsv/network/util.rb +44 -0
- data/lib/bsv/network.rb +1 -0
- data/lib/bsv/overlay/lookup_resolver.rb +0 -1
- data/lib/bsv/overlay/topic_broadcaster.rb +0 -1
- data/lib/bsv/primitives/curve.rb +1 -11
- data/lib/bsv/primitives/ecies.rb +1 -8
- data/lib/bsv/primitives/hex.rb +1 -1
- data/lib/bsv/script/script.rb +1 -1
- data/lib/bsv/transaction/beef.rb +0 -2
- data/lib/bsv/transaction/chain_tracker.rb +74 -13
- data/lib/bsv/transaction/chain_trackers/whats_on_chain.rb +3 -3
- data/lib/bsv/transaction/chain_trackers.rb +0 -10
- data/lib/bsv/transaction/fee_models/live_policy.rb +10 -8
- data/lib/bsv/transaction/merkle_path.rb +0 -2
- data/lib/bsv/version.rb +1 -1
- data/lib/bsv/wallet/errors.rb +65 -21
- data/lib/bsv/wallet/proto_wallet/validators.rb +7 -49
- data/lib/bsv/wallet/proto_wallet.rb +15 -8
- data/lib/bsv/wallet/serializer/abort_action.rb +38 -0
- data/lib/bsv/wallet/serializer/acquire_certificate.rb +171 -0
- data/lib/bsv/wallet/serializer/certificate.rb +184 -0
- data/lib/bsv/wallet/serializer/common.rb +207 -0
- data/lib/bsv/wallet/serializer/create_action_args.rb +259 -0
- data/lib/bsv/wallet/serializer/create_action_result.rb +85 -0
- data/lib/bsv/wallet/serializer/create_hmac.rb +67 -0
- data/lib/bsv/wallet/serializer/create_signature.rb +90 -0
- data/lib/bsv/wallet/serializer/decrypt.rb +60 -0
- data/lib/bsv/wallet/serializer/discover_by_attributes.rb +61 -0
- data/lib/bsv/wallet/serializer/discover_by_identity_key.rb +49 -0
- data/lib/bsv/wallet/serializer/discover_certificates_result.rb +39 -0
- data/lib/bsv/wallet/serializer/encrypt.rb +60 -0
- data/lib/bsv/wallet/serializer/get_header_for_height.rb +71 -0
- data/lib/bsv/wallet/serializer/get_height.rb +46 -0
- data/lib/bsv/wallet/serializer/get_network.rb +65 -0
- data/lib/bsv/wallet/serializer/get_public_key.rb +86 -0
- data/lib/bsv/wallet/serializer/get_version.rb +44 -0
- data/lib/bsv/wallet/serializer/internalize_action.rb +151 -0
- data/lib/bsv/wallet/serializer/list_actions.rb +348 -0
- data/lib/bsv/wallet/serializer/list_certificates.rb +124 -0
- data/lib/bsv/wallet/serializer/list_outputs.rb +167 -0
- data/lib/bsv/wallet/serializer/prove_certificate.rb +146 -0
- data/lib/bsv/wallet/serializer/relinquish_certificate.rb +56 -0
- data/lib/bsv/wallet/serializer/relinquish_output.rb +44 -0
- data/lib/bsv/wallet/serializer/reveal_counterparty_key_linkage.rb +108 -0
- data/lib/bsv/wallet/serializer/reveal_specific_key_linkage.rb +116 -0
- data/lib/bsv/wallet/serializer/sign_action_args.rb +94 -0
- data/lib/bsv/wallet/serializer/sign_action_result.rb +49 -0
- data/lib/bsv/wallet/serializer/status.rb +85 -0
- data/lib/bsv/wallet/serializer/verify_hmac.rb +67 -0
- data/lib/bsv/wallet/serializer/verify_signature.rb +101 -0
- data/lib/bsv/wallet/serializer.rb +180 -0
- data/lib/bsv/wallet/substrates/http_wallet_json.rb +129 -0
- data/lib/bsv/wallet/substrates/http_wallet_wire.rb +99 -0
- data/lib/bsv/wallet/wallet_wire.rb +20 -0
- data/lib/bsv/wallet/wallet_wire_processor.rb +61 -0
- data/lib/bsv/wallet/wallet_wire_transceiver.rb +61 -0
- data/lib/bsv/wallet/wire/calls.rb +79 -0
- data/lib/bsv/wallet/wire/frame.rb +181 -0
- data/lib/bsv/wallet/wire/reader_writer.rb +402 -0
- data/lib/bsv/wallet/wire/validation.rb +213 -0
- data/lib/bsv/wallet/wire.rb +13 -0
- data/lib/bsv/wallet.rb +17 -0
- metadata +47 -3
- data/lib/bsv/transaction/chain_trackers/chaintracks.rb +0 -83
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 serialiser for create_action args (call byte 1).
|
|
7
|
+
#
|
|
8
|
+
# Wire layout (port of go-sdk/wallet/serializer/create_action_args.go):
|
|
9
|
+
# [string] description
|
|
10
|
+
# [optional_bytes] input_beef (NegativeOne = nil)
|
|
11
|
+
# [inputs] NegativeOne | varint_count + input_record…
|
|
12
|
+
# [outputs] NegativeOne | varint_count + output_record…
|
|
13
|
+
# [optional_uint32] lock_time
|
|
14
|
+
# [optional_uint32] version
|
|
15
|
+
# [string_slice] labels
|
|
16
|
+
# [options_block] 0x00 = absent | 0x01 + fields
|
|
17
|
+
#
|
|
18
|
+
# Input record:
|
|
19
|
+
# [32 bytes] outpoint txid (wire order)
|
|
20
|
+
# [varint] outpoint vout
|
|
21
|
+
# [int_bytes or NegativeOne + varint] unlocking_script or length placeholder
|
|
22
|
+
# [string] input_description
|
|
23
|
+
# [optional_uint32] sequence_number
|
|
24
|
+
#
|
|
25
|
+
# Output record:
|
|
26
|
+
# [int_bytes] locking_script
|
|
27
|
+
# [varint] satoshis
|
|
28
|
+
# [string] output_description
|
|
29
|
+
# [optional_string] basket
|
|
30
|
+
# [optional_string] custom_instructions
|
|
31
|
+
# [string_slice] tags
|
|
32
|
+
#
|
|
33
|
+
# Options block (after 0x01 presence byte):
|
|
34
|
+
# [optional_bool] sign_and_process
|
|
35
|
+
# [optional_bool] accept_delayed_broadcast
|
|
36
|
+
# [0x01 or 0xFF] trust_self (1=known, 0xFF=absent)
|
|
37
|
+
# [txid_slice] known_txids
|
|
38
|
+
# [optional_bool] return_txid_only
|
|
39
|
+
# [optional_bool] no_send
|
|
40
|
+
# [optional_bytes] no_send_change (encoded outpoints, NegativeOne = nil)
|
|
41
|
+
# [txid_slice] send_with
|
|
42
|
+
# [optional_bool] randomize_outputs
|
|
43
|
+
module CreateActionArgs
|
|
44
|
+
TRUST_SELF_KNOWN = 1
|
|
45
|
+
|
|
46
|
+
module_function
|
|
47
|
+
|
|
48
|
+
# @param args [Hash]
|
|
49
|
+
# @return [String] binary
|
|
50
|
+
def serialize(args)
|
|
51
|
+
w = Wire::Writer.new
|
|
52
|
+
|
|
53
|
+
w.write_string(args[:description].to_s)
|
|
54
|
+
input_beef = args[:input_beef]
|
|
55
|
+
if input_beef.nil? || input_beef.b.empty?
|
|
56
|
+
w.write_negative_one
|
|
57
|
+
else
|
|
58
|
+
w.write_int_bytes(input_beef)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
serialize_inputs(w, args[:inputs])
|
|
62
|
+
serialize_outputs(w, args[:outputs])
|
|
63
|
+
|
|
64
|
+
w.write_optional_uint32(args[:lock_time])
|
|
65
|
+
w.write_optional_uint32(args[:version])
|
|
66
|
+
w.write_string_slice(args[:labels])
|
|
67
|
+
|
|
68
|
+
serialize_options(w, args[:options])
|
|
69
|
+
|
|
70
|
+
w.buf
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @param bytes [String] binary
|
|
74
|
+
# @return [Hash]
|
|
75
|
+
def deserialize(bytes)
|
|
76
|
+
raise ArgumentError, 'empty message' if bytes.b.empty?
|
|
77
|
+
|
|
78
|
+
r = Wire::Reader.new(bytes)
|
|
79
|
+
|
|
80
|
+
description = r.read_string
|
|
81
|
+
input_beef = r.read_int_bytes
|
|
82
|
+
input_beef = nil if input_beef.empty?
|
|
83
|
+
|
|
84
|
+
inputs = deserialize_inputs(r)
|
|
85
|
+
outputs = deserialize_outputs(r)
|
|
86
|
+
|
|
87
|
+
lock_time = r.read_optional_uint32
|
|
88
|
+
version = r.read_optional_uint32
|
|
89
|
+
labels = r.read_string_slice
|
|
90
|
+
|
|
91
|
+
options = deserialize_options(r)
|
|
92
|
+
|
|
93
|
+
result = { description: description }
|
|
94
|
+
result[:input_beef] = input_beef unless input_beef.nil?
|
|
95
|
+
result[:inputs] = inputs unless inputs.nil?
|
|
96
|
+
result[:outputs] = outputs unless outputs.nil?
|
|
97
|
+
result[:lock_time] = lock_time unless lock_time.nil?
|
|
98
|
+
result[:version] = version unless version.nil?
|
|
99
|
+
result[:labels] = labels unless labels.nil?
|
|
100
|
+
result[:options] = options unless options.nil?
|
|
101
|
+
result
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def serialize_inputs(writer, inputs)
|
|
105
|
+
if inputs.nil?
|
|
106
|
+
writer.write_negative_one
|
|
107
|
+
return
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
writer.write_varint(inputs.length)
|
|
111
|
+
inputs.each do |inp|
|
|
112
|
+
txid_hex, vout = inp[:outpoint].split('.')
|
|
113
|
+
writer.write_bytes([txid_hex].pack('H*'))
|
|
114
|
+
writer.write_varint(vout.to_i)
|
|
115
|
+
|
|
116
|
+
script = inp[:unlocking_script]
|
|
117
|
+
if script && !script.b.empty?
|
|
118
|
+
writer.write_int_bytes(script)
|
|
119
|
+
else
|
|
120
|
+
writer.write_negative_one
|
|
121
|
+
writer.write_varint(inp[:unlocking_script_length].to_i)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
writer.write_string(inp[:input_description].to_s)
|
|
125
|
+
writer.write_optional_uint32(inp[:sequence_number])
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def serialize_outputs(writer, outputs)
|
|
130
|
+
if outputs.nil?
|
|
131
|
+
writer.write_negative_one
|
|
132
|
+
return
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
writer.write_varint(outputs.length)
|
|
136
|
+
outputs.each do |out|
|
|
137
|
+
writer.write_int_bytes(out[:locking_script])
|
|
138
|
+
writer.write_varint(out[:satoshis].to_i)
|
|
139
|
+
writer.write_string(out[:output_description].to_s)
|
|
140
|
+
writer.write_optional_string(out[:basket])
|
|
141
|
+
writer.write_optional_string(out[:custom_instructions])
|
|
142
|
+
writer.write_string_slice(out[:tags])
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def serialize_options(writer, opts)
|
|
147
|
+
if opts.nil?
|
|
148
|
+
writer.write_byte(0)
|
|
149
|
+
return
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
writer.write_byte(1)
|
|
153
|
+
writer.write_optional_bool(opts[:sign_and_process])
|
|
154
|
+
writer.write_optional_bool(opts[:accept_delayed_broadcast])
|
|
155
|
+
|
|
156
|
+
if opts[:trust_self] == :known
|
|
157
|
+
writer.write_byte(TRUST_SELF_KNOWN)
|
|
158
|
+
else
|
|
159
|
+
writer.write_byte(0xFF)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
writer.write_txid_slice(opts[:known_txids])
|
|
163
|
+
writer.write_optional_bool(opts[:return_txid_only])
|
|
164
|
+
writer.write_optional_bool(opts[:no_send])
|
|
165
|
+
|
|
166
|
+
no_send_change_bytes = Common.encode_outpoints(opts[:no_send_change])
|
|
167
|
+
writer.write_int_bytes(no_send_change_bytes)
|
|
168
|
+
|
|
169
|
+
writer.write_txid_slice(opts[:send_with])
|
|
170
|
+
writer.write_optional_bool(opts[:randomize_outputs])
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def deserialize_inputs(reader)
|
|
174
|
+
count = reader.read_varint
|
|
175
|
+
return nil if count == 0xFFFF_FFFF_FFFF_FFFF
|
|
176
|
+
|
|
177
|
+
count.times.map do
|
|
178
|
+
txid_hex = reader.read_bytes(32).unpack1('H*')
|
|
179
|
+
vout = reader.read_varint
|
|
180
|
+
outpoint = "#{txid_hex}.#{vout}"
|
|
181
|
+
|
|
182
|
+
script_len = reader.read_varint
|
|
183
|
+
inp = { outpoint: outpoint }
|
|
184
|
+
|
|
185
|
+
if script_len == 0xFFFF_FFFF_FFFF_FFFF
|
|
186
|
+
length = reader.read_varint
|
|
187
|
+
inp[:unlocking_script_length] = length
|
|
188
|
+
else
|
|
189
|
+
script = reader.read_bytes(script_len)
|
|
190
|
+
inp[:unlocking_script] = script
|
|
191
|
+
inp[:unlocking_script_length] = script_len
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
inp[:input_description] = reader.read_string
|
|
195
|
+
seq = reader.read_optional_uint32
|
|
196
|
+
inp[:sequence_number] = seq unless seq.nil?
|
|
197
|
+
inp
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def deserialize_outputs(reader)
|
|
202
|
+
count = reader.read_varint
|
|
203
|
+
return nil if count == 0xFFFF_FFFF_FFFF_FFFF
|
|
204
|
+
|
|
205
|
+
count.times.map do
|
|
206
|
+
script = reader.read_int_bytes
|
|
207
|
+
satoshis = reader.read_varint
|
|
208
|
+
out_desc = reader.read_string
|
|
209
|
+
basket = reader.read_optional_string
|
|
210
|
+
custom = reader.read_optional_string
|
|
211
|
+
tags = reader.read_string_slice
|
|
212
|
+
|
|
213
|
+
out = { locking_script: script, satoshis: satoshis, output_description: out_desc }
|
|
214
|
+
out[:basket] = basket unless basket.nil?
|
|
215
|
+
out[:custom_instructions] = custom unless custom.nil?
|
|
216
|
+
out[:tags] = tags unless tags.nil?
|
|
217
|
+
out
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def deserialize_options(reader)
|
|
222
|
+
return nil if reader.read_byte != 1
|
|
223
|
+
|
|
224
|
+
opts = {}
|
|
225
|
+
|
|
226
|
+
sign_and_process = reader.read_optional_bool
|
|
227
|
+
accept_delayed_broadcast = reader.read_optional_bool
|
|
228
|
+
|
|
229
|
+
trust_byte = reader.read_byte
|
|
230
|
+
trust_self = trust_byte == TRUST_SELF_KNOWN ? :known : nil
|
|
231
|
+
|
|
232
|
+
known_txids = reader.read_txid_slice
|
|
233
|
+
return_txid_only = reader.read_optional_bool
|
|
234
|
+
no_send = reader.read_optional_bool
|
|
235
|
+
|
|
236
|
+
no_send_change_bytes = reader.read_int_bytes
|
|
237
|
+
no_send_change = Common.decode_outpoints(no_send_change_bytes.empty? ? nil : no_send_change_bytes)
|
|
238
|
+
|
|
239
|
+
send_with = reader.read_txid_slice
|
|
240
|
+
randomize_outputs = reader.read_optional_bool
|
|
241
|
+
|
|
242
|
+
opts[:sign_and_process] = sign_and_process unless sign_and_process.nil?
|
|
243
|
+
opts[:accept_delayed_broadcast] = accept_delayed_broadcast unless accept_delayed_broadcast.nil?
|
|
244
|
+
opts[:trust_self] = trust_self unless trust_self.nil?
|
|
245
|
+
opts[:known_txids] = known_txids unless known_txids.nil?
|
|
246
|
+
opts[:return_txid_only] = return_txid_only unless return_txid_only.nil?
|
|
247
|
+
opts[:no_send] = no_send unless no_send.nil?
|
|
248
|
+
opts[:no_send_change] = no_send_change unless no_send_change.nil?
|
|
249
|
+
opts[:send_with] = send_with unless send_with.nil?
|
|
250
|
+
opts[:randomize_outputs] = randomize_outputs unless randomize_outputs.nil?
|
|
251
|
+
opts
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
private_class_method :serialize_inputs, :serialize_outputs, :serialize_options,
|
|
255
|
+
:deserialize_inputs, :deserialize_outputs, :deserialize_options
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 serialiser for create_action result (call byte 1).
|
|
7
|
+
#
|
|
8
|
+
# Wire layout (port of go-sdk/wallet/serializer/create_action_result.go):
|
|
9
|
+
# [1 byte] 0x00 success sentinel (frame-level, already checked by Frame)
|
|
10
|
+
# [flag + 32 bytes] txid (wire-order) with flag byte: 0=absent, 1=present
|
|
11
|
+
# [flag + int_bytes] tx (BEEF bytes) with flag byte: 0=absent, 1=present + varint_len
|
|
12
|
+
# [optional_bytes] no_send_change encoded outpoints (NegativeOne = nil)
|
|
13
|
+
# [send_with_results] varint count + txid + status_byte each
|
|
14
|
+
# [1 byte flag] signable_transaction: 0=absent, 1=present
|
|
15
|
+
# If signable_transaction present:
|
|
16
|
+
# [int_bytes] tx (BEEF bytes)
|
|
17
|
+
# [int_bytes] reference bytes
|
|
18
|
+
module CreateActionResult
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
# @param result [Hash]
|
|
22
|
+
# @return [String] binary
|
|
23
|
+
def serialize(result)
|
|
24
|
+
w = Wire::Writer.new
|
|
25
|
+
w.write_byte(0) # success sentinel
|
|
26
|
+
|
|
27
|
+
txid_bytes = result[:txid] ? [result[:txid]].pack('H*').reverse : nil
|
|
28
|
+
w.write_optional_bytes_with_flag(txid_bytes, fixed_size: 32)
|
|
29
|
+
w.write_optional_bytes_with_flag(result[:tx])
|
|
30
|
+
|
|
31
|
+
no_send_change_bytes = Common.encode_outpoints(result[:no_send_change])
|
|
32
|
+
w.write_int_bytes(no_send_change_bytes)
|
|
33
|
+
|
|
34
|
+
Common.write_send_with_results(w, result[:send_with_results])
|
|
35
|
+
|
|
36
|
+
signable = result[:signable_transaction]
|
|
37
|
+
if signable
|
|
38
|
+
w.write_byte(1)
|
|
39
|
+
w.write_int_bytes(signable[:tx])
|
|
40
|
+
w.write_int_bytes(signable[:reference])
|
|
41
|
+
else
|
|
42
|
+
w.write_byte(0)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
w.buf
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @param bytes [String] binary
|
|
49
|
+
# @return [Hash]
|
|
50
|
+
def deserialize(bytes)
|
|
51
|
+
raise ArgumentError, 'empty response data' if bytes.b.empty?
|
|
52
|
+
|
|
53
|
+
r = Wire::Reader.new(bytes)
|
|
54
|
+
|
|
55
|
+
status = r.read_byte
|
|
56
|
+
raise ArgumentError, "response indicates failure: #{status}" unless status.zero?
|
|
57
|
+
|
|
58
|
+
txid_raw = r.read_optional_bytes_with_flag(fixed_size: 32)
|
|
59
|
+
txid_hex = txid_raw&.reverse&.unpack1('H*')
|
|
60
|
+
tx = r.read_optional_bytes_with_flag
|
|
61
|
+
|
|
62
|
+
no_send_change_bytes = r.read_int_bytes
|
|
63
|
+
no_send_change = Common.decode_outpoints(no_send_change_bytes.empty? ? nil : no_send_change_bytes)
|
|
64
|
+
|
|
65
|
+
send_with_results = Common.read_send_with_results(r)
|
|
66
|
+
|
|
67
|
+
signable_flag = r.read_byte
|
|
68
|
+
signable_transaction = if signable_flag == 1
|
|
69
|
+
tx_bytes = r.read_int_bytes
|
|
70
|
+
ref_bytes = r.read_int_bytes
|
|
71
|
+
{ tx: tx_bytes, reference: ref_bytes }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
result = {}
|
|
75
|
+
result[:txid] = txid_hex unless txid_hex.nil?
|
|
76
|
+
result[:tx] = tx unless tx.nil?
|
|
77
|
+
result[:no_send_change] = no_send_change unless no_send_change.nil?
|
|
78
|
+
result[:send_with_results] = send_with_results unless send_with_results.nil?
|
|
79
|
+
result[:signable_transaction] = signable_transaction unless signable_transaction.nil?
|
|
80
|
+
result
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +create_hmac+ call (call byte 13).
|
|
7
|
+
#
|
|
8
|
+
# Port of go-sdk/wallet/serializer/create_hmac.go.
|
|
9
|
+
module CreateHmac
|
|
10
|
+
HMAC_SIZE = 32
|
|
11
|
+
|
|
12
|
+
# Args wire layout:
|
|
13
|
+
# [key-related params]
|
|
14
|
+
# [VarInt data_len][data bytes]
|
|
15
|
+
# [optional_bool seek_permission]
|
|
16
|
+
module Args
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
def serialize(args)
|
|
20
|
+
w = BSV::Wallet::Wire::Writer.new
|
|
21
|
+
Common.write_key_related_params(
|
|
22
|
+
w,
|
|
23
|
+
protocol_id: args[:protocol_id],
|
|
24
|
+
key_id: args[:key_id],
|
|
25
|
+
counterparty: args[:counterparty],
|
|
26
|
+
privileged: args[:privileged],
|
|
27
|
+
privileged_reason: args[:privileged_reason]
|
|
28
|
+
)
|
|
29
|
+
data = Common.to_binary(args[:data])
|
|
30
|
+
w.write_varint(data.bytesize)
|
|
31
|
+
w.write_bytes(data)
|
|
32
|
+
w.write_optional_bool(args[:seek_permission])
|
|
33
|
+
w.buf
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def deserialize(bytes)
|
|
37
|
+
r = BSV::Wallet::Wire::Reader.new(bytes)
|
|
38
|
+
params = Common.read_key_related_params(r)
|
|
39
|
+
len = r.read_varint
|
|
40
|
+
data = r.read_bytes(len)
|
|
41
|
+
seek_permission = r.read_optional_bool
|
|
42
|
+
params.merge(data: data, seek_permission: seek_permission)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Result wire layout:
|
|
47
|
+
# [32 bytes: HMAC-SHA-256]
|
|
48
|
+
module Result
|
|
49
|
+
module_function
|
|
50
|
+
|
|
51
|
+
def serialize(result)
|
|
52
|
+
hmac = Common.to_binary(result[:hmac])
|
|
53
|
+
raise ArgumentError, "HMAC must be #{HMAC_SIZE} bytes, got #{hmac.bytesize}" unless hmac.bytesize == HMAC_SIZE
|
|
54
|
+
|
|
55
|
+
hmac
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def deserialize(bytes)
|
|
59
|
+
raise ArgumentError, "HMAC result too short: #{bytes.bytesize}" if bytes.bytesize < HMAC_SIZE
|
|
60
|
+
|
|
61
|
+
{ hmac: bytes.byteslice(0, HMAC_SIZE) }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +create_signature+ call (call byte 15).
|
|
7
|
+
#
|
|
8
|
+
# Port of go-sdk/wallet/serializer/create_signature.go.
|
|
9
|
+
module CreateSignature
|
|
10
|
+
HASH_SIZE = 32
|
|
11
|
+
|
|
12
|
+
# Args wire layout:
|
|
13
|
+
# [key-related params]
|
|
14
|
+
# [1 byte: data-type flag — 1=data, 2=hash_to_directly_sign]
|
|
15
|
+
# If flag=1: [VarInt data_len][data bytes]
|
|
16
|
+
# If flag=2: [32 bytes: hash]
|
|
17
|
+
# [optional_bool seek_permission]
|
|
18
|
+
module Args
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
def serialize(args)
|
|
22
|
+
data = args[:data] && Common.to_binary(args[:data])
|
|
23
|
+
hash = args[:hash_to_directly_sign] && Common.to_binary(args[:hash_to_directly_sign])
|
|
24
|
+
|
|
25
|
+
if data && hash
|
|
26
|
+
raise BSV::Wallet::InvalidParameterError.new(
|
|
27
|
+
'data and hash_to_directly_sign',
|
|
28
|
+
'not both provided — supply one or the other'
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
raise BSV::Wallet::InvalidParameterError.new('data or hash_to_directly_sign', 'present') unless data || hash
|
|
32
|
+
|
|
33
|
+
w = BSV::Wallet::Wire::Writer.new
|
|
34
|
+
Common.write_key_related_params(
|
|
35
|
+
w,
|
|
36
|
+
protocol_id: args[:protocol_id],
|
|
37
|
+
key_id: args[:key_id],
|
|
38
|
+
counterparty: args[:counterparty],
|
|
39
|
+
privileged: args[:privileged],
|
|
40
|
+
privileged_reason: args[:privileged_reason]
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if data
|
|
44
|
+
w.write_byte(1)
|
|
45
|
+
w.write_varint(data.bytesize)
|
|
46
|
+
w.write_bytes(data)
|
|
47
|
+
else
|
|
48
|
+
w.write_byte(2)
|
|
49
|
+
w.write_bytes(hash)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
w.write_optional_bool(args[:seek_permission])
|
|
53
|
+
w.buf
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def deserialize(bytes)
|
|
57
|
+
r = BSV::Wallet::Wire::Reader.new(bytes)
|
|
58
|
+
params = Common.read_key_related_params(r)
|
|
59
|
+
flag = r.read_byte
|
|
60
|
+
payload = case flag
|
|
61
|
+
when 1
|
|
62
|
+
len = r.read_varint
|
|
63
|
+
{ data: r.read_bytes(len) }
|
|
64
|
+
when 2
|
|
65
|
+
{ hash_to_directly_sign: r.read_bytes(HASH_SIZE) }
|
|
66
|
+
else
|
|
67
|
+
raise ArgumentError, "invalid data-type flag: #{flag}"
|
|
68
|
+
end
|
|
69
|
+
seek_permission = r.read_optional_bool
|
|
70
|
+
params.merge(payload).merge(seek_permission: seek_permission)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Result wire layout:
|
|
75
|
+
# [DER signature bytes — remaining payload]
|
|
76
|
+
module Result
|
|
77
|
+
module_function
|
|
78
|
+
|
|
79
|
+
def serialize(result)
|
|
80
|
+
Common.to_binary(result[:signature])
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def deserialize(bytes)
|
|
84
|
+
{ signature: bytes.b }
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +decrypt+ call (call byte 12).
|
|
7
|
+
#
|
|
8
|
+
# Port of go-sdk/wallet/serializer/decrypt.go.
|
|
9
|
+
module Decrypt
|
|
10
|
+
# Args wire layout:
|
|
11
|
+
# [key-related params]
|
|
12
|
+
# [VarInt ciphertext_len][ciphertext bytes]
|
|
13
|
+
# [optional_bool seek_permission]
|
|
14
|
+
module Args
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def serialize(args)
|
|
18
|
+
w = BSV::Wallet::Wire::Writer.new
|
|
19
|
+
Common.write_key_related_params(
|
|
20
|
+
w,
|
|
21
|
+
protocol_id: args[:protocol_id],
|
|
22
|
+
key_id: args[:key_id],
|
|
23
|
+
counterparty: args[:counterparty],
|
|
24
|
+
privileged: args[:privileged],
|
|
25
|
+
privileged_reason: args[:privileged_reason]
|
|
26
|
+
)
|
|
27
|
+
ciphertext = Common.to_binary(args[:ciphertext])
|
|
28
|
+
w.write_varint(ciphertext.bytesize)
|
|
29
|
+
w.write_bytes(ciphertext)
|
|
30
|
+
w.write_optional_bool(args[:seek_permission])
|
|
31
|
+
w.buf
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def deserialize(bytes)
|
|
35
|
+
r = BSV::Wallet::Wire::Reader.new(bytes)
|
|
36
|
+
params = Common.read_key_related_params(r)
|
|
37
|
+
len = r.read_varint
|
|
38
|
+
ciphertext = r.read_bytes(len)
|
|
39
|
+
seek_permission = r.read_optional_bool
|
|
40
|
+
params.merge(ciphertext: ciphertext, seek_permission: seek_permission)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Result wire layout:
|
|
45
|
+
# [plaintext bytes — remaining payload]
|
|
46
|
+
module Result
|
|
47
|
+
module_function
|
|
48
|
+
|
|
49
|
+
def serialize(result)
|
|
50
|
+
Common.to_binary(result[:plaintext])
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def deserialize(bytes)
|
|
54
|
+
{ plaintext: bytes.b }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +discover_by_attributes+ call (call byte 22).
|
|
7
|
+
#
|
|
8
|
+
# Args wire layout:
|
|
9
|
+
# [varint: attribute_count] per entry: [varint-int key_bytes][varint-int value_bytes]
|
|
10
|
+
# [optional_uint32: limit]
|
|
11
|
+
# [optional_uint32: offset]
|
|
12
|
+
# [optional_bool: seek_permission]
|
|
13
|
+
#
|
|
14
|
+
# Result wire layout: see DiscoverCertificatesResult.
|
|
15
|
+
#
|
|
16
|
+
# Keys are written in sorted order (matching Go sort.Strings) to ensure
|
|
17
|
+
# deterministic encoding across SDK implementations.
|
|
18
|
+
module DiscoverByAttributes
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
def serialize_args(args)
|
|
22
|
+
w = Wire::Writer.new
|
|
23
|
+
attributes = args[:attributes] || {}
|
|
24
|
+
w.write_varint(attributes.length)
|
|
25
|
+
attributes.keys.sort.each do |k|
|
|
26
|
+
w.write_int_bytes(k.to_s.b)
|
|
27
|
+
w.write_int_bytes(attributes[k].to_s.b)
|
|
28
|
+
end
|
|
29
|
+
w.write_optional_uint32(args[:limit])
|
|
30
|
+
w.write_optional_uint32(args[:offset])
|
|
31
|
+
w.write_optional_bool(args[:seek_permission])
|
|
32
|
+
w.buf
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def deserialize_args(bytes)
|
|
36
|
+
r = Wire::Reader.new(bytes)
|
|
37
|
+
count = r.read_varint
|
|
38
|
+
attributes = {}
|
|
39
|
+
count.times do
|
|
40
|
+
k = r.read_int_bytes.force_encoding('UTF-8')
|
|
41
|
+
v = r.read_int_bytes.force_encoding('UTF-8')
|
|
42
|
+
attributes[k] = v
|
|
43
|
+
end
|
|
44
|
+
limit = r.read_optional_uint32
|
|
45
|
+
offset = r.read_optional_uint32
|
|
46
|
+
seek_permission = r.read_optional_bool
|
|
47
|
+
{ attributes: attributes, limit: limit, offset: offset,
|
|
48
|
+
seek_permission: seek_permission }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def serialize_result(result)
|
|
52
|
+
DiscoverCertificatesResult.serialize(result)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def deserialize_result(bytes)
|
|
56
|
+
DiscoverCertificatesResult.deserialize(bytes)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +discover_by_identity_key+ call (call byte 21).
|
|
7
|
+
#
|
|
8
|
+
# Args wire layout:
|
|
9
|
+
# [33 bytes: identity_key compressed pubkey]
|
|
10
|
+
# [optional_uint32: limit]
|
|
11
|
+
# [optional_uint32: offset]
|
|
12
|
+
# [optional_bool: seek_permission]
|
|
13
|
+
#
|
|
14
|
+
# Result wire layout: see DiscoverCertificatesResult.
|
|
15
|
+
module DiscoverByIdentityKey
|
|
16
|
+
PUBKEY_SIZE = 33
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
def serialize_args(args)
|
|
21
|
+
w = Wire::Writer.new
|
|
22
|
+
w.write_bytes([args[:identity_key].to_s].pack('H*'))
|
|
23
|
+
w.write_optional_uint32(args[:limit])
|
|
24
|
+
w.write_optional_uint32(args[:offset])
|
|
25
|
+
w.write_optional_bool(args[:seek_permission])
|
|
26
|
+
w.buf
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def deserialize_args(bytes)
|
|
30
|
+
r = Wire::Reader.new(bytes)
|
|
31
|
+
identity_key = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
|
|
32
|
+
limit = r.read_optional_uint32
|
|
33
|
+
offset = r.read_optional_uint32
|
|
34
|
+
seek_permission = r.read_optional_bool
|
|
35
|
+
{ identity_key: identity_key, limit: limit, offset: offset,
|
|
36
|
+
seek_permission: seek_permission }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def serialize_result(result)
|
|
40
|
+
DiscoverCertificatesResult.serialize(result)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def deserialize_result(bytes)
|
|
44
|
+
DiscoverCertificatesResult.deserialize(bytes)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|