class Ciri::P2P::Discovery::Protocol::Message
implement the DiscV4 protocol github.com/ethereum/devp2p/blob/master/discv4.md
Constants
- MAX_LEN
Attributes
message_hash[R]
packet_data[R]
packet_type[R]
Public Class Methods
decode_message(raw_bytes)
click to toggle source
return a Message
# File lib/ciri/p2p/discovery/protocol.rb, line 102 def decode_message(raw_bytes) hash = raw_bytes[0...32] # signature is 65 length r,s,v signature = raw_bytes[32...97] packet_type = Utils.big_endian_decode raw_bytes[97] packet_data = raw_bytes[98..-1] Message.new(message_hash: hash, signature: signature, packet_type: packet_type, packet_data: packet_data) end
new(message_hash:, signature:, packet_type:, packet_data:)
click to toggle source
# File lib/ciri/p2p/discovery/protocol.rb, line 45 def initialize(message_hash:, signature:, packet_type:, packet_data:) @message_hash = message_hash @signature = signature @packet_type = packet_type @packet_data = packet_data end
pack(packet, private_key:)
click to toggle source
return a new message instance include packet
# File lib/ciri/p2p/discovery/protocol.rb, line 112 def pack(packet, private_key:) packet_data = Ciri::RLP.encode(packet) packet_type = packet.class.code encoded_packet_type = Utils.big_endian_encode(packet_type) signature = private_key.ecdsa_signature(Utils.keccak(encoded_packet_type + packet_data)).to_s hash = Utils.keccak(signature + encoded_packet_type + packet_data) if (msg_size=hash.size + signature.size + encoded_packet_type.size + packet_data.size) > MAX_LEN raise InvalidMessageError.new("failed to pack, message size is too long, size: #{msg_size}, max_len: #{MAX_LEN}") end Message.new(message_hash: hash, signature: signature, packet_type: packet_type, packet_data: packet_data) end
Public Instance Methods
encode_message()
click to toggle source
encode message to string
# File lib/ciri/p2p/discovery/protocol.rb, line 91 def encode_message buf = String.new buf << message_hash buf << @signature buf << packet_type buf << packet_data buf end
packet()
click to toggle source
# File lib/ciri/p2p/discovery/protocol.rb, line 61 def packet packet_class = case @packet_type when Ping::CODE Ping when Pong::CODE Pong when FindNode::CODE FindNode when Neighbors::CODE Neighbors else raise UnknownMessageCodeError.new("unkonwn discovery message code: #{@packet_type}") end # TODO according discv4 protocol, rlp_decode should support ignore additional elements # we should support ignore_extra_data option in Ciri::RLP packet_class.rlp_decode @packet_data end
sender()
click to toggle source
compute key and return NodeID
# File lib/ciri/p2p/discovery/protocol.rb, line 53 def sender @sender ||= begin encoded_packet_type = Utils.big_endian_encode(packet_type) public_key = Key.ecdsa_recover(Utils.keccak(encoded_packet_type + packet_data), @signature) NodeID.new(public_key) end end
validate()
click to toggle source
validate message hash and signature
# File lib/ciri/p2p/discovery/protocol.rb, line 80 def validate encoded_packet_type = Utils.big_endian_encode(packet_type) raise InvalidMessageError.new("mismatch hash") if message_hash != Utils.keccak(@signature + encoded_packet_type + packet_data) begin sender rescue StandardError => e raise InvalidMessageError.new("recover sender error: #{e}") end end