- Remove executable permissions from configuration files (.editorconfig, .env.example, .gitignore) - Remove executable permissions from documentation files (README.md, LICENSE, SECURITY.md) - Remove executable permissions from web assets (HTML, CSS, JS files) - Remove executable permissions from data files (JSON, SQL, YAML, requirements.txt) - Remove executable permissions from source code files across all apps - Add executable permissions to Python
5.8 KiB
5.8 KiB
Blockchain Node Database Schema
This document describes the SQLModel schema for the AITBC blockchain node.
Overview
The blockchain node uses SQLite for local storage with SQLModel (SQLAlchemy + Pydantic).
Tables
Block
Stores blockchain blocks.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY | Auto-increment ID |
height |
INTEGER | UNIQUE, INDEX | Block height |
hash |
VARCHAR | UNIQUE, INDEX | Block hash (hex) |
parent_hash |
VARCHAR | Parent block hash | |
proposer |
VARCHAR | Block proposer address | |
timestamp |
DATETIME | INDEX | Block timestamp |
tx_count |
INTEGER | Transaction count | |
state_root |
VARCHAR | NULLABLE | State root hash |
Relationships:
transactions→ Transaction (one-to-many)receipts→ Receipt (one-to-many)
Transaction
Stores transactions.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY | Auto-increment ID |
tx_hash |
VARCHAR | UNIQUE, INDEX | Transaction hash (hex) |
block_height |
INTEGER | FK → block.height, INDEX | Block containing this tx |
sender |
VARCHAR | Sender address | |
recipient |
VARCHAR | Recipient address | |
payload |
JSON | Transaction data | |
created_at |
DATETIME | INDEX | Creation timestamp |
Relationships:
block→ Block (many-to-one)
Receipt
Stores job completion receipts.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY | Auto-increment ID |
job_id |
VARCHAR | INDEX | Job identifier |
receipt_id |
VARCHAR | UNIQUE, INDEX | Receipt hash (hex) |
block_height |
INTEGER | FK → block.height, INDEX | Block containing receipt |
payload |
JSON | Receipt payload | |
miner_signature |
JSON | Miner's signature | |
coordinator_attestations |
JSON | Coordinator attestations | |
minted_amount |
INTEGER | NULLABLE | Tokens minted |
recorded_at |
DATETIME | INDEX | Recording timestamp |
Relationships:
block→ Block (many-to-one)
Account
Stores account balances.
| Column | Type | Constraints | Description |
|---|---|---|---|
address |
VARCHAR | PRIMARY KEY | Account address |
balance |
INTEGER | Token balance | |
nonce |
INTEGER | Transaction nonce | |
updated_at |
DATETIME | Last update time |
Entity Relationship Diagram
┌─────────────┐
│ Block │
├─────────────┤
│ id │
│ height (UK) │◄──────────────┐
│ hash (UK) │ │
│ parent_hash │ │
│ proposer │ │
│ timestamp │ │
│ tx_count │ │
│ state_root │ │
└─────────────┘ │
│ │
│ 1:N │ 1:N
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Transaction │ │ Receipt │
├─────────────┤ ├─────────────┤
│ id │ │ id │
│ tx_hash(UK) │ │ job_id │
│ block_height│ │ receipt_id │
│ sender │ │ block_height│
│ recipient │ │ payload │
│ payload │ │ miner_sig │
│ created_at │ │ attestations│
└─────────────┘ │ minted_amt │
│ recorded_at │
└─────────────┘
┌─────────────┐
│ Account │
├─────────────┤
│ address(PK) │
│ balance │
│ nonce │
│ updated_at │
└─────────────┘
Validation
Important: SQLModel with table=True does not run Pydantic field validators on model instantiation. Validation must be performed at the API/service layer before creating model instances.
See: https://github.com/tiangolo/sqlmodel/issues/52
Hex Validation
The following fields should be validated as hex strings before insertion:
Block.hashBlock.parent_hashBlock.state_rootTransaction.tx_hashReceipt.receipt_id
Migrations
Initial Setup
from aitbc_chain.database import init_db
init_db() # Creates all tables
Alembic (Future)
For production, use Alembic for migrations:
# Initialize Alembic
alembic init migrations
# Generate migration
alembic revision --autogenerate -m "description"
# Apply migration
alembic upgrade head
Usage Examples
Creating a Block with Transactions
from aitbc_chain.models import Block, Transaction
from aitbc_chain.database import session_scope
with session_scope() as session:
block = Block(
height=1,
hash="0x" + "a" * 64,
parent_hash="0x" + "0" * 64,
proposer="validator1"
)
session.add(block)
session.commit()
tx = Transaction(
tx_hash="0x" + "b" * 64,
block_height=block.height,
sender="alice",
recipient="bob",
payload={"amount": 100}
)
session.add(tx)
session.commit()
Querying with Relationships
from sqlmodel import select
with session_scope() as session:
# Get block with transactions
block = session.exec(
select(Block).where(Block.height == 1)
).first()
# Access related transactions (lazy loaded)
for tx in block.transactions:
print(f"TX: {tx.tx_hash}")