Module: BSV::Transaction::VarInt

Defined in:
lib/bsv/transaction/var_int.rb

Overview

Bitcoin variable-length integer encoding/decoding.

VarInts encode unsigned integers compactly: values under 253 use a single byte; larger values use a marker byte followed by 2, 4, or 8 bytes in little-endian order.

Constant Summary collapse

MAX_UINT64 =

Maximum value representable by a Bitcoin VarInt (unsigned 64-bit).

0xFFFF_FFFF_FFFF_FFFF

Class Method Summary collapse

Class Method Details

.decode(data, offset = 0) ⇒ Array(Integer, Integer)

Decode a Bitcoin VarInt from binary data at the given offset.

Parameters:

  • data (String)

    binary data containing the VarInt

  • offset (Integer) (defaults to: 0)

    byte offset to start reading from

Returns:

  • (Array(Integer, Integer))

    the decoded value and number of bytes consumed

Raises:

  • (ArgumentError)


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/bsv/transaction/var_int.rb', line 41

def decode(data, offset = 0)
  raise ArgumentError, "truncated varint: need 1 byte at offset #{offset}, got end of data" if offset >= data.bytesize

  first = data.getbyte(offset)

  case first
  when 0..0xFC
    [first, 1]
  when 0xFD
    raise ArgumentError, "truncated varint: need 3 bytes at offset #{offset}, got #{data.bytesize - offset}" if data.bytesize < offset + 3

    [data.byteslice(offset + 1, 2).unpack1('v'), 3]
  when 0xFE
    raise ArgumentError, "truncated varint: need 5 bytes at offset #{offset}, got #{data.bytesize - offset}" if data.bytesize < offset + 5

    [data.byteslice(offset + 1, 4).unpack1('V'), 5]
  when 0xFF
    raise ArgumentError, "truncated varint: need 9 bytes at offset #{offset}, got #{data.bytesize - offset}" if data.bytesize < offset + 9

    [data.byteslice(offset + 1, 8).unpack1('Q<'), 9]
  end
end

.encode(value) ⇒ String

Encode an integer as a Bitcoin VarInt.

Parameters:

  • value (Integer)

    non-negative integer to encode (0..2^64-1)

Returns:

  • (String)

    encoded binary bytes

Raises:

  • (ArgumentError)

    if value is negative or exceeds 2^64-1



21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/bsv/transaction/var_int.rb', line 21

def encode(value)
  raise ArgumentError, "varint requires non-negative integer, got #{value}" if value.negative?
  raise ArgumentError, "varint value #{value} exceeds uint64 max (#{MAX_UINT64})" if value > MAX_UINT64

  if value < 0xFD
    [value].pack('C')
  elsif value <= 0xFFFF
    [0xFD, value].pack('Cv')
  elsif value <= 0xFFFFFFFF
    [0xFE, value].pack('CV')
  else
    [0xFF, value].pack('CQ<')
  end
end