diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..a41da18
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,29 @@
+name: CI
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.11"
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install -e .[dev]
+
+ - name: Lint
+ run: make lint
+
+ - name: Run tests
+ run: make test
diff --git a/.gitignore b/.gitignore
index 9308a4b..d40d7cf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -258,6 +258,17 @@ pythontex-files-*/
# easy-todo
*.lod
+# MiniChain local planning docs (do not commit)
+issues.md
+architectureProposal.md
+
+# Python caches and virtualenvs
+__pycache__/
+*.py[cod]
+.pytest_cache/
+.ruff_cache/
+.venv/
+
# xcolor
*.xcp
@@ -324,3 +335,6 @@ TSWLatexianTemp*
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
# Uncomment the next line to have this generated file ignored.
#*Notes.bib
+
+
+docs/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a99220a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,21 @@
+PYTHON ?= python3
+
+.PHONY: install dev-install test lint format start-node
+
+install:
+ $(PYTHON) -m pip install .
+
+dev-install:
+ $(PYTHON) -m pip install -e .[dev]
+
+test:
+ $(PYTHON) -m pytest
+
+lint:
+ $(PYTHON) -m ruff check src tests
+
+format:
+ $(PYTHON) -m ruff format src tests
+
+start-node:
+ PYTHONPATH=src $(PYTHON) -m minichain --host 127.0.0.1 --port 7000
diff --git a/README.md b/README.md
index 0ea906d..7706e0a 100644
--- a/README.md
+++ b/README.md
@@ -1,236 +1,71 @@
-
-
+# MiniChain
-
-
-

-

-
+MiniChain is a minimal, research-oriented blockchain implementation in Python. This repository currently contains the project scaffolding and development environment for the v0 core chain roadmap.
-
+## Current Status
-
-
+Issue #1 (project scaffolding) is implemented with:
-[](https://TODO.stability.nexus/)
+- Python package layout under `src/minichain`
+- Placeholder component modules for:
+ - `crypto`, `transaction`, `block`, `state`, `mempool`, `consensus`, `network`, `storage`, `node`
+- `pyproject.toml` project configuration
+- `Makefile` for common developer tasks
+- Basic CI workflow (`.github/workflows/ci.yml`)
+- Baseline tests under `tests/`
-
+## Requirements
-
+- Python 3.11+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
----
-
-
-
MiniChain
-
-
-MiniChain is a minimal fully functional blockchain implemented in Python.
-
-### Background and Motivation
-
-* Most well-known blockchains are now several years old and have accumulated a lot of technical debt.
- Simply forking their codebases is not an optimal option for starting a new chain.
-
-* MiniChain will be focused on research. Its primary purpose is not to be yet another blockchain
- trying to be the one blockchain to kill them all, but rather to serve as a clean codebase that can be a benchmark for research of
- variations of the technology. (We hope that MiniChain will be as valuable for blockchain research as, for instance,
- MiniSat was valuable for satisfiability and automated reasoning research. MiniSat had less than 600 lines of C++ code.)
-
-* MiniChain will be focused on education. By having a clean and small codebase, devs will be able to understand
- blockchains by looking at the codebase.
-
-* The blockchain space is again going through a phase where many new blockchains are being launched.
- Back in 2017 and 2018, such an expansion period led to many general frameworks for blockchains,
- such as Scorex and various Hyperledger frameworks. But most of these frameworks suffered from speculative generality and
- were bloated. They focused on extensibility and configurability. MiniChain has a different philosophy:
- focus on minimality and, therefore, ease of modification.
-
-* Recent advances in networking and crypto libraries for Python make it possible to develop MiniChain in Python.
- Given that Python is one of the easiest languages to learn and results in usually boilerplate-minimized and easy to read code,
- implementing MiniChain in Python aligns with MiniChain's educational goal.
-
-
-### Overview of Tasks
-
-* Develop a fully functional minimal blockchain in Python, with all the expected components:
- peer-to-peer networking, consensus, mempool, ledger, ...
-
-* Bonus task: add smart contracts to the blockchain.
-
-Candidates are expected to refine these tasks in their GSoC proposals.
-It is encouraged that you develop an initial prototype during the application phase.
-
-### Requirements
-
-* Use [PyNaCl](https://pynacl.readthedocs.io/en/latest/) library for hashing, signing transactions and verifying signatures.
-* Use [Py-libp2p](https://github.com/libp2p/py-libp2p/tree/main) for p2p networking.
-* Implement Proof-of-Work as the consensus protocol.
-* Use accounts (instead of UTxO) as the accounting model for the ledger.
-* Use as few lines of code as possible without compromising readability and understandability.
-* For the bonus task, make Python itself be the language used for smart contracts, but watch out for security concerns related to executing arbitrary code from untrusted sources.
-
-### Resources
-
-* Read this book: https://www.marabu.dev/blockchain-foundations.pdf
-
-
----
-
-## Project Maturity
-
-TODO: In the checklist below, mark the items that have been completed and delete items that are not applicable to the current project:
-
-* [ ] The project has a logo.
-* [ ] The project has a favicon.
-* [ ] The protocol:
- - [ ] has been described and formally specified in a paper.
- - [ ] has had its main properties mathematically proven.
- - [ ] has been formally verified.
-* [ ] The smart contracts:
- - [ ] were thoroughly reviewed by at least two knights of The Stable Order.
- - [ ] were deployed to:
- - [ ] Ergo
- - [ ] Cardano
- - [ ] EVM Chains:
- - [ ] Ethereum Classic
- - [ ] Ethereum
- - [ ] Polygon
- - [ ] BSC
- - [ ] Base
-* [ ] The mobile app:
- - [ ] has an _About_ page containing the Stability Nexus's logo and pointing to the social media accounts of the Stability Nexus.
- - [ ] is available for download as a release in this repo.
- - [ ] is available in the relevant app stores.
-* [ ] The web frontend:
- - [ ] has proper title and metadata.
- - [ ] has proper open graph metadata, to ensure that it is shown well when shared in social media (Discord, Telegram, Twitter, LinkedIn).
- - [ ] has a footer, containing the Stability Nexus's logo and pointing to the social media accounts of the Stability Nexus.
- - [ ] is fully static and client-side.
- - [ ] is deployed to Github Pages via a Github Workflow.
- - [ ] is accessible through the https://TODO:PROJECT-NAME.stability.nexus domain.
-* [ ] the project is listed in [https://stability.nexus/protocols](https://stability.nexus/protocols).
-
----
-
-## Tech Stack
-
-TODO:
-
-### Frontend
-
-TODO:
-
-- Next.js 14+ (React)
-- TypeScript
-- TailwindCSS
-- shadcn/ui
-
-### Blockchain
-
-TODO:
-
-- Wagmi
-- Solidity Smart Contracts
-- Ethers.js
-
----
-
-## Getting Started
-
-### Prerequisites
-
-TODO
-
-- Node.js 18+
-- npm/yarn/pnpm
-- MetaMask or any other web3 wallet browser extension
-
-### Installation
-
-TODO
-
-#### 1. Clone the Repository
+## Setup
```bash
-git clone https://github.com/StabilityNexus/TODO.git
-cd TODO
+python3 -m venv .venv
+source .venv/bin/activate
+python -m pip install --upgrade pip
+make dev-install
```
-#### 2. Install Dependencies
-
-Using your preferred package manager:
+If you also want networking dependencies:
```bash
-npm install
-# or
-yarn install
-# or
-pnpm install
+python -m pip install -e .[network]
```
-#### 3. Run the Development Server
-
-Start the app locally:
+## Common Commands
```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
+make test # run unit tests
+make lint # run ruff checks
+make format # format with ruff
+make start-node # run scaffold node entrypoint
```
-#### 4. Open your Browser
-
-Navigate to [http://localhost:3000](http://localhost:3000) to see the application.
-
----
-
-## Contributing
-
-We welcome contributions of all kinds! To contribute:
-
-1. Fork the repository and create your feature branch (`git checkout -b feature/AmazingFeature`).
-2. Commit your changes (`git commit -m 'Add some AmazingFeature'`).
-3. Run the development workflow commands to ensure code quality:
- - `npm run format:write`
- - `npm run lint:fix`
- - `npm run typecheck`
-4. Push your branch (`git push origin feature/AmazingFeature`).
-5. Open a Pull Request for review.
+## Run the Node Entrypoint
-If you encounter bugs, need help, or have feature requests:
-
-- Please open an issue in this repository providing detailed information.
-- Describe the problem clearly and include any relevant logs or screenshots.
-
-We appreciate your feedback and contributions!
+```bash
+PYTHONPATH=src python -m minichain --host 127.0.0.1 --port 7000
+```
-© 2025 The Stable Order.
+## Repository Layout
+
+```text
+.github/workflows/ci.yml
+src/minichain/
+ __init__.py
+ __main__.py
+ crypto.py
+ transaction.py
+ block.py
+ state.py
+ mempool.py
+ consensus.py
+ network.py
+ storage.py
+ node.py
+tests/
+ test_scaffold.py
+issues.md
+architectureProposal.md
+```
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..b22da7e
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,39 @@
+[build-system]
+requires = ["hatchling>=1.24"]
+build-backend = "hatchling.build"
+
+[project]
+name = "minichain"
+version = "0.1.0"
+description = "Minimal, research-oriented blockchain in Python"
+readme = "README.md"
+requires-python = ">=3.11"
+authors = [{ name = "MiniChain Contributors" }]
+dependencies = [
+ "PyNaCl>=1.5.0",
+]
+
+[project.optional-dependencies]
+network = [
+ "py-libp2p>=0.2.0",
+]
+dev = [
+ "pytest>=8.0",
+ "ruff>=0.7.0",
+]
+
+[project.scripts]
+minichain-node = "minichain.__main__:main"
+
+[tool.pytest.ini_options]
+minversion = "8.0"
+addopts = "-q"
+testpaths = ["tests"]
+pythonpath = ["src"]
+
+[tool.ruff]
+line-length = 100
+target-version = "py311"
+
+[tool.ruff.lint]
+select = ["E", "F", "I"]
diff --git a/src/minichain/__init__.py b/src/minichain/__init__.py
new file mode 100644
index 0000000..3bc48b2
--- /dev/null
+++ b/src/minichain/__init__.py
@@ -0,0 +1,4 @@
+"""MiniChain package."""
+
+__all__ = ["__version__"]
+__version__ = "0.1.0"
diff --git a/src/minichain/__main__.py b/src/minichain/__main__.py
new file mode 100644
index 0000000..614289f
--- /dev/null
+++ b/src/minichain/__main__.py
@@ -0,0 +1,23 @@
+"""CLI entrypoint for running a MiniChain node."""
+
+from __future__ import annotations
+
+import argparse
+
+from minichain.node import start_node
+
+
+def build_parser() -> argparse.ArgumentParser:
+ parser = argparse.ArgumentParser(description="Run a MiniChain node.")
+ parser.add_argument("--host", default="127.0.0.1", help="Host interface for the node")
+ parser.add_argument("--port", default=7000, type=int, help="Port for the node")
+ return parser
+
+
+def main() -> None:
+ args = build_parser().parse_args()
+ start_node(host=args.host, port=args.port)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/minichain/block.py b/src/minichain/block.py
new file mode 100644
index 0000000..bc33b77
--- /dev/null
+++ b/src/minichain/block.py
@@ -0,0 +1 @@
+"""Block primitives and block-level validation logic (to be implemented)."""
diff --git a/src/minichain/consensus.py b/src/minichain/consensus.py
new file mode 100644
index 0000000..41953b9
--- /dev/null
+++ b/src/minichain/consensus.py
@@ -0,0 +1 @@
+"""Consensus and mining primitives (to be implemented)."""
diff --git a/src/minichain/crypto.py b/src/minichain/crypto.py
new file mode 100644
index 0000000..aec33d7
--- /dev/null
+++ b/src/minichain/crypto.py
@@ -0,0 +1,78 @@
+"""Cryptographic identity and signature helpers."""
+
+from __future__ import annotations
+
+from typing import Any
+
+try:
+ from nacl.encoding import HexEncoder, RawEncoder
+ from nacl.exceptions import BadSignatureError
+ from nacl.hash import blake2b
+ from nacl.signing import SigningKey, VerifyKey
+except ModuleNotFoundError as exc: # pragma: no cover - exercised in dependency-light envs
+ _NACL_IMPORT_ERROR = exc
+ HexEncoder = RawEncoder = None # type: ignore[assignment]
+ BadSignatureError = Exception # type: ignore[assignment]
+ SigningKey = VerifyKey = Any # type: ignore[assignment]
+
+ADDRESS_LENGTH_BYTES = 20
+
+
+def _require_nacl() -> None:
+ if "blake2b" not in globals():
+ msg = "PyNaCl is required for minichain.crypto. Install with: pip install PyNaCl"
+ raise RuntimeError(msg) from _NACL_IMPORT_ERROR
+
+
+def generate_key_pair() -> tuple[SigningKey, VerifyKey]:
+ """Generate a new Ed25519 keypair."""
+ _require_nacl()
+ signing_key = SigningKey.generate()
+ return signing_key, signing_key.verify_key
+
+
+def derive_address(verify_key: VerifyKey) -> str:
+ """Derive a 20-byte address from a verify key as lowercase hex."""
+ _require_nacl()
+ digest = blake2b(verify_key.encode(), encoder=RawEncoder)
+ return digest[:ADDRESS_LENGTH_BYTES].hex()
+
+
+def serialize_signing_key(signing_key: SigningKey) -> str:
+ """Serialize a signing key into a hex string."""
+ _require_nacl()
+ return signing_key.encode(encoder=HexEncoder).decode("ascii")
+
+
+def deserialize_signing_key(signing_key_hex: str) -> SigningKey:
+ """Deserialize a signing key from a hex string."""
+ _require_nacl()
+ return SigningKey(signing_key_hex, encoder=HexEncoder)
+
+
+def serialize_verify_key(verify_key: VerifyKey) -> str:
+ """Serialize a verify key into a hex string."""
+ _require_nacl()
+ return verify_key.encode(encoder=HexEncoder).decode("ascii")
+
+
+def deserialize_verify_key(verify_key_hex: str) -> VerifyKey:
+ """Deserialize a verify key from a hex string."""
+ _require_nacl()
+ return VerifyKey(verify_key_hex, encoder=HexEncoder)
+
+
+def sign_message(message: bytes, signing_key: SigningKey) -> bytes:
+ """Sign bytes and return the detached signature bytes."""
+ _require_nacl()
+ return signing_key.sign(message).signature
+
+
+def verify_signature(message: bytes, signature: bytes, verify_key: VerifyKey) -> bool:
+ """Verify a detached Ed25519 signature."""
+ _require_nacl()
+ try:
+ verify_key.verify(message, signature)
+ except BadSignatureError:
+ return False
+ return True
diff --git a/src/minichain/mempool.py b/src/minichain/mempool.py
new file mode 100644
index 0000000..3e15d3b
--- /dev/null
+++ b/src/minichain/mempool.py
@@ -0,0 +1 @@
+"""Mempool data structures and transaction selection logic (to be implemented)."""
diff --git a/src/minichain/network.py b/src/minichain/network.py
new file mode 100644
index 0000000..7245a33
--- /dev/null
+++ b/src/minichain/network.py
@@ -0,0 +1 @@
+"""P2P networking layer built on py-libp2p (to be implemented)."""
diff --git a/src/minichain/node.py b/src/minichain/node.py
new file mode 100644
index 0000000..8922753
--- /dev/null
+++ b/src/minichain/node.py
@@ -0,0 +1,8 @@
+"""Node orchestration layer for MiniChain."""
+
+from __future__ import annotations
+
+
+def start_node(host: str, port: int) -> None:
+ """Start a MiniChain node (placeholder for Issue #20 integration)."""
+ print(f"MiniChain node scaffold started on {host}:{port}")
diff --git a/src/minichain/state.py b/src/minichain/state.py
new file mode 100644
index 0000000..16dc1a0
--- /dev/null
+++ b/src/minichain/state.py
@@ -0,0 +1 @@
+"""Account state and ledger transitions (to be implemented)."""
diff --git a/src/minichain/storage.py b/src/minichain/storage.py
new file mode 100644
index 0000000..0b8f8ee
--- /dev/null
+++ b/src/minichain/storage.py
@@ -0,0 +1 @@
+"""Persistent storage integration (to be implemented)."""
diff --git a/src/minichain/transaction.py b/src/minichain/transaction.py
new file mode 100644
index 0000000..0957177
--- /dev/null
+++ b/src/minichain/transaction.py
@@ -0,0 +1 @@
+"""Transaction data structures and validation rules (to be implemented)."""
diff --git a/tests/test_crypto.py b/tests/test_crypto.py
new file mode 100644
index 0000000..2b40967
--- /dev/null
+++ b/tests/test_crypto.py
@@ -0,0 +1,63 @@
+"""Unit tests for the cryptographic identity module."""
+
+from __future__ import annotations
+
+import pytest
+
+pytest.importorskip("nacl")
+
+from minichain.crypto import (
+ derive_address,
+ deserialize_signing_key,
+ deserialize_verify_key,
+ generate_key_pair,
+ serialize_signing_key,
+ serialize_verify_key,
+ sign_message,
+ verify_signature,
+)
+
+
+def test_generated_key_pair_can_sign_and_verify() -> None:
+ signing_key, verify_key = generate_key_pair()
+ message = b"minichain-crypto-test"
+
+ signature = sign_message(message, signing_key)
+
+ assert verify_signature(message, signature, verify_key)
+
+
+def test_address_derivation_is_deterministic() -> None:
+ signing_key, verify_key = generate_key_pair()
+ first = derive_address(verify_key)
+ second = derive_address(verify_key)
+
+ assert first == second
+ assert first == derive_address(signing_key.verify_key)
+ assert len(first) == 40
+
+
+def test_invalid_signature_is_rejected() -> None:
+ signing_key, verify_key = generate_key_pair()
+ other_signing_key, _ = generate_key_pair()
+ message = b"minichain-message"
+
+ wrong_signature = sign_message(message, other_signing_key)
+
+ assert not verify_signature(message, wrong_signature, verify_key)
+
+
+def test_key_hex_serialization_round_trip() -> None:
+ signing_key, verify_key = generate_key_pair()
+
+ signing_key_hex = serialize_signing_key(signing_key)
+ verify_key_hex = serialize_verify_key(verify_key)
+
+ decoded_signing_key = deserialize_signing_key(signing_key_hex)
+ decoded_verify_key = deserialize_verify_key(verify_key_hex)
+
+ message = b"serialization-round-trip"
+ signature = sign_message(message, decoded_signing_key)
+
+ assert verify_signature(message, signature, decoded_verify_key)
+ assert derive_address(decoded_verify_key) == derive_address(verify_key)
diff --git a/tests/test_scaffold.py b/tests/test_scaffold.py
new file mode 100644
index 0000000..3ddcaec
--- /dev/null
+++ b/tests/test_scaffold.py
@@ -0,0 +1,31 @@
+"""Scaffolding checks for Issue #1."""
+
+from __future__ import annotations
+
+import importlib
+
+COMPONENT_MODULES = [
+ "crypto",
+ "transaction",
+ "block",
+ "state",
+ "mempool",
+ "consensus",
+ "network",
+ "storage",
+ "node",
+]
+
+
+def test_component_modules_are_importable() -> None:
+ for module in COMPONENT_MODULES:
+ imported = importlib.import_module(f"minichain.{module}")
+ assert imported is not None
+
+
+def test_cli_parser_defaults() -> None:
+ from minichain.__main__ import build_parser
+
+ args = build_parser().parse_args([])
+ assert args.host == "127.0.0.1"
+ assert args.port == 7000