Wire Protocols
ELA P2P Message Format
All P2P messages follow this header format:
┌────────────┬────────────┬────────────┬────────────┐
│ Magic (4) │ CMD (12) │ Length (4) │ Checksum(4)│
├────────────┴────────────┴────────────┴────────────┤
│ Payload (variable) │
└────────────────────────────────────────────────────┘
- Magic: 4-byte network identifier (different per network: mainnet, testnet, regnet)
- CMD: 12-byte null-padded ASCII command name
- Length: 4-byte little-endian payload length
- Checksum: First 4 bytes of double-SHA-256 of payload
Message Types
| CMD | Direction | Purpose |
|---|---|---|
version | Both | Protocol version handshake |
verack | Both | Version acknowledgment |
ping | Both | Liveness check |
pong | Both | Liveness response |
getaddr | Request | Request peer addresses |
addr | Response | Send known peer addresses |
inv | Both | Inventory announcement (blocks, txs) |
getdata | Request | Request full block/tx data |
getblocks | Request | Request block hashes (sync) |
block | Response | Full block (DposBlock with optional Confirm) |
tx | Both | Transaction |
notfound | Response | Requested item not found |
mempool | Request | Request mempool contents |
filteradd | Request | Add to bloom filter |
filterclear | Request | Clear bloom filter |
filterload | Request | Load bloom filter |
merkleblock | Response | Partial Merkle tree (for SPV) |
reject | Response | Reject notification |
Handshake Sequence
Initiator Responder
│ │
├── version ──────────────────────>│
│ │
│<────────────────────── version ──┤
│ │
├── verack ───────────────────────>│
│ │
│<─────────────────────── verack ──┤
│ │
│ (connection established) │
The version message contains:
- Protocol version
- Services bitmask
- Timestamp
- Node height
- Nonce (for self-connection detection)
- User agent string
- Relay flag
DPoS P2P Messages
The BPoS consensus subsystem uses encrypted communication on port 20339:
| CMD | Purpose |
|---|---|
proposal | BPoS block proposal from on-duty validator |
vote | BPoS proposal vote (accept/reject) |
confirm | Aggregated confirmation (2/3+ votes) |
viewchange | View change request (when on-duty arbiter fails) |
nextturndposinfo | Next turn validator set announcement |
cipheraddr | Obfuscated validator address exchange |
Arbiter P2P Messages
Validators communicate via the DPoS P2P network using two message types:
const (
DistributeItemCommand = "disitem" // Multi-sig / Schnorr proposals + feedback
SendSchnorrItemCommand = "senditem" // Schnorr phase 3 trigger
)
DistributedItem Wire Format
┌──────────────────┬────────────┬──────────────────┬──────────────┐
│ ContentType (1) │ TxType (1) │ SignedData (var) │ Feedback (var)│
└──────────────────┴────────────┴──────────────────┴──────────────┘
Content types:
| Code | Name | Purpose |
|---|---|---|
0x00 | MultisigContent | Classic multi-sig proposal |
0x01 | IllegalContent | Illegal evidence |
0x02 | SchnorrMultisigContent2 | Schnorr Phase 2 (R request) |
0x03 | SchnorrMultisigContent3 | Schnorr Phase 3 (S request) |
0x10 | AnswerMultisigContent | Multi-sig co-signature |
0x11 | AnswerIllegalContent | Illegal evidence response |
0x12 | AnswerSchnorrMultisigContent2 | Schnorr R response |
0x13 | AnswerSchnorrMultisigContent3 | Schnorr S response |
Transaction types:
| Code | Name |
|---|---|
0x00 | WithdrawTransaction |
0x01 | ReturnDepositTransaction |
0x02 | NFTDestroyTransaction |
ESC/EID Wire Protocol
Standard Ethereum devp2p protocol:
- RLPx transport encryption
- ETH/66 sub-protocol for block/tx propagation
- Snap protocol for fast sync (optional)
- Custom
pbftsub-protocol for PBFT consensus messages
Carrier v2 DHT Wire Format
All DHT messages use CBOR (Concise Binary Object Representation) encoding over UDP:
┌──────────┬────────────┬──────────────────┐
│ Type (1) │ TxID (4) │ CBOR Payload │
└──────────┴────────────┴──────────────────┘
Message types:
0x01: Request (PING, FIND_NODE, FIND_VALUE, STORE)0x02: Response0x03: Error
Each message is encrypted using the recipient's X25519 public key via NaCl CryptoBox.
SPV Bloom Filter Protocol
SPV clients use BIP37-style bloom filter negotiation:
Client Full Node
│ │
├── filterload(filter) ───────────>│ Set bloom filter
│ │
├── getblocks(locator) ───────────>│ Request headers
│ │
│<──────────── merkleblock+tx ─────┤ Filtered blocks
│<──────────── merkleblock+tx ─────┤
│ │
├── filteradd(element) ───────────>│ Add watch address
│ │
├── filterclear ──────────────────>│ Remove filter
│ │
False Positive Rate: Tracked via EWMA (Exponentially Weighted Moving Average) in fprate/fprate.go. When the false positive rate exceeds the target, the bloom filter is rebuilt with a lower FP target.