Class: BSV::Wallet::Wire::Writer

Inherits:
Object
  • Object
show all
Defined in:
lib/bsv/wallet_interface/wire/writer.rb

Overview

Builds a binary byte string using BRC-100 wire protocol encoding conventions.

All multi-byte integers use little-endian order unless stated otherwise. VarInts follow Bitcoin encoding; -1 is encoded as the 9-byte MaxUint64 sentinel.

Constant Summary collapse

MAX_PRIVILEGED_REASON =

Maximum byte length for a PrivilegedReason string (Int8 length field).

127

Instance Method Summary collapse

Constructor Details

#initializeWriter

Returns a new instance of Writer.



14
15
16
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 14

def initialize
  @buf = ''.b
end

Instance Method Details

#to_binaryString

Returns the accumulated binary data.

Returns:

  • (String)

    binary string (encoding: ASCII-8BIT)



21
22
23
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 21

def to_binary
  @buf
end

#write_byte(val) ⇒ Object

Appends a single unsigned byte (0–255).

Parameters:

  • val (Integer)


28
29
30
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 28

def write_byte(val)
  @buf << [val & 0xFF].pack('C')
end

#write_byte_array(data) ⇒ Object

Appends a VarInt-prefixed byte array.

Parameters:

  • data (String)

    binary string



76
77
78
79
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 76

def write_byte_array(data)
  write_varint(data.bytesize)
  write_bytes(data)
end

#write_bytes(data) ⇒ Object

Appends raw bytes with no length prefix.

Parameters:

  • data (String)

    binary string



69
70
71
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 69

def write_bytes(data)
  @buf << data.b
end

#write_counterparty(val) ⇒ Object

Appends a counterparty value using the first-byte dispatch scheme.

Encoding:

'self'   → 0x0B (11)
'anyone' → 0x0C (12)
nil      → 0x00 (0)
hex pubkey (33 bytes compressed) → 33 raw bytes

Parameters:

  • val (String, nil)

    ‘self’, ‘anyone’, nil, or 66-char hex pubkey



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 143

def write_counterparty(val)
  case val
  when 'self'
    write_byte(11)
  when 'anyone'
    write_byte(12)
  when nil
    write_byte(0)
  else
    write_bytes([val].pack('H*'))
  end
end

#write_int8(val) ⇒ Object

Appends a signed 8-bit integer (-128–127). Negative values are encoded as their two’s-complement byte.

Parameters:

  • val (Integer)


36
37
38
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 36

def write_int8(val)
  @buf << [val].pack('c')
end

#write_map(hash_or_nil) ⇒ Object

Appends an optional string→string map: VarInt count + key/value pairs, or -1 if nil.

Parameters:

  • hash_or_nil (Hash, nil)


180
181
182
183
184
185
186
187
188
189
190
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 180

def write_map(hash_or_nil)
  if hash_or_nil.nil?
    write_signed_varint(-1)
  else
    write_varint(hash_or_nil.length)
    hash_or_nil.each do |key, value|
      write_utf8_string(key.to_s)
      write_utf8_string(value.to_s)
    end
  end
end

#write_optional_bool(val_or_nil) ⇒ Object

Appends an optional boolean as a signed Int8: 1=true, 0=false, -1=nil.

Parameters:

  • val_or_nil (Boolean, nil)


115
116
117
118
119
120
121
122
123
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 115

def write_optional_bool(val_or_nil)
  if val_or_nil.nil?
    write_int8(-1)
  elsif val_or_nil
    write_int8(1)
  else
    write_int8(0)
  end
end

#write_optional_byte_array(data_or_nil) ⇒ Object

Appends a VarInt-prefixed byte array, or the -1 sentinel if nil.

Parameters:

  • data_or_nil (String, nil)


84
85
86
87
88
89
90
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 84

def write_optional_byte_array(data_or_nil)
  if data_or_nil.nil?
    write_signed_varint(-1)
  else
    write_byte_array(data_or_nil)
  end
end

#write_optional_utf8_string(str_or_nil) ⇒ Object

Appends a VarInt-prefixed UTF-8 string, or the -1 sentinel if nil.

Parameters:

  • str_or_nil (String, nil)


104
105
106
107
108
109
110
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 104

def write_optional_utf8_string(str_or_nil)
  if str_or_nil.nil?
    write_signed_varint(-1)
  else
    write_utf8_string(str_or_nil)
  end
end

#write_outpoint(txid_hex, index) ⇒ Object

Appends an outpoint: 32 bytes (txid in display order) + VarInt index.

Parameters:

  • txid_hex (String)

    64-character hex txid

  • index (Integer)

    output index



129
130
131
132
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 129

def write_outpoint(txid_hex, index)
  write_bytes([txid_hex].pack('H*'))
  write_varint(index)
end

#write_privileged(privileged, privileged_reason) ⇒ Object

Appends privileged parameters: optional bool + Int8-length reason string.

PrivilegedReason uses Int8 for its length field (max 127 bytes), not VarInt. -1 (0xFF) means absent.

Parameters:

  • privileged (Boolean, nil)
  • privileged_reason (String, nil)


199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 199

def write_privileged(privileged, privileged_reason)
  write_optional_bool(privileged)
  if privileged_reason.nil?
    write_int8(-1)
  else
    reason_bytes = privileged_reason.encode('UTF-8').b
    raise ArgumentError, 'privileged_reason exceeds 127 bytes' if reason_bytes.bytesize > MAX_PRIVILEGED_REASON

    write_int8(reason_bytes.bytesize)
    write_bytes(reason_bytes)
  end
end

#write_protocol_id(protocol_id) ⇒ Object

Appends a protocol ID: UInt8 security level + VarInt-prefixed UTF-8 name.

Parameters:

  • protocol_id (Array)
    Integer level, String name


159
160
161
162
163
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 159

def write_protocol_id(protocol_id)
  level, name = protocol_id
  write_byte(level)
  write_utf8_string(name)
end

#write_signed_varint(val) ⇒ Object

Appends a signed VarInt where -1 is encoded as MaxUint64 (9 bytes: FF * 9).

Parameters:

  • val (Integer)

    non-negative integer, or -1 to signal absence



58
59
60
61
62
63
64
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 58

def write_signed_varint(val)
  if val == -1
    @buf << "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF".b
  else
    write_varint(val)
  end
end

#write_string_array(arr_or_nil) ⇒ Object

Appends an optional string array: VarInt count + strings, or -1 if nil.

Parameters:

  • arr_or_nil (Array<String>, nil)


168
169
170
171
172
173
174
175
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 168

def write_string_array(arr_or_nil)
  if arr_or_nil.nil?
    write_signed_varint(-1)
  else
    write_varint(arr_or_nil.length)
    arr_or_nil.each { |s| write_utf8_string(s) }
  end
end

#write_utf8_string(str) ⇒ Object

Appends a VarInt-prefixed UTF-8 string.

Parameters:

  • str (String)


95
96
97
98
99
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 95

def write_utf8_string(str)
  bytes = str.encode('UTF-8').b
  write_varint(bytes.bytesize)
  write_bytes(bytes)
end

#write_varint(val) ⇒ Object

Appends an unsigned Bitcoin VarInt.

Parameters:

  • val (Integer)

    non-negative integer



43
44
45
46
47
48
49
50
51
52
53
# File 'lib/bsv/wallet_interface/wire/writer.rb', line 43

def write_varint(val)
  @buf << if val < 0xFD
            [val].pack('C')
          elsif val <= 0xFFFF
            [0xFD, val].pack('Cv')
          elsif val <= 0xFFFF_FFFF
            [0xFE, val].pack('CV')
          else
            [0xFF, val].pack('CQ<')
          end
end