lib/eth/rlp/encoder.rb
# Copyright (c) 2016-2023 The Ruby-Eth Contributors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # -*- encoding : ascii-8bit -*- # Provides the {Eth} module. module Eth # Provides an recursive-length prefix (RLP) encoder and decoder. module Rlp # Provides an RLP-encoder. module Encoder extend self # Encodes a Ruby object in RLP format. # # @param obj [Object] a Ruby object. # @return [String] the RLP encoded item. # @raise [Eth::Rlp::EncodingError] in the rather unlikely case that the item # is too big to encode (will not happen). # @raise [Eth::Rlp::SerializationError] if the serialization fails. def perform(obj) item = Sedes.infer(obj).serialize(obj) result = encode_raw item end private # Encodes the raw item. def encode_raw(item) return item if item.instance_of? Rlp::Data return encode_primitive item if Util.primitive? item return encode_list item if Util.list? item raise EncodingError "Cannot encode object of type #{item.class.name}" end # Encodes a single primitive. def encode_primitive(item) return Util.str_to_bytes item if item.size == 1 && item.ord < Constant::PRIMITIVE_PREFIX_OFFSET payload = Util.str_to_bytes item prefix = length_prefix payload.size, Constant::PRIMITIVE_PREFIX_OFFSET "#{prefix}#{payload}" end # Encodes a single list. def encode_list(list) payload = list.map { |item| encode_raw item }.join prefix = length_prefix payload.size, Constant::LIST_PREFIX_OFFSET "#{prefix}#{payload}" end # Determines a length prefix. def length_prefix(length, offset) if length < Constant::SHORT_LENGTH_LIMIT (offset + length).chr elsif length < Constant::LONG_LENGTH_LIMIT length_string = Util.int_to_big_endian length length_len = (offset + Constant::SHORT_LENGTH_LIMIT - 1 + length_string.size).chr "#{length_len}#{length_string}" else raise EncodingError, "Length greater than 256**8: #{length}" end end end end end