Two-port Recursive-length prefix (RLP) serialization simulation using Tokio. RLP logic is written from scratch.
Server (port 9999) Client (port 9998)
┌─────────────────┐ ┌─────────────────┐
│ Listens on 9999 │◄── ack channel ──│ Connects to 9999│
│ │ │ │
│ Connects to 9998│── data channel ─►│ Listens on 9998 │
└─────────────────┘ └─────────────────┘
- Port 9999: Server listens, receives acks from client
- Port 9998: Client listens, receives RLP-encoded transactions from server
Two independent TCP connections. Data flows server → client on one, acknowledgement signal (acks) flow client → server on the other.
Build:
cargo build --releaseTerminal 1 (start the server first):
cargo run --bin serverTerminal 2:
cargo run --bin clientOnce both are connected, type commands in the server terminal:
Send string data
> data
> data hello
> data hello world
> data blah blah blah blah blah blah blah blah blah blah blah blah blah
> quit
Format: data <value>
Send Transaction data (Simulates transaction objects on EVM chains)
> tx deadbeef 1000000
> tx cafe 500
> tx ab01cd02ef03 999
> quit
Format: tx <to_address_hex> <value>
The server encodes each transaction as RLP, sends it over TCP to the client's port. The client decodes it, prints the raw bytes and decoded fields, then sends an ack back to the server's port.
src/
├── lib.rs # Transaction type, encode_string / decode_string helpers
├── rlp/
│ ├── mod.rs # Rlp, RlpStream, Encodable, Decodable, DecoderError
│ ├── encode.rs # Encoding helpers + Encodable impls for primitives
│ └── decode.rs # Decoding helpers + Decodable impls for primitives
└── bin/
├── server.rs # TCP server — reads stdin, encodes and sends RLP
└── client.rs # TCP client — receives RLP, decodes and prints
tokio— async runtime and TCPhex— hex string parsing for addresses
RLP encoding/decoding is implemented from scratch in src/rlp/.