Shekyl Stats

Refreshing...

Network

Connected
Seed Nodes Active
--

Chain

Current Block
0
Target Height
0
Top Block Hash
--
Block Time Target
2 min

Rewards

Last Block Reward
0.000000 SKL
Difficulty
0
Estimated Hash Rate
0 H/s

Supply

Circulating Supply
--
Remaining Supply
--
Total Burned
0.000000 SKL

Economics

Release Multiplier
0
Burn Rate %
0

Staking

Stake Ratio
0
Staker Pool
0.000000 SKL
Staker Emission Share
0
Total Staked
N/A
Staking Height
N/A
Tier 0 Lock Blocks
N/A
Tier 1 Lock Blocks
N/A
Tier 2 Lock Blocks
N/A

Protocol

Transaction Format
TransactionV3
Membership Proof
FCMP++
Spend Auth
Ed25519 + ML-DSA-65
Confidentiality
Stealth + BP+

Node

TX Pool Size
0
Database Size
0 B
Node Version
--
Sync Status
Syncing
All Documentation

Levin Protocol

P2P network protocol specification for node-to-node communication.

Levin Protocol

This is a document explaining the current design of the Levin protocol, as used by Shekyl. The protocol is largely inherited from cryptonote, but has undergone some changes.

This document also may differ from the struct bucket_head2 in Shekyl'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.

PQC note:

  • the transport header described here is unchanged by the planned PQC rollout
  • however, reboot-only TransactionV3 objects with hybrid signatures will make transaction-bearing protocol messages materially larger
  • the canonical transaction/authentication format is specified in POST_QUANTUM_CRYPTOGRAPHY.md

This document does not currently list all data being sent by the Shekyl protocol, that portion is a work-in-progress. Please take the time to do it if interested in learning about Shekyl p2p traffic!

Implementations: the live daemon path is C++ (contrib/epee/include/net/levin_*, contrib/epee/src/levin_*). A byte-identical Rust framing implementation lives at rust/shekyl-levin (LV-1, KAT'd against the C++ unit tests, with ci/levin-constant-parity guarding the shared wire constants); it is deliberately unwired until the scheduled p2p cutover. Where it is deliberately stricter than the C++, the authoritative list is the crate's own docs (rust/shekyl-levin/src/lib.rs) — kept in one place on purpose. Command bodies are epee portable_storage. The binary codec is rust/shekyl-portable-storage (LV-2a, landed). Typed Levin command maps in shekyl-levin are LV-2b (landed): handshake / timed-sync / ping / support-flags, network_address, and notifies 2002–2004 / 2006–2010. Cryptonote blobs stay opaque bytes (shekyl-wire). Live shekyld dual-stack is the #[ignore] harness rust/shekyl-levin/tests/dual_stack.rs (SHEKYLD_BIN; docs/design/LV2_PORTABLE_STORAGE.md §12 step 4). Decision: docs/design/LV2_PORTABLE_STORAGE.md. See also docs/design/IMPLEMENTATION_INDEX.md (LV row) and the docs/FOLLOWUPS.md "Levin p2p migration" entry.

This header is sent for every Shekyl p2p message. It is 29 bytes. PWD-B5 deleted the inherited signed i32 that used to sit at offset 21 (return_code); flags follow command immediately. The slot is retired, never reused.

 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |Q|S|B|E|               Reserved
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |      0x01     |      0x00     |      0x00     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     0x00      |
+-+-+-+-+-+-+-+-+

Signature

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 Shekyl 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.

Length

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.

Expect Response

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.

Command

An unsigned 32-bit little endian integer representing the Shekyl-specific command being invoked.

Flags

  • 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.

Version

A fixed value of 1 as an unsigned 32-bit little endian integer.

Message Flow

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

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

Requests are the basis of the admin protocol for Shekyl. 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.

Responses

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. Application success or failure is the payload or hanging up; there is no header status field.

Fragmented

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

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.

Commands

This document currently focuses on the Levin framing layer and high-level command inventory. It does not yet enumerate every field in every transaction- bearing payload.

For the rebooted chain:

  • commands that relay transactions or blocks will eventually carry TransactionV3 payloads
  • TransactionV3 introduces dedicated PQ authentication fields outside tx_extra
  • downstream tooling must not assume pre-PQC transaction sizes

P2P (Admin) Commands

(1001 Request) Handshake

(1001 Response) Handshake

(1002 Request) Timed Sync

(1002 Response) Timed Sync

(1003 Request) Ping

(1003 Response) Ping

(1007 Request) Support Flags

(1007 Response) Support Flags

Commands 1004–1006 (Stat Info / Network State / Peer ID) do not exist in Shekyl. COMMAND_REQUEST_SUPPORT_FLAGS is P2P_COMMANDS_POOL_BASE + 7. Do not reintroduce them.

Cryptonote Protocol Commands

(2001 Notification) New Block — deleted (PWD-B6)

Command 2001 is refused as unknown. Shekyl never needed Monero's full-block / compact-block dual path; 2001 already forwarded into the 2008 handler, so the second id was a wire alias with a 32× weaker cap. NOTIFY_NEW_COMPACT_BLOCK (2008) is the sole block announce.

(2002 Notification) New Transactions

Carries one or more serialized transactions for mempool relay. This is the primary message type affected by v3 PQC sizing: each TransactionV3 user transaction adds 5389 bytes of hybrid authentication data (pqc_auth_weight(); see docs/V3_ROLLOUT.md).

Over anonymity networks, this message is the most fingerprinting-sensitive: it is sent shortly after a wallet constructs a transaction and is the strongest timing signal linking a peer to a spend event.

(2003 Notification) Request Get Objects

(2004 Notification) Response Get Objects

Response carries requested block/transaction objects. Payload size is variable and scales linearly with the number of v3 transactions in the requested range.

(2006 Notification) Request Chain

(2007 Notification) Response Chain Entry

Carries block hashes for chain synchronization. Not affected by v3 PQC sizing (block headers do not contain pqc_auth).

(2008 Notification) New Compact Block

Sole block-announce path after PWD-B6. Header plus optional tx bodies; relay typically omits txs. The receiving peer requests missing transactions via 2009. Full blocks still travel on 2004 during sync. Not directly affected by PQC sizing, but the follow-up 2009 exchange is.

(2009 Notification) Request Compact Missing TX

Requests omitted transactions by index in the compact-block header. The fill is another 2008 carrying the requested tx bodies, including pqc_auth.

(2010 Notification) Get Txpool Complement

Carries a list of transaction hashes (CONTAINER_POD_AS_BLOB). Live in NOTIFY_GET_TXPOOL_COMPLEMENT (cryptonote_protocol_defs.h) and handled by handle_notify_get_txpool_complement. Command 2005 was never allocated.

Command-body field layouts for 1001 / 1002 / 1003 / 1007 and notifies 2002–2004 / 2006–2010 live in shekyl-levin (payload). See LV2_PORTABLE_STORAGE.md §5–§6.

Wire Data Privacy Summary

CommandPQC size impactAnonymity sensitivityNotes
1001 HandshakeNoneLowPeer identity exchange
1002 Timed SyncNoneMediumTimestamp fingerprinting risk
2002 New Transactions+5.4 KB per user txHighOrigin-attributable timing signal
2003/2004 Get ObjectsProportional to tx countLowSync protocol
2006/2007 Chain EntryNoneNoneHash-only
2008 Compact BlockMinimalLowSole block announce (PWD-B6); header + optional txs
2009 Compact missing TX+5.4 KB per requested txMediumFollow-up to compact block
2010 Txpool complementNone (hashes only)LowMempool hash set