Class: BSV::Wallet::Wire::Reader
- Inherits:
-
Object
- Object
- BSV::Wallet::Wire::Reader
- Defined in:
- lib/bsv/wallet_interface/wire/reader.rb
Overview
Consumes a binary byte string using BRC-100 wire protocol decoding conventions.
All multi-byte integers use little-endian order unless stated otherwise. VarInts follow Bitcoin encoding; the 9-byte MaxUint64 sentinel decodes as -1.
Constant Summary collapse
- MAX_UINT64 =
The 64-bit sentinel value that encodes -1 in a signed VarInt.
0xFFFF_FFFF_FFFF_FFFF
Instance Attribute Summary collapse
-
#offset ⇒ Object
readonly
Current read position (bytes consumed so far).
Instance Method Summary collapse
-
#initialize(data) ⇒ Reader
constructor
A new instance of Reader.
-
#read_byte ⇒ Integer
Reads a single unsigned byte (0–255).
-
#read_byte_array ⇒ String
Reads a VarInt-prefixed byte array.
-
#read_bytes(n) ⇒ String
Reads exactly n raw bytes.
-
#read_counterparty ⇒ String?
Reads a counterparty value using the first-byte dispatch scheme.
-
#read_int8 ⇒ Integer
Reads a signed 8-bit integer (-128–127).
-
#read_map ⇒ Hash?
Reads an optional string→string map: VarInt count + key/value pairs, or nil.
-
#read_optional_bool ⇒ Boolean?
Reads a signed Int8 optional boolean: 1=true, 0=false, -1=nil.
-
#read_optional_byte_array ⇒ String?
Reads an optional VarInt-prefixed byte array; returns nil for the -1 sentinel.
-
#read_optional_utf8_string ⇒ String?
Reads an optional VarInt-prefixed UTF-8 string; returns nil for the -1 sentinel.
-
#read_outpoint ⇒ Array(String, Integer)
Reads an outpoint: 32 bytes (txid hex in display order) + VarInt index.
-
#read_privileged ⇒ Array(Boolean|nil, String|nil)
Reads privileged parameters: optional bool + Int8-length reason string.
-
#read_protocol_id ⇒ Array(Integer, String)
Reads a protocol ID: UInt8 security level + VarInt-prefixed UTF-8 name.
-
#read_remaining ⇒ String
Reads all remaining bytes from the current offset.
-
#read_signed_varint ⇒ Integer
Reads a signed VarInt, returning -1 for the MaxUint64 sentinel.
-
#read_string_array ⇒ Array<String>?
Reads an optional string array: VarInt count + strings, or nil for the -1 sentinel.
-
#read_utf8_string ⇒ String
Reads a VarInt-prefixed UTF-8 string.
-
#read_varint ⇒ Integer
Reads an unsigned Bitcoin VarInt.
Constructor Details
#initialize(data) ⇒ Reader
Returns a new instance of Reader.
14 15 16 17 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 14 def initialize(data) @data = data.b @offset = 0 end |
Instance Attribute Details
#offset ⇒ Object (readonly)
Current read position (bytes consumed so far).
20 21 22 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 20 def offset @offset end |
Instance Method Details
#read_byte ⇒ Integer
Reads a single unsigned byte (0–255).
25 26 27 28 29 30 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 25 def read_byte require_bytes(1) byte = @data.getbyte(@offset) @offset += 1 byte end |
#read_byte_array ⇒ String
Reads a VarInt-prefixed byte array.
102 103 104 105 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 102 def read_byte_array len = read_varint read_bytes(len) end |
#read_bytes(n) ⇒ String
Reads exactly n raw bytes.
83 84 85 86 87 88 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 83 def read_bytes(n) require_bytes(n) slice = @data.byteslice(@offset, n) @offset += n slice end |
#read_counterparty ⇒ String?
Reads a counterparty value using the first-byte dispatch scheme.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 158 def read_counterparty flag = read_byte case flag when 11 'self' when 12 'anyone' when 0 nil else # First byte is part of the 33-byte compressed pubkey; read 32 more remaining = read_bytes(32) ([flag].pack('C') + remaining).unpack1('H*') end end |
#read_int8 ⇒ Integer
Reads a signed 8-bit integer (-128–127).
35 36 37 38 39 40 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 35 def read_int8 require_bytes(1) val = @data.byteslice(@offset, 1).unpack1('c') @offset += 1 val end |
#read_map ⇒ Hash?
Reads an optional string→string map: VarInt count + key/value pairs, or nil.
196 197 198 199 200 201 202 203 204 205 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 196 def read_map count = read_signed_varint return nil if count == -1 count.times.each_with_object({}) do |_, hash| key = read_utf8_string val = read_utf8_string hash[key] = val end end |
#read_optional_bool ⇒ Boolean?
Reads a signed Int8 optional boolean: 1=true, 0=false, -1=nil.
138 139 140 141 142 143 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 138 def read_optional_bool val = read_int8 return nil if val == -1 val == 1 end |
#read_optional_byte_array ⇒ String?
Reads an optional VarInt-prefixed byte array; returns nil for the -1 sentinel.
110 111 112 113 114 115 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 110 def read_optional_byte_array len = read_signed_varint return nil if len == -1 read_bytes(len) end |
#read_optional_utf8_string ⇒ String?
Reads an optional VarInt-prefixed UTF-8 string; returns nil for the -1 sentinel.
128 129 130 131 132 133 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 128 def read_optional_utf8_string len = read_signed_varint return nil if len == -1 read_bytes(len).force_encoding('UTF-8') end |
#read_outpoint ⇒ Array(String, Integer)
Reads an outpoint: 32 bytes (txid hex in display order) + VarInt index.
148 149 150 151 152 153 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 148 def read_outpoint txid_bytes = read_bytes(32) txid_hex = txid_bytes.unpack1('H*') index = read_varint [txid_hex, index] end |
#read_privileged ⇒ Array(Boolean|nil, String|nil)
Reads privileged parameters: optional bool + Int8-length reason string.
210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 210 def read_privileged privileged = read_optional_bool reason_len = read_int8 privileged_reason = if reason_len == -1 nil elsif reason_len.negative? raise ArgumentError, "invalid privileged_reason length: #{reason_len}" else read_bytes(reason_len).force_encoding('UTF-8') end [privileged, privileged_reason] end |
#read_protocol_id ⇒ Array(Integer, String)
Reads a protocol ID: UInt8 security level + VarInt-prefixed UTF-8 name.
177 178 179 180 181 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 177 def read_protocol_id level = read_byte name = read_utf8_string [level, name] end |
#read_remaining ⇒ String
Reads all remaining bytes from the current offset.
93 94 95 96 97 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 93 def read_remaining slice = @data.byteslice(@offset, @data.bytesize - @offset) || ''.b @offset = @data.bytesize slice end |
#read_signed_varint ⇒ Integer
Reads a signed VarInt, returning -1 for the MaxUint64 sentinel.
74 75 76 77 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 74 def read_signed_varint val = read_varint val == MAX_UINT64 ? -1 : val end |
#read_string_array ⇒ Array<String>?
Reads an optional string array: VarInt count + strings, or nil for the -1 sentinel.
186 187 188 189 190 191 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 186 def read_string_array count = read_signed_varint return nil if count == -1 count.times.map { read_utf8_string } end |
#read_utf8_string ⇒ String
Reads a VarInt-prefixed UTF-8 string.
120 121 122 123 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 120 def read_utf8_string len = read_varint read_bytes(len).force_encoding('UTF-8') end |
#read_varint ⇒ Integer
Reads an unsigned Bitcoin VarInt.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/bsv/wallet_interface/wire/reader.rb', line 45 def read_varint require_bytes(1) first = @data.getbyte(@offset) case first when 0..0xFC @offset += 1 first when 0xFD require_bytes(3) val = @data.byteslice(@offset + 1, 2).unpack1('v') @offset += 3 val when 0xFE require_bytes(5) val = @data.byteslice(@offset + 1, 4).unpack1('V') @offset += 5 val else # 0xFF require_bytes(9) val = @data.byteslice(@offset + 1, 8).unpack1('Q<') @offset += 9 val end end |