Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

Public Ledger Auctions — G7

Distributed prototype of a P2P English-auction system backed by a public blockchain ledger.

Quick start

Prerequisites

  • Docker ≥ 24 with the Compose plugin (docker compose version)

Build and start

docker compose up -d --build

Check running services

docker compose ps

View logs

docker compose logs -f            # all services
docker compose logs -f frontend   # single service

Stop (keep volumes)

docker compose stop

Full teardown including volumes

docker compose down -v

Configuration

All tuneable parameters are set via environment variables. Override them in .env (already provided) or inline in docker-compose.yml.

Variable Default Description
P2P_PORT 8080 Netty TCP port for P2P messages
FRONTEND_PORT 8090 HTTP port for the web/REST gateway
ENABLE_FRONTEND false Set true only on the frontend service
POW_DIFFICULTY 16 Leading-zero bits required for PoW block mining
CONSENSUS_MODE POW POW or POR (Proof-of-Reputation)
BOOTSTRAP_HOST (none) Hostname of the bootstrap node to contact on startup
BOOTSTRAP_PORT 8080 Port of the bootstrap node
IDENTITY_PATH (in-memory) Path to persist the node's ECDSA keypair (e.g. /app/data/identity.key)
LEDGER_PATH /app/data/ledger.json Path to the NDJSON ledger file
NODE_ROLE (miner) Set FULL_NODE to disable mining on a node

The provided .env file sets sensible defaults:

POW_DIFFICULTY=16 #or 8

Using the auction interface

Open the web UI at http://localhost:8090 after docker compose up -d.

REST API (base URL: http://localhost:8090)

Health check

curl http://localhost:8090/api/health

Create an auction

curl -s -X POST http://localhost:8090/api/create-auction \
  -H 'Content-Type: application/json' \
  -d '{"itemName":"Bicycle","startingPrice":100.0,"durationSeconds":300}'

Place a bid

curl -s -X POST http://localhost:8090/api/place-bid \
  -H 'Content-Type: application/json' \
  -d '{"itemName":"Bicycle","bidAmount":125.0}'

Close an auction

curl -s -X POST http://localhost:8090/api/close-auction \
  -H 'Content-Type: application/json' \
  -d '{"itemName":"Bicycle"}'

The auction identifier is derived from itemName (SHA-256 hash of the normalised name). Use the exact same name across all operations.


Running the test suite

Tests run outside Docker, against the compiled code directly (no network needed for unit/integration tests).

Prerequisites

  • Java 17+, Maven 3.9+

Run all tests

mvn test

Expected result: 25 tests, 0 failures.

Test coverage

Test class What it covers
Sprint1SecurityTest ECDSA identity, message signing, signature verification, replay rejection
Sprint2OverlayTest Kademlia routing table, bucket eviction, LRU replacement
Sprint2IterativeLookupTest Iterative FIND_NODE / FIND_VALUE across multi-hop topology
Sprint3ConsensusTest Block validation, chain reorg, fork resolution by cumulative work
AuctionLifecycleTest Create → bid → close auction flow, duplicate/invalid bid rejection
PoRConsensusTest PoR difficulty reduction, invalid-block penalty, reputation-weighted chain scoring, miner key JSON round-trip
GossipConvergenceIntegrationTest Multi-node gossip: transaction published to node B converges to node C without manual sync
FaultInjectionResilienceIntegrationTest Simultaneous failure of 2 out of 4 nodes; surviving partition continues accepting transactions and eventually converges

Run a specific test class

mvn test -Dtest=PoRConsensusTest
mvn test -Dtest=FaultInjectionResilienceIntegrationTest

Fault injection and adversarial test scenarios

Scenario 1 — Node crash and recovery

# Start the stack
docker compose up -d

# Create an auction
curl -s -X POST http://localhost:8090/api/create-auction \
  -H 'Content-Type: application/json' \
  -d '{"itemName":"Watch","startingPrice":50.0,"durationSeconds":600}'

# Kill two nodes
docker compose stop node-1 node-2

# Place a bid — surviving nodes must still accept it
curl -s -X POST http://localhost:8090/api/place-bid \
  -H 'Content-Type: application/json' \
  -d '{"itemName":"Watch","bidAmount":75.0}'

# Restart killed nodes
docker compose start node-1 node-2

# Nodes resync chain from peers via gossip/chain-request (check logs)
docker compose logs -f node-1

Expected: bid is accepted while nodes are down; restarted nodes catch up via chain sync.

Scenario 2 — Ledger persistence across full restart

docker compose up -d

curl -s -X POST http://localhost:8090/api/create-auction \
  -H 'Content-Type: application/json' \
  -d '{"itemName":"Lamp","startingPrice":20.0,"durationSeconds":600}'

# Full stop and restart (volumes are kept)
docker compose stop
docker compose start

# Auction must still be present — chain loaded from volume
curl http://localhost:8090/api/health

Expected: chain length ≥ 2 after restart; auction state preserved.

Scenario 3 — Sybil resistance (S/Kademlia)

Node IDs are derived via PoW over the public key (SHA-256(pubkey || nonce) must have N leading zero bits). A new node that tries to join must solve the puzzle before its ID is accepted into routing tables, making cheap Sybil ID generation computationally costly.

Verify the puzzle is enforced:

docker compose logs bootstrap-1 | grep "NodeID generated"
# Output: "NodeID generated successfully! Nonce found: <N>"

Scenario 4 — Invalid block rejection and PoR penalty

Covered by PoRConsensusTest.invalidBlockPenalisesMiner: a block with a tampered hash is rejected and the producing node's reputation is set to 0, increasing its effective mining difficulty on subsequent attempts.


Security properties

Property Mechanism
Node identity ECDSA secp256r1 keypair, persisted across restarts via Docker volume
Transport security TLS 1.3 / 1.2 on all P2P connections (Netty SslHandler)
Message authentication Every SecureMessage is ECDSA-signed by the sender; signature verified on receipt
Anti-replay Per-sender nonce on transactions; monotone nonce enforced at ingestion
Block integrity SHA-256 hash chain; PoW difficulty enforced on all blocks
Sybil resistance (overlay) S/Kademlia: node ID requires PoW over keypair
Sybil resistance (ledger) PoR: repeated invalid blocks reduce reputation and raise effective difficulty
Least exposure Only frontend:8090 and bootstrap ports exposed to host; all other communication stays on the internal auction-net bridge

About

Decentralized P2P auction system backed by a public blockchain ledger. Kademlia DHT, PoW/PoR consensus, TLS, ECDSA

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages