diff --git a/apps/blockchain-node/src/aitbc_chain/consensus/poa.py b/apps/blockchain-node/src/aitbc_chain/consensus/poa.py index b4b7cc50..14ad42a0 100755 --- a/apps/blockchain-node/src/aitbc_chain/consensus/poa.py +++ b/apps/blockchain-node/src/aitbc_chain/consensus/poa.py @@ -185,6 +185,7 @@ class PoAProposer: tx_hash=tx.tx_hash, sender=sender, recipient=recipient, + payload=tx_data, value=value, fee=fee, nonce=sender_account.nonce - 1, @@ -237,6 +238,7 @@ class PoAProposer: ) # Broadcast the new block + tx_list = [tx.content for tx in processed_txs] if processed_txs else [] await gossip_broker.publish( "blocks", { @@ -248,7 +250,8 @@ class PoAProposer: "timestamp": block.timestamp.isoformat(), "tx_count": block.tx_count, "state_root": block.state_root, - } + "transactions": tx_list, + }, ) async def _ensure_genesis_block(self) -> None: diff --git a/apps/blockchain-node/src/aitbc_chain/main.py b/apps/blockchain-node/src/aitbc_chain/main.py index a7fd7c2c..c415b31e 100755 --- a/apps/blockchain-node/src/aitbc_chain/main.py +++ b/apps/blockchain-node/src/aitbc_chain/main.py @@ -124,7 +124,7 @@ class BlockchainNode: chain_id = block_data.get("chain_id", settings.chain_id) logger.info(f"Importing block for chain {chain_id}: {block_data.get('height')}") sync = ChainSync(session_factory=session_scope, chain_id=chain_id) - res = sync.import_block(block_data) + res = sync.import_block(block_data, transactions=block_data.get("transactions")) logger.info(f"Import result: accepted={res.accepted}, reason={res.reason}") except Exception as exc: logger.error(f"Error processing block from gossip: {exc}") diff --git a/apps/blockchain-node/src/aitbc_chain/rpc/router.py b/apps/blockchain-node/src/aitbc_chain/rpc/router.py index 9230d8c6..b87220c5 100755 --- a/apps/blockchain-node/src/aitbc_chain/rpc/router.py +++ b/apps/blockchain-node/src/aitbc_chain/rpc/router.py @@ -105,6 +105,14 @@ async def get_block(height: int) -> Dict[str, Any]: metrics_registry.increment("rpc_get_block_not_found_total") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="block not found") metrics_registry.increment("rpc_get_block_success_total") + + txs = session.exec(select(Transaction).where(Transaction.block_height == height)).all() + tx_list = [] + for tx in txs: + t = dict(tx.payload) if tx.payload else {} + t["tx_hash"] = tx.tx_hash + tx_list.append(t) + metrics_registry.observe("rpc_get_block_duration_seconds", time.perf_counter() - start) return { "height": block.height, @@ -114,6 +122,7 @@ async def get_block(height: int) -> Dict[str, Any]: "timestamp": block.timestamp.isoformat(), "tx_count": block.tx_count, "state_root": block.state_root, + "transactions": tx_list, } @@ -151,6 +160,13 @@ async def get_blocks_range(start: int, end: int) -> Dict[str, Any]: # Serialize blocks block_list = [] for block in blocks: + txs = session.exec(select(Transaction).where(Transaction.block_height == block.height)).all() + tx_list = [] + for tx in txs: + t = dict(tx.payload) if tx.payload else {} + t["tx_hash"] = tx.tx_hash + tx_list.append(t) + block_list.append({ "height": block.height, "hash": block.hash, @@ -159,6 +175,7 @@ async def get_blocks_range(start: int, end: int) -> Dict[str, Any]: "timestamp": block.timestamp.isoformat(), "tx_count": block.tx_count, "state_root": block.state_root, + "transactions": tx_list, }) metrics_registry.increment("rpc_get_blocks_range_success_total") diff --git a/apps/coordinator-api/.env.example b/apps/coordinator-api/.env.example index b9867ef1..dbb320d9 100644 --- a/apps/coordinator-api/.env.example +++ b/apps/coordinator-api/.env.example @@ -1,7 +1,7 @@ APP_ENV=dev APP_HOST=127.0.0.1 APP_PORT=8011 -DATABASE_URL=sqlite:///./data/coordinator.db +DATABASE_URL=sqlite:////opt/aitbc/data/coordinator.db CLIENT_API_KEYS=${CLIENT_API_KEY},client_dev_key_2 MINER_API_KEYS=${MINER_API_KEY},miner_dev_key_2 ADMIN_API_KEYS=${ADMIN_API_KEY} diff --git a/apps/coordinator-api/scripts/migrate_complete.py b/apps/coordinator-api/scripts/migrate_complete.py index 1ad80b2d..d3940093 100755 --- a/apps/coordinator-api/scripts/migrate_complete.py +++ b/apps/coordinator-api/scripts/migrate_complete.py @@ -8,7 +8,7 @@ import json from decimal import Decimal # Database configurations -SQLITE_DB = "coordinator.db" +SQLITE_DB = "/opt/aitbc/data/coordinator.db" PG_CONFIG = { "host": "localhost", "database": "aitbc_coordinator", diff --git a/apps/coordinator-api/scripts/migrate_to_postgresql.py b/apps/coordinator-api/scripts/migrate_to_postgresql.py index 85d59095..ef8fdd6f 100755 --- a/apps/coordinator-api/scripts/migrate_to_postgresql.py +++ b/apps/coordinator-api/scripts/migrate_to_postgresql.py @@ -16,7 +16,7 @@ from decimal import Decimal import json # Database configurations -SQLITE_DB = "coordinator.db" +SQLITE_DB = "/opt/aitbc/data/coordinator.db" PG_CONFIG = { "host": "localhost", "database": "aitbc_coordinator", diff --git a/apps/coordinator-api/src/app/config.py b/apps/coordinator-api/src/app/config.py index f55b8de9..c61a9cd1 100755 --- a/apps/coordinator-api/src/app/config.py +++ b/apps/coordinator-api/src/app/config.py @@ -30,7 +30,7 @@ class DatabaseConfig(BaseSettings): # Default SQLite path - consistent with blockchain-node pattern if self.adapter == "sqlite": - return "sqlite:///./data/coordinator.db" + return "sqlite:////opt/aitbc/data/coordinator.db" # Default PostgreSQL connection string return f"{self.adapter}://localhost:5432/coordinator" @@ -187,7 +187,7 @@ class Settings(BaseSettings): if self.database.url: return self.database.url # Default SQLite path - consistent with blockchain-node pattern - return "sqlite:///./data/coordinator.db" + return "sqlite:////opt/aitbc/data/coordinator.db" @database_url.setter def database_url(self, value: str): diff --git a/apps/coordinator-api/src/app/database.py b/apps/coordinator-api/src/app/database.py index 42043e80..eebe1e77 100755 --- a/apps/coordinator-api/src/app/database.py +++ b/apps/coordinator-api/src/app/database.py @@ -2,13 +2,14 @@ from sqlmodel import create_engine, SQLModel from sqlalchemy import StaticPool +from .config import settings -# Create in-memory SQLite database for now +# Create database engine using URL from config engine = create_engine( - "sqlite:///./data/coordinator.db", - connect_args={"check_same_thread": False}, - poolclass=StaticPool, - echo=True # Enable SQL logging for debugging + settings.database_url, + connect_args={"check_same_thread": False} if settings.database_url.startswith("sqlite") else {}, + poolclass=StaticPool if settings.database_url.startswith("sqlite") else None, + echo=settings.test_mode # Enable SQL logging for debugging in test mode ) diff --git a/dev/scripts/dev_heartbeat.py b/dev/scripts/dev_heartbeat.py old mode 100644 new mode 100755