Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
name: Enokiweave CI/CD

permissions: {} # Default to no permissions

on:
push:
branches: [ '**' ]
workflow_dispatch:

env:
CARGO_TERM_COLOR: always
REGISTRY: docker.io
REPOSITORY: myceliumai
IMAGE_NAME: enokiweave

jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
contents: read
outputs:
core: ${{ steps.filter.outputs.core }}
steps:
- uses: actions/checkout@v4

- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
core:
- 'src/**'
- 'Cargo.*'
- '.github/workflows/**'
- 'Dockerfile'

check:
needs: changes
if: ${{ needs.changes.outputs.core == 'true' }}
name: Check
runs-on: ubuntu-latest
continue-on-error: true
permissions:
contents: read
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- name: Set up cargo cache
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-

- name: Install LMDB
run: sudo apt-get update && sudo apt-get install -y liblmdb-dev

- name: Run cargo fmt
run: cargo fmt --all -- --check

- name: Run cargo clippy
run: cargo clippy -- -D warnings

test:
needs: changes
if: ${{ needs.changes.outputs.core == 'true' }}
name: Test Suite
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable

- name: Set up cargo cache
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-

- name: Install LMDB
run: sudo apt-get update && sudo apt-get install -y liblmdb-dev

- name: Run cargo test
run: cargo test

security:
name: Security Checks
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
scanners: 'vuln,secret,config'
- uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
category: 'trivy'

build:
needs: [changes, security, check, test]
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check if should build
id: should_build
run: |
if [[
"${{ github.event_name }}" == "push" &&
"${{ github.ref }}" == "refs/heads/main" &&
"${{ needs.changes.outputs.core }}" == "true"
]]; then
echo "run=true" >> $GITHUB_OUTPUT
fi

- uses: actions/checkout@v4
if: steps.should_build.outputs.run == 'true'

- uses: docker/setup-buildx-action@v3
if: steps.should_build.outputs.run == 'true'

- uses: docker/login-action@v3
if: steps.should_build.outputs.run == 'true'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- uses: docker/metadata-action@v5
if: steps.should_build.outputs.run == 'true'
id: meta
with:
images: ${{ env.REGISTRY }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
type=sha,format=long

- uses: docker/build-push-action@v5
if: steps.should_build.outputs.run == 'true'
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
63 changes: 63 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Build stage
FROM rust:1.75-slim-bullseye as builder

# Install system dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
pkg-config \
liblmdb-dev \
&& rm -rf /var/lib/apt/lists/*

# Create a new empty shell project
WORKDIR /usr/src/enokiweave

# Copy manifests
COPY Cargo.lock Cargo.toml ./

# Copy source code
COPY src ./src
COPY setup ./setup

# Build for release
RUN cargo build --release

# Runtime stage
FROM debian:bullseye-slim

# Install runtime dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
liblmdb0 \
&& rm -rf /var/lib/apt/lists/*

# Create non-root user
RUN groupadd -r enoki && useradd -r -g enoki enoki

# Create necessary directories and set permissions
RUN mkdir -p /var/lib/enokiweave /etc/enokiweave && \
chown -R enoki:enoki /var/lib/enokiweave /etc/enokiweave

# Copy the build artifacts from builder
COPY --from=builder /usr/src/enokiweave/target/release/enokiweave /usr/local/bin/
COPY --from=builder /usr/src/enokiweave/target/release/build-transaction /usr/local/bin/

# Copy configuration files
COPY setup/example_genesis_file.json /etc/enokiweave/genesis.json
COPY setup/example_initial_peers_file.txt /etc/enokiweave/peers.txt

# Set working directory
WORKDIR /var/lib/enokiweave

# Switch to non-root user
USER enoki

# Expose ports
EXPOSE 3001

# Add healthcheck
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3001/health || exit 1

# Set entrypoint
ENTRYPOINT ["enokiweave"]
CMD ["--genesis-file-path", "/etc/enokiweave/genesis.json", "--rpc_port", "3001"]
17 changes: 17 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: '3.8'

services:
enokiweave:
image: ${DOCKER_HUB_USERNAME}/enokiweave:latest
ports:
- "3001:3001"
volumes:
- enokiweave-data:/var/lib/enokiweave
- ./setup/example_genesis_file.json:/etc/enokiweave/genesis.json
- ./setup/example_initial_peers_file.txt:/etc/enokiweave/peers.txt
environment:
- RUST_LOG=info
restart: unless-stopped

volumes:
enokiweave-data:
4 changes: 4 additions & 0 deletions src/address.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
use anyhow::Result;
use serde::{Deserialize, Serialize};

#[allow(dead_code)]
pub const ZERO_ADDRESS: Address = Address([0; 32]);

#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone, Copy)]
pub struct Address(pub [u8; 32]);

impl Address {
#[allow(dead_code)]
pub fn new(data: [u8; 32]) -> Self {
Self(data)
}

#[allow(dead_code)]
pub fn as_hex(&self) -> String {
hex::encode(self.0)
}

#[allow(dead_code)]
pub fn from_hex(hex_address: &str) -> Result<Address> {
let decoded = hex::decode(hex_address)?;
let mut address = [0u8; 32];
Expand Down
41 changes: 21 additions & 20 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use anyhow::{anyhow, Result};
use clap::Parser;
use libp2p::futures::StreamExt;
use libp2p::mdns::tokio::Tokio;
Expand All @@ -17,7 +16,7 @@ use std::error::Error;
use std::sync::Arc;
use tcp::tokio::Transport as TokioTransport;
use tokio::sync::Mutex;
use tracing::{error, info, trace, warn};
use tracing::{info, trace, warn};
use transaction_manager::TransactionManager;

use crate::rpc::run_http_rpc_server;
Expand All @@ -27,7 +26,7 @@ mod rpc;
mod transaction;
mod transaction_manager;

const DB_NAME: &'static str = "./local_db/transaction_db";
const DB_NAME: &str = "./local_db/transaction_db";

#[derive(NetworkBehaviour)]
#[behaviour(out_event = "OutEvent")]
Expand All @@ -43,13 +42,13 @@ impl From<FloodsubEvent> for OutEvent {
}
impl From<MdnsEvent> for OutEvent {
fn from(value: MdnsEvent) -> Self {
OutEvent::Mdns(value)
OutEvent::Mdns(Box::new(value))
}
}

enum OutEvent {
Floodsub(FloodsubEvent),
Mdns(MdnsEvent),
Mdns(Box<MdnsEvent>),
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -77,22 +76,24 @@ async fn handle_swarm_events(mut swarm: Swarm<P2PBlockchainBehaviour>) {
info!("Listening on {:?}", address);
}
SwarmEvent::Behaviour(OutEvent::Floodsub(FloodsubEvent::Message(_))) => {}
SwarmEvent::Behaviour(OutEvent::Mdns(MdnsEvent::Discovered(list))) => {
for (peer_id, _multiaddr) in list {
swarm
.behaviour_mut()
.floodsub
.add_node_to_partial_view(peer_id);
SwarmEvent::Behaviour(OutEvent::Mdns(mdns_event)) => match *mdns_event {
MdnsEvent::Discovered(list) => {
for (peer_id, _multiaddr) in list {
swarm
.behaviour_mut()
.floodsub
.add_node_to_partial_view(peer_id);
}
}
}
SwarmEvent::Behaviour(OutEvent::Mdns(MdnsEvent::Expired(list))) => {
for (peer_id, _multiaddr) in list {
swarm
.behaviour_mut()
.floodsub
.remove_node_from_partial_view(&peer_id);
MdnsEvent::Expired(list) => {
for (peer_id, _multiaddr) in list {
swarm
.behaviour_mut()
.floodsub
.remove_node_from_partial_view(&peer_id);
}
}
}
},
_ => {}
}
}
Expand All @@ -113,7 +114,7 @@ fn are_all_peers_dead(peers: Vec<Multiaddr>, swarm: &mut Swarm<P2PBlockchainBeha
warn!("No peers are alive and reachable");
}
}
return !any_peers_alive;
!any_peers_alive
}

#[tokio::main]
Expand Down
Loading
Loading