module Ciri::RLP::Encode

Public Instance Methods

encode(input, type = nil) click to toggle source

Encode input to rlp encoding

Examples:

Ciri::RLP.encode("hello world")
# File lib/ciri/rlp/encode.rb, line 41
def encode(input, type = nil)
  type ? encode_with_type(input, type) : encode_simple(input)
end
encode_simple(input) click to toggle source
# File lib/ciri/rlp/encode.rb, line 45
def encode_simple(input)
  if input.is_a?(Array)
    encode_list(input) {|i| encode_simple(i)}
  elsif input.is_a?(Integer)
    encode_with_type(input, Integer)
  elsif input.class.respond_to?(:rlp_encode)
    input.class.rlp_encode(input)
  else
    encode_with_type(input, Raw)
  end
end
encode_with_type(item, type, zero: '') click to toggle source

Use this method before RLP.encode, this method encode ruby objects to rlp friendly format, string or array. see Ciri::RLP::Serializable::TYPES for supported types

Examples:

item = Ciri::RLP.encode_with_type(number, :int, zero: "\x00".b)
encoded_text = Ciri::RLP.encode(item)
# File lib/ciri/rlp/encode.rb, line 65
def encode_with_type(item, type, zero: '')
  if type == Integer
    if item == 0
      "\x80".b
    elsif item < 0x80
      Ciri::Utils.big_endian_encode(item, zero)
    else
      buf = Ciri::Utils.big_endian_encode(item, zero)
      [0x80 + buf.size].pack("c*") + buf
    end
  elsif type == Bool
    item ? Bool::ENCODED_TRUE : Bool::ENCODED_FALSE
  elsif type.is_a?(Class) && type.respond_to?(:rlp_encode)
    type.rlp_encode(item)
  elsif type.is_a?(Array)
    if type.size == 1 # array type
      encode_list(item) {|i| encode_with_type(i, type[0])}
    else # unknown
      raise RLP::InvalidError.new "type size should be 1, got #{type}"
    end
  elsif type == Raw
    encode_raw(item)
  elsif type == Bytes
    raise RLP::InvalidError.new "expect String, got #{item.class}" unless item.is_a?(String)
    encode_raw(item)
  elsif type == List
    raise RLP::InvalidError.new "expect Array, got #{item.class}" unless item.is_a?(Array)
    encode_raw(item)
  else
    raise RLP::InvalidError.new "unknown type #{type}"
  end
rescue
  error "when encoding #{Utils.to_hex item.to_s} into #{type}"
  raise
end

Protected Instance Methods

encode_list(input, &encoder) click to toggle source
# File lib/ciri/rlp/encode.rb, line 128
def encode_list(input, &encoder)
  input ||= [] # allow nil list
  output = encoder ? input.map {|item| encoder.call(item)}.join : input.join
  length = output.length
  if length < 56
    to_binary(0xc0 + length) + output
  elsif length < 256 ** 8
    binary_length = to_binary(length)
    to_binary(0xf7 + binary_length.size) + binary_length + output
  else
    raise InputOverflow.new("input length #{input.size} is too long")
  end
end
encode_raw(input) click to toggle source
# File lib/ciri/rlp/encode.rb, line 103
def encode_raw(input)
  result = if input.is_a?(String)
             encode_string(input)
           elsif input.is_a?(Array)
             encode_list(input) {|item| encode(item)}
           else
             raise ArgumentError.new("input must be a String or Array, #{input.inspect}")
           end
  result.b
end
encode_string(input) click to toggle source
# File lib/ciri/rlp/encode.rb, line 114
def encode_string(input)
  length = input.length
  if length == 1 && input.ord < 0x80
    input
  elsif length < 56
    to_binary(0x80 + length) + input
  elsif length < 256 ** 8
    binary_length = to_binary(length)
    to_binary(0xb7 + binary_length.size) + binary_length + input
  else
    raise InputOverflow.new("input length #{input.size} is too long")
  end
end

Private Instance Methods

to_binary(n) click to toggle source
# File lib/ciri/rlp/encode.rb, line 144
def to_binary(n)
  Ciri::Utils.big_endian_encode(n)
end