class Eth::Tx

def self.decode(data)

def self.decode(data)
  data = Utils.hex_to_bin(data) if data.match(/\A(?:0x)?\h+\Z/)
  deserialize(RLP.decode data)
end

def check_transaction_validity

def check_transaction_validity
  if [gas_price, gas_limit, value, nonce].max > UINT_MAX
    raise InvalidTransaction, "Values way too high!"
  elsif gas_limit < intrinsic_gas_used
    raise InvalidTransaction, "Gas limit too low"
  end
end

def data

def data
  Eth.tx_data_hex? ? data_hex : data_bin
end

def data=(string)

def data=(string)
  Eth.tx_data_hex? ? self.data_hex=(string) : self.data_bin=(string)
end

def data_hex

def data_hex
  Utils.bin_to_prefixed_hex data_bin
end

def data_hex=(hex)

def data_hex=(hex)
  self.data_bin = Utils.hex_to_bin(hex)
end

def encoded

def encoded
  RLP.encode self
end

def from

def from
  if signature
    public_key = OpenSsl.recover_compact(signature_hash, signature)
    Utils.public_key_to_address(public_key) if public_key
  end
end

def hash

def hash
  "0x#{Utils.bin_to_hex Utils.keccak256_rlp(self)}"
end

def hash_keys

def hash_keys
  keys = self.class.serializable_fields.keys
  keys.delete(:data_bin)
  keys + [:data]
end

def hex

def hex
  Utils.bin_to_prefixed_hex encoded
end

def initialize(params)

def initialize(params)
  fields = {v: 0, r: 0, s: 0}.merge params
  fields[:to] = Utils.normalize_address(fields[:to])
  if params[:data]
    self.data = params.delete(:data)
    fields[:data_bin] = data_bin
  end
  serializable_initialize fields
  check_transaction_validity
end

def intrinsic_gas_used

def intrinsic_gas_used
  num_zero_bytes = data_bin.count(BYTE_ZERO)
  num_non_zero_bytes = data_bin.size - num_zero_bytes
  Gas::GTXCOST +
    Gas::GTXDATAZERO * num_zero_bytes +
    Gas::GTXDATANONZERO * num_non_zero_bytes
end

def sedes

def sedes
  if Eth.prevent_replays? && !(Eth.replayable_v? v)
    self.class
  else
    UnsignedTx
  end
end

def sign(key)

def sign(key)
  self.signature = key.sign(unsigned_encoded)
  vrs = Utils.v_r_s_for signature
  self.v = vrs[0]
  self.r = vrs[1]
  self.s = vrs[2]
  self
end

def signature

def signature
  return @signature if @signature
  self.signature = [
    Utils.int_to_base256(v),
    Utils.zpad_int(r),
    Utils.zpad_int(s),
  ].join if [v, r, s].all?
end

def signature_hash

def signature_hash
  Utils.keccak256 unsigned_encoded
end

def signing_data

def signing_data
  Utils.bin_to_prefixed_hex unsigned_encoded
end

def to_h

def to_h
  hash_keys.inject({}) do |hash, field|
    hash[field] = send field
    hash
  end
end

def unsigned

def unsigned
  Tx.new to_h.merge(v: Eth.chain_id, r: 0, s: 0)
end

def unsigned_encoded

def unsigned_encoded
  RLP.encode(unsigned, sedes: sedes)
end