bsv-sdk 0.20.0 → 0.23.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 +106 -0
- data/lib/bsv/mcp/tools/broadcast_p2pkh.rb +5 -3
- 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 +27 -4
- data/lib/bsv/network/protocols/jungle_bus.rb +34 -0
- data/lib/bsv/network/protocols/woc_rest.rb +28 -1
- data/lib/bsv/network/protocols.rb +1 -0
- 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/transaction/chain_tracker.rb +66 -13
- data/lib/bsv/transaction/chain_trackers.rb +0 -10
- data/lib/bsv/transaction/fee_models/live_policy.rb +10 -8
- 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 +14 -1
- 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 +46 -2
- data/lib/bsv/transaction/chain_trackers/chaintracks.rb +0 -83
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
5
|
+
module BSV
|
|
6
|
+
module Wallet
|
|
7
|
+
module Serializer
|
|
8
|
+
# BRC-103 wire codec for the +list_certificates+ call (call byte 18).
|
|
9
|
+
#
|
|
10
|
+
# Args wire layout:
|
|
11
|
+
# [varint: certifier_count] per certifier: [33-byte pubkey]
|
|
12
|
+
# [varint: type_count] per type: [32-byte raw type]
|
|
13
|
+
# [optional_uint32: limit]
|
|
14
|
+
# [optional_uint32: offset]
|
|
15
|
+
# [privileged params]
|
|
16
|
+
#
|
|
17
|
+
# Result wire layout:
|
|
18
|
+
# [varint: total_certificates]
|
|
19
|
+
# per certificate:
|
|
20
|
+
# [varint-int: serialised Certificate bytes]
|
|
21
|
+
# [1 byte: keyring present flag (0/1)]
|
|
22
|
+
# If keyring present:
|
|
23
|
+
# [varint: keyring_count] per entry: [varint-str key][varint-int base64 bytes]
|
|
24
|
+
# [varint-int: verifier bytes]
|
|
25
|
+
module ListCertificates
|
|
26
|
+
CERT_TYPE_SIZE = 32
|
|
27
|
+
PUBKEY_SIZE = 33
|
|
28
|
+
|
|
29
|
+
module_function
|
|
30
|
+
|
|
31
|
+
def serialize_args(args)
|
|
32
|
+
w = Wire::Writer.new
|
|
33
|
+
|
|
34
|
+
certifiers = args[:certifiers] || []
|
|
35
|
+
w.write_varint(certifiers.length)
|
|
36
|
+
certifiers.each { |c| w.write_bytes([c.to_s].pack('H*')) }
|
|
37
|
+
|
|
38
|
+
types = args[:types] || []
|
|
39
|
+
w.write_varint(types.length)
|
|
40
|
+
types.each do |t|
|
|
41
|
+
type_bytes = Base64.strict_decode64(t.to_s)
|
|
42
|
+
w.write_bytes(type_bytes.ljust(CERT_TYPE_SIZE, "\x00").byteslice(0, CERT_TYPE_SIZE))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
w.write_optional_uint32(args[:limit])
|
|
46
|
+
w.write_optional_uint32(args[:offset])
|
|
47
|
+
Common.write_privileged_params(w, args[:privileged], args[:privileged_reason])
|
|
48
|
+
w.buf
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def deserialize_args(bytes)
|
|
52
|
+
r = Wire::Reader.new(bytes)
|
|
53
|
+
|
|
54
|
+
certifier_count = r.read_varint
|
|
55
|
+
certifiers = certifier_count.times.map { r.read_bytes(PUBKEY_SIZE).unpack1('H*') }
|
|
56
|
+
|
|
57
|
+
type_count = r.read_varint
|
|
58
|
+
types = type_count.times.map { Base64.strict_encode64(r.read_bytes(CERT_TYPE_SIZE)) }
|
|
59
|
+
|
|
60
|
+
limit = r.read_optional_uint32
|
|
61
|
+
offset = r.read_optional_uint32
|
|
62
|
+
privileged, privileged_reason = Common.read_privileged_params(r)
|
|
63
|
+
|
|
64
|
+
{ certifiers: certifiers, types: types, limit: limit, offset: offset,
|
|
65
|
+
privileged: privileged, privileged_reason: privileged_reason }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def serialize_result(result)
|
|
69
|
+
w = Wire::Writer.new
|
|
70
|
+
certs = result[:certificates] || []
|
|
71
|
+
w.write_varint(certs.length)
|
|
72
|
+
|
|
73
|
+
certs.each do |cert_result|
|
|
74
|
+
cert = cert_result[:certificate] || cert_result
|
|
75
|
+
cert_bytes = Certificate.serialize_certificate(cert, include_signature: true)
|
|
76
|
+
w.write_int_bytes(cert_bytes)
|
|
77
|
+
|
|
78
|
+
keyring = cert_result[:keyring]
|
|
79
|
+
if keyring
|
|
80
|
+
w.write_byte(1)
|
|
81
|
+
w.write_varint(keyring.length)
|
|
82
|
+
keyring.keys.sort.each do |k|
|
|
83
|
+
w.write_str_with_varint_len(k)
|
|
84
|
+
w.write_int_from_base64(keyring[k].to_s)
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
w.write_byte(0)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
verifier = cert_result[:verifier]
|
|
91
|
+
w.write_int_bytes(verifier ? verifier.b : ''.b)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
w.buf
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def deserialize_result(bytes)
|
|
98
|
+
r = Wire::Reader.new(bytes)
|
|
99
|
+
total = r.read_varint
|
|
100
|
+
|
|
101
|
+
certificates = total.times.map do
|
|
102
|
+
cert_bytes = r.read_int_bytes
|
|
103
|
+
cert = Certificate.deserialize_certificate(cert_bytes)
|
|
104
|
+
|
|
105
|
+
keyring = nil
|
|
106
|
+
if r.read_byte == 1
|
|
107
|
+
keyring_len = r.read_varint
|
|
108
|
+
keyring = {}
|
|
109
|
+
keyring_len.times do
|
|
110
|
+
k = r.read_str_with_varint_len
|
|
111
|
+
keyring[k] = r.read_base64_int
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
verifier = r.read_int_bytes
|
|
116
|
+
{ certificate: cert, keyring: keyring, verifier: verifier.empty? ? nil : verifier }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
{ total_certificates: total, certificates: certificates }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +list_outputs+ call (call byte 6).
|
|
7
|
+
#
|
|
8
|
+
# Args wire layout:
|
|
9
|
+
# [varint-str: basket]
|
|
10
|
+
# [string-slice: tags] nil → NegativeOne
|
|
11
|
+
# [1 byte: tag_query_mode] 1=all, 2=any, 0xFF=nil
|
|
12
|
+
# [1 byte: include] 1=locking_scripts, 2=entire_transactions, 0xFF=nil
|
|
13
|
+
# [optional_bool: include_custom_instructions]
|
|
14
|
+
# [optional_bool: include_tags]
|
|
15
|
+
# [optional_bool: include_labels]
|
|
16
|
+
# [optional_uint32: limit]
|
|
17
|
+
# [optional_uint32: offset]
|
|
18
|
+
# [optional_bool: seek_permission]
|
|
19
|
+
#
|
|
20
|
+
# Result wire layout:
|
|
21
|
+
# [varint: total_outputs]
|
|
22
|
+
# [varint: beef_len, or NegativeOne if nil][beef bytes]
|
|
23
|
+
# per output:
|
|
24
|
+
# [32-byte wire txid][varint vout]
|
|
25
|
+
# [varint: satoshis]
|
|
26
|
+
# [varint: locking_script_len, or NegativeOne][script bytes]
|
|
27
|
+
# [varint-str: custom_instructions] 0-length string if nil
|
|
28
|
+
# [string-slice: tags]
|
|
29
|
+
# [string-slice: labels]
|
|
30
|
+
module ListOutputs
|
|
31
|
+
TAG_QUERY_MODE_ALL = 1
|
|
32
|
+
TAG_QUERY_MODE_ANY = 2
|
|
33
|
+
INCLUDE_LOCKING_SCRIPTS = 1
|
|
34
|
+
INCLUDE_ENTIRE_TRANSACTIONS = 2
|
|
35
|
+
NEGATIVE_ONE_BYTE = 0xFF
|
|
36
|
+
|
|
37
|
+
module_function
|
|
38
|
+
|
|
39
|
+
def serialize_args(args)
|
|
40
|
+
w = Wire::Writer.new
|
|
41
|
+
w.write_str_with_varint_len(args.fetch(:basket, ''))
|
|
42
|
+
w.write_string_slice(args[:tags])
|
|
43
|
+
|
|
44
|
+
mode_byte = case args[:tag_query_mode]
|
|
45
|
+
when :all then TAG_QUERY_MODE_ALL
|
|
46
|
+
when :any then TAG_QUERY_MODE_ANY
|
|
47
|
+
else NEGATIVE_ONE_BYTE
|
|
48
|
+
end
|
|
49
|
+
w.write_byte(mode_byte)
|
|
50
|
+
|
|
51
|
+
include_byte = case args[:include]
|
|
52
|
+
when :locking_scripts then INCLUDE_LOCKING_SCRIPTS
|
|
53
|
+
when :entire_transactions then INCLUDE_ENTIRE_TRANSACTIONS
|
|
54
|
+
else NEGATIVE_ONE_BYTE
|
|
55
|
+
end
|
|
56
|
+
w.write_byte(include_byte)
|
|
57
|
+
|
|
58
|
+
w.write_optional_bool(args[:include_custom_instructions])
|
|
59
|
+
w.write_optional_bool(args[:include_tags])
|
|
60
|
+
w.write_optional_bool(args[:include_labels])
|
|
61
|
+
w.write_optional_uint32(args[:limit])
|
|
62
|
+
w.write_optional_uint32(args[:offset])
|
|
63
|
+
w.write_optional_bool(args[:seek_permission])
|
|
64
|
+
w.buf
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def deserialize_args(bytes)
|
|
68
|
+
r = Wire::Reader.new(bytes)
|
|
69
|
+
basket = r.read_str_with_varint_len
|
|
70
|
+
tags = r.read_string_slice
|
|
71
|
+
|
|
72
|
+
mode = case r.read_byte
|
|
73
|
+
when TAG_QUERY_MODE_ALL then :all
|
|
74
|
+
when TAG_QUERY_MODE_ANY then :any
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
inc = case r.read_byte
|
|
78
|
+
when INCLUDE_LOCKING_SCRIPTS then :locking_scripts
|
|
79
|
+
when INCLUDE_ENTIRE_TRANSACTIONS then :entire_transactions
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
{
|
|
83
|
+
basket: basket,
|
|
84
|
+
tags: tags,
|
|
85
|
+
tag_query_mode: mode,
|
|
86
|
+
include: inc,
|
|
87
|
+
include_custom_instructions: r.read_optional_bool,
|
|
88
|
+
include_tags: r.read_optional_bool,
|
|
89
|
+
include_labels: r.read_optional_bool,
|
|
90
|
+
limit: r.read_optional_uint32,
|
|
91
|
+
offset: r.read_optional_uint32,
|
|
92
|
+
seek_permission: r.read_optional_bool
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def serialize_result(result)
|
|
97
|
+
w = Wire::Writer.new
|
|
98
|
+
outputs = result[:outputs] || []
|
|
99
|
+
w.write_varint(outputs.length)
|
|
100
|
+
|
|
101
|
+
beef = result[:beef]
|
|
102
|
+
if beef
|
|
103
|
+
w.write_int_bytes(beef.b)
|
|
104
|
+
else
|
|
105
|
+
w.write_negative_one
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
outputs.each do |output|
|
|
109
|
+
outpoint = output[:outpoint] || ''
|
|
110
|
+
txid_hex, vout = outpoint.to_s.split('.', 2)
|
|
111
|
+
w.write_outpoint(txid_hex.to_s, vout.to_i)
|
|
112
|
+
w.write_varint(output[:satoshis].to_i)
|
|
113
|
+
locking_script = output[:locking_script]
|
|
114
|
+
if locking_script && !locking_script.empty?
|
|
115
|
+
w.write_int_bytes(locking_script.b)
|
|
116
|
+
else
|
|
117
|
+
w.write_negative_one
|
|
118
|
+
end
|
|
119
|
+
w.write_optional_string(output[:custom_instructions])
|
|
120
|
+
w.write_string_slice(output[:tags])
|
|
121
|
+
w.write_string_slice(output[:labels])
|
|
122
|
+
end
|
|
123
|
+
w.buf
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def deserialize_result(bytes)
|
|
127
|
+
r = Wire::Reader.new(bytes)
|
|
128
|
+
total_outputs = r.read_varint
|
|
129
|
+
|
|
130
|
+
beef_len = r.read_varint
|
|
131
|
+
beef = if beef_len == 0xFFFF_FFFF_FFFF_FFFF
|
|
132
|
+
nil
|
|
133
|
+
else
|
|
134
|
+
r.read_bytes(beef_len)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
outputs = total_outputs.times.map do
|
|
138
|
+
outpoint_data = r.read_outpoint
|
|
139
|
+
outpoint = "#{outpoint_data[:txid_hex]}.#{outpoint_data[:vout]}"
|
|
140
|
+
satoshis = r.read_varint
|
|
141
|
+
locking_script_len = r.read_varint
|
|
142
|
+
locking_script = if locking_script_len == 0xFFFF_FFFF_FFFF_FFFF
|
|
143
|
+
nil
|
|
144
|
+
else
|
|
145
|
+
r.read_bytes(locking_script_len)
|
|
146
|
+
end
|
|
147
|
+
custom_instructions = r.read_optional_string
|
|
148
|
+
tags = r.read_string_slice
|
|
149
|
+
labels = r.read_string_slice
|
|
150
|
+
|
|
151
|
+
{
|
|
152
|
+
outpoint: outpoint,
|
|
153
|
+
satoshis: satoshis,
|
|
154
|
+
locking_script: locking_script,
|
|
155
|
+
custom_instructions: custom_instructions,
|
|
156
|
+
tags: tags,
|
|
157
|
+
labels: labels,
|
|
158
|
+
spendable: true
|
|
159
|
+
}
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
{ total_outputs: total_outputs, beef: beef, outputs: outputs }
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
5
|
+
module BSV
|
|
6
|
+
module Wallet
|
|
7
|
+
module Serializer
|
|
8
|
+
# BRC-103 wire codec for the +prove_certificate+ call (call byte 19).
|
|
9
|
+
#
|
|
10
|
+
# Args wire layout (matches go-sdk SerializeProveCertificateArgs):
|
|
11
|
+
# [32 bytes: cert.type]
|
|
12
|
+
# [33 bytes: cert.subject pubkey]
|
|
13
|
+
# [32 bytes: cert.serial_number]
|
|
14
|
+
# [33 bytes: cert.certifier pubkey]
|
|
15
|
+
# [36 bytes: cert.revocation_outpoint]
|
|
16
|
+
# [varint-int: cert.signature bytes] (0-length if nil)
|
|
17
|
+
# [varint: field_count] per field: [varint-int name_bytes][varint-int value_bytes]
|
|
18
|
+
# [varint: fields_to_reveal_count] per field: [varint-int name_bytes]
|
|
19
|
+
# [33 bytes: verifier pubkey]
|
|
20
|
+
# [privileged params]
|
|
21
|
+
#
|
|
22
|
+
# Result wire layout:
|
|
23
|
+
# [varint: keyring_count] per entry: [varint-int key_bytes][varint-int base64 bytes]
|
|
24
|
+
module ProveCertificate
|
|
25
|
+
CERT_TYPE_SIZE = 32
|
|
26
|
+
SERIAL_SIZE = 32
|
|
27
|
+
PUBKEY_SIZE = 33
|
|
28
|
+
|
|
29
|
+
module_function
|
|
30
|
+
|
|
31
|
+
def serialize_args(args)
|
|
32
|
+
w = Wire::Writer.new
|
|
33
|
+
cert = args[:certificate] || {}
|
|
34
|
+
|
|
35
|
+
type_bytes = Base64.strict_decode64(cert[:type].to_s)
|
|
36
|
+
w.write_bytes(type_bytes.ljust(CERT_TYPE_SIZE, "\x00").byteslice(0, CERT_TYPE_SIZE))
|
|
37
|
+
w.write_bytes([cert[:subject].to_s].pack('H*'))
|
|
38
|
+
|
|
39
|
+
serial_bytes = Base64.strict_decode64(cert[:serial_number].to_s)
|
|
40
|
+
w.write_bytes(serial_bytes.ljust(SERIAL_SIZE, "\x00").byteslice(0, SERIAL_SIZE))
|
|
41
|
+
w.write_bytes([cert[:certifier].to_s].pack('H*'))
|
|
42
|
+
|
|
43
|
+
outpoint_str = cert[:revocation_outpoint].to_s
|
|
44
|
+
if outpoint_str.empty? || outpoint_str == '.'
|
|
45
|
+
w.write_outpoint(Certificate::NULL_TXID_HEX, 0)
|
|
46
|
+
else
|
|
47
|
+
txid_hex, vout = outpoint_str.split('.', 2)
|
|
48
|
+
w.write_outpoint(txid_hex.to_s, vout.to_i)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
sig = cert[:signature]
|
|
52
|
+
if sig && !sig.to_s.empty?
|
|
53
|
+
w.write_int_bytes([sig.to_s].pack('H*'))
|
|
54
|
+
else
|
|
55
|
+
w.write_int_bytes(''.b)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
fields = cert[:fields] || {}
|
|
59
|
+
w.write_varint(fields.length)
|
|
60
|
+
fields.keys.sort.each do |k|
|
|
61
|
+
w.write_int_bytes(k.b)
|
|
62
|
+
w.write_int_bytes(fields[k].to_s.b)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
fields_to_reveal = args[:fields_to_reveal] || []
|
|
66
|
+
w.write_varint(fields_to_reveal.length)
|
|
67
|
+
fields_to_reveal.each { |f| w.write_int_bytes(f.to_s.b) }
|
|
68
|
+
|
|
69
|
+
w.write_bytes([args[:verifier].to_s].pack('H*'))
|
|
70
|
+
|
|
71
|
+
Common.write_privileged_params(w, args[:privileged], args[:privileged_reason])
|
|
72
|
+
w.buf
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def deserialize_args(bytes)
|
|
76
|
+
r = Wire::Reader.new(bytes)
|
|
77
|
+
|
|
78
|
+
type_raw = r.read_bytes(CERT_TYPE_SIZE)
|
|
79
|
+
subject = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
|
|
80
|
+
serial_raw = r.read_bytes(SERIAL_SIZE)
|
|
81
|
+
certifier = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
|
|
82
|
+
|
|
83
|
+
outpoint_data = r.read_outpoint
|
|
84
|
+
revocation_outpoint = "#{outpoint_data[:txid_hex]}.#{outpoint_data[:vout]}"
|
|
85
|
+
|
|
86
|
+
sig_bytes = r.read_int_bytes
|
|
87
|
+
signature = sig_bytes.empty? ? nil : sig_bytes.unpack1('H*')
|
|
88
|
+
|
|
89
|
+
field_count = r.read_varint
|
|
90
|
+
fields = {}
|
|
91
|
+
field_count.times do
|
|
92
|
+
k = r.read_int_bytes.force_encoding('UTF-8')
|
|
93
|
+
v = r.read_int_bytes.force_encoding('UTF-8')
|
|
94
|
+
fields[k] = v
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
fields_to_reveal_count = r.read_varint
|
|
98
|
+
fields_to_reveal = fields_to_reveal_count.times.map do
|
|
99
|
+
r.read_int_bytes.force_encoding('UTF-8')
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
verifier = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
|
|
103
|
+
privileged, privileged_reason = Common.read_privileged_params(r)
|
|
104
|
+
|
|
105
|
+
{
|
|
106
|
+
certificate: {
|
|
107
|
+
type: Base64.strict_encode64(type_raw),
|
|
108
|
+
subject: subject,
|
|
109
|
+
serial_number: Base64.strict_encode64(serial_raw),
|
|
110
|
+
certifier: certifier,
|
|
111
|
+
revocation_outpoint: revocation_outpoint,
|
|
112
|
+
signature: signature,
|
|
113
|
+
fields: fields
|
|
114
|
+
},
|
|
115
|
+
fields_to_reveal: fields_to_reveal,
|
|
116
|
+
verifier: verifier,
|
|
117
|
+
privileged: privileged,
|
|
118
|
+
privileged_reason: privileged_reason
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def serialize_result(result)
|
|
123
|
+
w = Wire::Writer.new
|
|
124
|
+
keyring = result[:keyring_for_verifier] || {}
|
|
125
|
+
w.write_varint(keyring.length)
|
|
126
|
+
keyring.keys.sort.each do |k|
|
|
127
|
+
w.write_int_bytes(k.to_s.b)
|
|
128
|
+
w.write_int_from_base64(keyring[k].to_s)
|
|
129
|
+
end
|
|
130
|
+
w.buf
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def deserialize_result(bytes)
|
|
134
|
+
r = Wire::Reader.new(bytes)
|
|
135
|
+
count = r.read_varint
|
|
136
|
+
keyring = {}
|
|
137
|
+
count.times do
|
|
138
|
+
k = r.read_int_bytes.force_encoding('UTF-8')
|
|
139
|
+
keyring[k] = r.read_base64_int
|
|
140
|
+
end
|
|
141
|
+
{ keyring_for_verifier: keyring }
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
5
|
+
module BSV
|
|
6
|
+
module Wallet
|
|
7
|
+
module Serializer
|
|
8
|
+
# BRC-103 wire codec for the +relinquish_certificate+ call (call byte 20).
|
|
9
|
+
#
|
|
10
|
+
# Args wire layout:
|
|
11
|
+
# [32 bytes: type]
|
|
12
|
+
# [32 bytes: serial_number]
|
|
13
|
+
# [33 bytes: certifier pubkey]
|
|
14
|
+
#
|
|
15
|
+
# Result wire layout:
|
|
16
|
+
# [empty — relinquished is implicit from the frame error byte]
|
|
17
|
+
module RelinquishCertificate
|
|
18
|
+
CERT_TYPE_SIZE = 32
|
|
19
|
+
SERIAL_SIZE = 32
|
|
20
|
+
PUBKEY_SIZE = 33
|
|
21
|
+
|
|
22
|
+
module_function
|
|
23
|
+
|
|
24
|
+
def serialize_args(args)
|
|
25
|
+
w = Wire::Writer.new
|
|
26
|
+
type_bytes = Base64.strict_decode64(args[:type].to_s)
|
|
27
|
+
w.write_bytes(type_bytes.ljust(CERT_TYPE_SIZE, "\x00").byteslice(0, CERT_TYPE_SIZE))
|
|
28
|
+
serial_bytes = Base64.strict_decode64(args[:serial_number].to_s)
|
|
29
|
+
w.write_bytes(serial_bytes.ljust(SERIAL_SIZE, "\x00").byteslice(0, SERIAL_SIZE))
|
|
30
|
+
w.write_bytes([args[:certifier].to_s].pack('H*'))
|
|
31
|
+
w.buf
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def deserialize_args(bytes)
|
|
35
|
+
r = Wire::Reader.new(bytes)
|
|
36
|
+
type_raw = r.read_bytes(CERT_TYPE_SIZE)
|
|
37
|
+
serial_raw = r.read_bytes(SERIAL_SIZE)
|
|
38
|
+
certifier = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
|
|
39
|
+
{
|
|
40
|
+
type: Base64.strict_encode64(type_raw),
|
|
41
|
+
serial_number: Base64.strict_encode64(serial_raw),
|
|
42
|
+
certifier: certifier
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def serialize_result(_result)
|
|
47
|
+
''.b
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def deserialize_result(_bytes)
|
|
51
|
+
{ relinquished: true }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +relinquish_output+ call (call byte 7).
|
|
7
|
+
#
|
|
8
|
+
# Args wire layout:
|
|
9
|
+
# [varint-str: basket]
|
|
10
|
+
# [32-byte wire txid][varint vout]
|
|
11
|
+
#
|
|
12
|
+
# Result wire layout:
|
|
13
|
+
# [empty — relinquished is implicit from the frame error byte]
|
|
14
|
+
module RelinquishOutput
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def serialize_args(args)
|
|
18
|
+
Wire::Validation.outpoint_string!('output', args[:output].to_s)
|
|
19
|
+
txid_hex, vout = args[:output].to_s.split('.', 2)
|
|
20
|
+
w = Wire::Writer.new
|
|
21
|
+
w.write_str_with_varint_len(args.fetch(:basket, ''))
|
|
22
|
+
w.write_outpoint(txid_hex, vout.to_i)
|
|
23
|
+
w.buf
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def deserialize_args(bytes)
|
|
27
|
+
r = Wire::Reader.new(bytes)
|
|
28
|
+
basket = r.read_str_with_varint_len
|
|
29
|
+
outpoint_data = r.read_outpoint
|
|
30
|
+
output = "#{outpoint_data[:txid_hex]}.#{outpoint_data[:vout]}"
|
|
31
|
+
{ basket: basket, output: output }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def serialize_result(_result)
|
|
35
|
+
''.b
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def deserialize_result(_bytes)
|
|
39
|
+
{ relinquished: true }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +reveal_counterparty_key_linkage+ call (call byte 9).
|
|
7
|
+
#
|
|
8
|
+
# Port of go-sdk/wallet/serializer/reveal_counterparty_key_linkage.go.
|
|
9
|
+
module RevealCounterpartyKeyLinkage
|
|
10
|
+
PUBKEY_SIZE = 33
|
|
11
|
+
|
|
12
|
+
# Args wire layout:
|
|
13
|
+
# [privileged params]
|
|
14
|
+
# [33 bytes: counterparty compressed pubkey]
|
|
15
|
+
# [33 bytes: verifier compressed pubkey]
|
|
16
|
+
module Args
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
def serialize(args)
|
|
20
|
+
counterparty = args[:counterparty]
|
|
21
|
+
verifier = args[:verifier]
|
|
22
|
+
raise BSV::Wallet::InvalidParameterError.new('counterparty', 'a 33-byte binary pubkey or 66-char hex') unless counterparty
|
|
23
|
+
raise BSV::Wallet::InvalidParameterError.new('verifier', 'a 33-byte binary pubkey or 66-char hex') unless verifier
|
|
24
|
+
|
|
25
|
+
w = BSV::Wallet::Wire::Writer.new
|
|
26
|
+
Common.write_privileged_params(w, args[:privileged], args[:privileged_reason])
|
|
27
|
+
w.write_bytes(pubkey_bytes(counterparty))
|
|
28
|
+
w.write_bytes(pubkey_bytes(verifier))
|
|
29
|
+
w.buf
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def deserialize(bytes)
|
|
33
|
+
r = BSV::Wallet::Wire::Reader.new(bytes)
|
|
34
|
+
privileged, reason = Common.read_privileged_params(r)
|
|
35
|
+
counterparty = r.read_bytes(PUBKEY_SIZE)
|
|
36
|
+
verifier = r.read_bytes(PUBKEY_SIZE)
|
|
37
|
+
{
|
|
38
|
+
privileged: privileged,
|
|
39
|
+
privileged_reason: reason,
|
|
40
|
+
counterparty: counterparty,
|
|
41
|
+
verifier: verifier
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def pubkey_bytes(value)
|
|
46
|
+
return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
|
|
47
|
+
|
|
48
|
+
[value.to_s].pack('H*')
|
|
49
|
+
end
|
|
50
|
+
private_class_method :pubkey_bytes
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Result wire layout:
|
|
54
|
+
# [33 bytes: prover pubkey]
|
|
55
|
+
# [33 bytes: verifier pubkey]
|
|
56
|
+
# [33 bytes: counterparty pubkey]
|
|
57
|
+
# [VarInt revelation_time_len][revelation_time bytes]
|
|
58
|
+
# [VarInt encrypted_linkage_len][encrypted_linkage bytes]
|
|
59
|
+
# [VarInt encrypted_linkage_proof_len][encrypted_linkage_proof bytes]
|
|
60
|
+
module Result
|
|
61
|
+
module_function
|
|
62
|
+
|
|
63
|
+
def serialize(result)
|
|
64
|
+
w = BSV::Wallet::Wire::Writer.new
|
|
65
|
+
w.write_bytes(pubkey_bytes(result[:prover]))
|
|
66
|
+
w.write_bytes(pubkey_bytes(result[:verifier]))
|
|
67
|
+
w.write_bytes(pubkey_bytes(result[:counterparty]))
|
|
68
|
+
w.write_str_with_varint_len(result[:revelation_time].to_s)
|
|
69
|
+
encrypted_linkage = Common.to_binary(result[:encrypted_linkage])
|
|
70
|
+
w.write_varint(encrypted_linkage.bytesize)
|
|
71
|
+
w.write_bytes(encrypted_linkage)
|
|
72
|
+
encrypted_linkage_proof = Common.to_binary(result[:encrypted_linkage_proof])
|
|
73
|
+
w.write_varint(encrypted_linkage_proof.bytesize)
|
|
74
|
+
w.write_bytes(encrypted_linkage_proof)
|
|
75
|
+
w.buf
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def deserialize(bytes)
|
|
79
|
+
r = BSV::Wallet::Wire::Reader.new(bytes)
|
|
80
|
+
prover = r.read_bytes(PUBKEY_SIZE)
|
|
81
|
+
verifier = r.read_bytes(PUBKEY_SIZE)
|
|
82
|
+
counterparty = r.read_bytes(PUBKEY_SIZE)
|
|
83
|
+
revelation_time = r.read_str_with_varint_len
|
|
84
|
+
el_len = r.read_varint
|
|
85
|
+
encrypted_linkage = r.read_bytes(el_len)
|
|
86
|
+
elp_len = r.read_varint
|
|
87
|
+
encrypted_linkage_proof = r.read_bytes(elp_len)
|
|
88
|
+
{
|
|
89
|
+
prover: prover,
|
|
90
|
+
verifier: verifier,
|
|
91
|
+
counterparty: counterparty,
|
|
92
|
+
revelation_time: revelation_time,
|
|
93
|
+
encrypted_linkage: encrypted_linkage,
|
|
94
|
+
encrypted_linkage_proof: encrypted_linkage_proof
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def pubkey_bytes(value)
|
|
99
|
+
return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
|
|
100
|
+
|
|
101
|
+
[value.to_s].pack('H*')
|
|
102
|
+
end
|
|
103
|
+
private_class_method :pubkey_bytes
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|