This is a document explaining the current design of the Levin protocol, as used by Monero. The protocol is largely inherited from cryptonote, but has undergone some changes.
This document also may differ from the
struct bucket_head2
in Monero's code slightly - the spec
here is slightly more strict to allow for extensibility.
One of the goals of this document is to clearly indicate what is
being sent "on the wire" to identify metadata that could de-anonymize
users over I2P/Tor. These issues will be addressed as they are found.
See ANONYMITY_NETWORKS.md
in the docs
folder
for any outstanding issues.
This document does not currently list all data being sent by the monero protocol, that portion is a work-in-progress. Please take the time to do it if interested in learning about Monero p2p traffic!
This header is sent for every Monero p2p message.
0 1 2 3
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x01 | 0x21 | 0x01 | 0x01 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x01 | 0x01 | 0x01 | 0x01 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| E. Response | Command
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Return Code
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Q|S|B|E| Reserved
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x01 | 0x00 | 0x00 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x00 |
+-+-+-+-+-+-+-+-+
The first 8 bytes are the "signature" which helps identify the protocol (in case someone connected to the wrong port, etc). The comments indicate that byte sequence is from "benders nightmare".
This also can be used by deep packet inspection (DPI) engines to identify Monero when the link is not encrypted. SSL has been proposed as a means to mitigate this issue, but BIP-151 or the Noise protocol should also be considered.
The length is an unsigned 64-bit little endian integer. The length does not include the header.
The implementation currently rejects received messages that exceed 100 MB (base 10) by default.
A zero-byte if no response is expected from the peer, and a non-zero byte if a response is expected from the peer. Peers must respond to requests with this flag in the same order that they were received, however, other messages can be sent between responses.
There are some commands in the cryptonote protocol where a response is expected from the peer, but this flag is not set. Those responses are returned as notify messages and can be sent in any order by the peer.
An unsigned 32-bit little endian integer representing the Monero specific command being invoked.
A signed 32-bit little endian integer representing the response from
the peer from the last command that was invoked. This is 0
for request messages.
Q
- Bit is set if the message is a request.S
- Bit is set if the message is a response.B
- Bit is set if this is a the beginning of a fragmented message.E
- Bit is set if this is the end of a fragmented message.A fixed value of 1
as an unsigned 32-bit little endian
integer.
The protocol can be subdivided into: (1) notifications, (2) requests, (3) responses, (4) fragmented messages, and (5) dummy messages. Response messages must be sent in the same order that a peer issued a request message. A peer does not have to send a response immediately following a request - any other message type can be sent instead.
Notifications are one-way messages that can be sent at any time
without an expectation of a response from the peer. The Q
bit must be set, the S
, B
and E
bits must be unset, and the Expect Response
field must be
zeroed.
Some notifications must be in response to other notifications. This is not part of the levin messaging layer, and is described in the commands section.
Requests are the basis of the admin protocol for Monero. The
Q
bit must be set, the S
, B
and
E
bits must be unset, and the Expect Response
field must be non-zero. The peer is expected to send a response message
with the same command
number.
Response message can only be sent after a peer first issues a request
message. Responses must have the S
bit set, the
Q
, B
and E
bits unset, and have a
zeroed Expect Response
field. The Command
field must be the same value that was sent in the request message. The
Return Code
is specific to the Command
being
issued (see [commands])(#commands)).
Fragmented messages were introduced for the "white noise" feature for
i2p/tor. A transaction can be sent in fragments to conceal when "real"
data is being sent instead of dummy messages. Only one fragmented
message can be sent at a time, and bits B
and
E
are never set at the same time (see dummy messages). The re-constructed message must
contain a levin header for a different (non-fragment) message type.
The Q
and S
bits are never set and the
Expect Response
field must always be zero. The first
fragment has the B
bit set, neither B
nor
E
is set for "middle" fragments, and E
is set
for the last fragment.
Dummy messages have the B
and E
bits set,
the Q
and S
bits unset, and the
Expect Response
field zeroed. When a message of this type
is received, the contents can be safely ignored.
1001
Request)
Handshake1001
Response)
Handshake1002
Request) Timed
Sync1002
Response) Timed
Sync1003
Request) Ping1003
Response) Ping1004
Request) Stat
Info1004
Response) Stat
Info1005
Request) Network
State1005
Response)
Network State1006
Request) Peer ID1006
Response) Peer ID1007
Request) Support
Flags1007
Response)
Support Flags2001
Notification)
New Block2002
Notification) New Transactions2003
Notification) Request Get Objects2004
Notification) Response Get Objects2006
Notification) Request Chain2007
Notification) Response Chain Entry2008
Notification) New Fluffy Block2009
Notification) Request Fluffy Missing TX