Skip to content

kon14/Taliro

Repository files navigation

A UTXO-based blockchain written in Rust πŸ¦€.


Despite its simplicity, this project aims to demonstrate a fully somewhat-functional UTXO-based blockchain.
Taliro nodes connect to each other over a P2P network, exchanging blocks and transactions.
Each node maintains its own local copy of the blockchain.

A RESTful API is exposed for developer-focused interaction and inspection purposes.
It allows for basic blockchain state querying, submission of transactions, ad hoc block mining and peer inspection.
This is NOT meant to be a secure user-facing API, as such endpoint payloads are structured in a way that facilitates development.
Rudimentary dev endpoint authorization is supported via an optional master key secret.


Running via Docker Compose πŸ’»

# Bring up two Taliro nodes (no authorization)
> docker compose up --build

# Bring up two Taliro nodes (secret key authorization)
> HTTP_MASTER_KEY_SECRET="7h3 c4k3 15 4 l13" docker compose up --build

# View node logs
> docker compose logs -f taliro-node-alpha
> docker compose logs -f taliro-node-beta

# Stop the nodes
> docker compose down

# Stop and remove all data
> docker compose down -v
πŸ” SELinux Compatibility

SELinux users may face issues accessing the Docker socket, despite being members of the docker user group.
While configuring SELinux policies is outside the scope of this readme file, you may temporarily bypass it as follows:

# Check for AVC denial logs
> journalctl -b | grep 'avc:  denied'

# Put SELinux in permissive mode
> sudo setenforce 0
🦭 Podman Compatibility

Podman is technically supported, but depending on your setup, you might need a couple of workarounds.
Head over to docker-compose.yml and flip any relevant promtail volume entries to their corresponding podman variants.

If you're facing issues around DNS resolution, you're likely hitting a podman-compose bug resulting in containers not being registered to the taliro-net network.
Troubleshooting instructions are provided within docker-compose.yml.

# Navigate to Swagger UI (on Linux)
> xdg-open "http://localhost:4100/swagger/index.html" # Node Alpha
> xdg-open "http://localhost:4200/swagger/index.html" # Node Beta

Note: Make sure you bring up the full Swagger UI path to avoid 404s caused by path normalization redirects.


Monitoring πŸ•΅πŸ»

# Navigate to Grafana (on Linux)
> xdg-open "http://localhost:3000"

Note: Grafana might take a few seconds to spin up.
Credentials: admin / admin.


Architecture Overview πŸ—οΈ

flowchart TD
    HTTP["<ins>**HTTP Dev API**</ins><br />(Axum)"]
    P2P["<ins>**P2P Network**</ins><br />(libp2p)<br /><br />- Gossipsub<br />- Kademlia<br />- Taliro (Request/Response)"]
    UC[Application Use Cases]
    NODE_CMD[<ins>**Node**</ins><br />Command Orchestration<br />Event Loop]
    BC[Blockchain]
    MP[Mempool]
    UTXO[UTXO Set]
    BLOCK_VAL[Block Validator]
    TX_VAL[Transaction Validator]
    SYNC_Q[Block Sync Queue]
    PROC_Q[Block Processing Queue]
    OUTBOX[Outbox]
    SLED["<ins>**Storage**</ins><br />(Sled)<br />"]
    
    HTTP --> UC
    P2P --> NODE_CMD
    UC --> NODE_CMD
    NODE_CMD --> BC
    NODE_CMD --> MP
    NODE_CMD --> UTXO
    NODE_CMD --> P2P
    NODE_CMD --> SYNC_Q
    SYNC_Q --> PROC_Q
    BC --> BLOCK_VAL
    BC --> OUTBOX
    BLOCK_VAL --> TX_VAL
    MP --> TX_VAL
    OUTBOX --> NODE_CMD
    BC --> SLED
    UTXO --> SLED
    NODE_CMD --> SLED
    OUTBOX --> SLED
    
    %% Styling External Boundaries
    style HTTP fill:#ffcc00,stroke:#000000,stroke-width:2px,color:#000000
    style P2P fill:#ffcc00,stroke:#000000,stroke-width:2px,color:#000000
    
    %% Styling Node Orchestrator
    style NODE_CMD fill:#87ceeb,stroke:#000000,stroke-width:3px,color:#000000
    
    %% Styling Core Components
    style BC fill:#b19cd9,stroke:#000000,stroke-width:2px,color:#000000
    style MP fill:#b19cd9,stroke:#000000,stroke-width:2px,color:#000000
    style UTXO fill:#b19cd9,stroke:#000000,stroke-width:2px,color:#000000
    
    %% Styling Internal Storage
    style SLED fill:#90ee90,stroke:#000000,stroke-width:2px,color:#000000
Loading

I see you've taken an interest in this one πŸ€”.
Whether it's cause you like what you see or you absolutely loathe it...
You may always refer to the Architecture Documentation for a detailed analysis of the project and its design decisions.


Environment Variables πŸ“ƒ

Variable Description Required Default Example
STORAGE_DB_PATH The filesystem path to be used for your Sled storage. True β€” $XDG_CONFIG_HOME/blockchain/db
HTTP_API_PORT The port to be used by the HTTP server. False 4000 8080
HTTP_API_BASE_URL A public URL pointing to the backend API's root path. True β€” https://foo.bar.baz/api
HTTP_MASTER_KEY_SECRET Optional secret to be used for development endpoint authorization. False β€” 7h3 c4k3 15 4 l13
NETWORK_LISTEN_ADDRESS The P2P node's network address.
Using an epheral port (tcp/0) will prohibit peers from reconnecting on restart.
False /ip4/0.0.0.0/tcp/0 /ip4/192.168.1.125/tcp/54244
NETWORK_INIT_PEERS Semicolon-separated list of initial peer addresses (multiaddr with peer id). False β€” /ip4/192.168.1.125/tcp/54244/p2p/12D3KooWSg4ox9udRcwrjo8ETg1gjB7g5wSSwjVMGKWJiqF9XjdB;
NETWORK_IDENTITY_KEY_PAIR Base64 encoded ed25519 key pair to be used for persistent node identity.
May be obtained from the dev HTTP API (GET @ /dev/network/self).
False Generated CAESQPDur8zTyaDoZwmCIhtpdaE5s-TjOZd8iQhHKaaL7hQ6-nZnaha4CWVWEtIfYx4Vx53sxrChvlm25_EhXftu9Yo
RUST_LOG Specifies the desired logging level.
Refer to the tracing_subscriber documentation for details.
Syntax is env_logger-compatible.
False error info
CONFIG_PATH Optional path to a TOML configuration file. False β€” $XDG_CONFIG_HOME/blockchain/config.toml

Container Health Monitoring πŸ₯

The container image includes built-in health checks:

# Check container health status
> docker ps --filter "name=taliro-node"

# View health check logs
> docker inspect --format='{{json .State.Health}}' taliro-node-alpha
> docker inspect --format='{{json .State.Health}}' taliro-node-beta
🦭 Podman Compatibility

Podman image builds default to the oci format, which doesn't support health check instructions.
Make sure you build your images in docker format to retain health check functionality.

# Build image, preserving health check instructions
> podman build -t taliro --format docker .

Local Development πŸ‘¨πŸ»β€πŸ”¬

The following section assumes your environment contains an installation of the Rust development toolchain.

# Prepare Git Hooks (Optional)
lefthook install
# Build
> cargo build

# Bring up a node
> HTTP_API_BASE_URL=http://localhost:4000 \
HTTP_API_PORT=4000 \
HTTP_MASTER_KEY_SECRET="7h3 c4k3 15 4 l13" \
NETWORK_LISTEN_ADDRESS=/ip4/0.0.0.0/tcp/2048 \
NETWORK_INIT_PEERS=/ip4/192.168.1.125/tcp/2049/p2p/12D3KooWKwUzXLNEAF97yuvyvWNVVunxAULArPj7pHWAvSveU1rc; \
NETWORK_IDENTITY_KEY_PAIR=CAESQPDur8zTyaDoZwmCIhtpdaE5s-TjOZd8iQhHKaaL7hQ6-nZnaha4CWVWEtIfYx4Vx53sxrChvlm25_EhXftu9Yo \
cargo run

About

A UTXO-based blockchain written in Rust πŸ¦€.

Topics

Resources

License

Stars

Watchers

Forks