fix: improve blockchain node RPC responses and database path consistency

- Add transaction data to RPC responses (get_block, get_blocks_range)
- Fix import_block to handle transactions parameter
- Change database paths to absolute paths for consistency
- Make dev_heartbeat.py executable
This commit is contained in:
2026-03-24 10:12:24 +01:00
parent bbe67239a1
commit 9302661dc4
9 changed files with 33 additions and 12 deletions

View File

@@ -185,6 +185,7 @@ class PoAProposer:
tx_hash=tx.tx_hash, tx_hash=tx.tx_hash,
sender=sender, sender=sender,
recipient=recipient, recipient=recipient,
payload=tx_data,
value=value, value=value,
fee=fee, fee=fee,
nonce=sender_account.nonce - 1, nonce=sender_account.nonce - 1,
@@ -237,6 +238,7 @@ class PoAProposer:
) )
# Broadcast the new block # Broadcast the new block
tx_list = [tx.content for tx in processed_txs] if processed_txs else []
await gossip_broker.publish( await gossip_broker.publish(
"blocks", "blocks",
{ {
@@ -248,7 +250,8 @@ class PoAProposer:
"timestamp": block.timestamp.isoformat(), "timestamp": block.timestamp.isoformat(),
"tx_count": block.tx_count, "tx_count": block.tx_count,
"state_root": block.state_root, "state_root": block.state_root,
} "transactions": tx_list,
},
) )
async def _ensure_genesis_block(self) -> None: async def _ensure_genesis_block(self) -> None:

View File

@@ -124,7 +124,7 @@ class BlockchainNode:
chain_id = block_data.get("chain_id", settings.chain_id) chain_id = block_data.get("chain_id", settings.chain_id)
logger.info(f"Importing block for chain {chain_id}: {block_data.get('height')}") logger.info(f"Importing block for chain {chain_id}: {block_data.get('height')}")
sync = ChainSync(session_factory=session_scope, chain_id=chain_id) 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}") logger.info(f"Import result: accepted={res.accepted}, reason={res.reason}")
except Exception as exc: except Exception as exc:
logger.error(f"Error processing block from gossip: {exc}") logger.error(f"Error processing block from gossip: {exc}")

View File

@@ -105,6 +105,14 @@ async def get_block(height: int) -> Dict[str, Any]:
metrics_registry.increment("rpc_get_block_not_found_total") metrics_registry.increment("rpc_get_block_not_found_total")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="block not found") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="block not found")
metrics_registry.increment("rpc_get_block_success_total") 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) metrics_registry.observe("rpc_get_block_duration_seconds", time.perf_counter() - start)
return { return {
"height": block.height, "height": block.height,
@@ -114,6 +122,7 @@ async def get_block(height: int) -> Dict[str, Any]:
"timestamp": block.timestamp.isoformat(), "timestamp": block.timestamp.isoformat(),
"tx_count": block.tx_count, "tx_count": block.tx_count,
"state_root": block.state_root, "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 # Serialize blocks
block_list = [] block_list = []
for block in blocks: 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({ block_list.append({
"height": block.height, "height": block.height,
"hash": block.hash, "hash": block.hash,
@@ -159,6 +175,7 @@ async def get_blocks_range(start: int, end: int) -> Dict[str, Any]:
"timestamp": block.timestamp.isoformat(), "timestamp": block.timestamp.isoformat(),
"tx_count": block.tx_count, "tx_count": block.tx_count,
"state_root": block.state_root, "state_root": block.state_root,
"transactions": tx_list,
}) })
metrics_registry.increment("rpc_get_blocks_range_success_total") metrics_registry.increment("rpc_get_blocks_range_success_total")

View File

@@ -1,7 +1,7 @@
APP_ENV=dev APP_ENV=dev
APP_HOST=127.0.0.1 APP_HOST=127.0.0.1
APP_PORT=8011 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 CLIENT_API_KEYS=${CLIENT_API_KEY},client_dev_key_2
MINER_API_KEYS=${MINER_API_KEY},miner_dev_key_2 MINER_API_KEYS=${MINER_API_KEY},miner_dev_key_2
ADMIN_API_KEYS=${ADMIN_API_KEY} ADMIN_API_KEYS=${ADMIN_API_KEY}

View File

@@ -8,7 +8,7 @@ import json
from decimal import Decimal from decimal import Decimal
# Database configurations # Database configurations
SQLITE_DB = "coordinator.db" SQLITE_DB = "/opt/aitbc/data/coordinator.db"
PG_CONFIG = { PG_CONFIG = {
"host": "localhost", "host": "localhost",
"database": "aitbc_coordinator", "database": "aitbc_coordinator",

View File

@@ -16,7 +16,7 @@ from decimal import Decimal
import json import json
# Database configurations # Database configurations
SQLITE_DB = "coordinator.db" SQLITE_DB = "/opt/aitbc/data/coordinator.db"
PG_CONFIG = { PG_CONFIG = {
"host": "localhost", "host": "localhost",
"database": "aitbc_coordinator", "database": "aitbc_coordinator",

View File

@@ -30,7 +30,7 @@ class DatabaseConfig(BaseSettings):
# Default SQLite path - consistent with blockchain-node pattern # Default SQLite path - consistent with blockchain-node pattern
if self.adapter == "sqlite": if self.adapter == "sqlite":
return "sqlite:///./data/coordinator.db" return "sqlite:////opt/aitbc/data/coordinator.db"
# Default PostgreSQL connection string # Default PostgreSQL connection string
return f"{self.adapter}://localhost:5432/coordinator" return f"{self.adapter}://localhost:5432/coordinator"
@@ -187,7 +187,7 @@ class Settings(BaseSettings):
if self.database.url: if self.database.url:
return self.database.url return self.database.url
# Default SQLite path - consistent with blockchain-node pattern # Default SQLite path - consistent with blockchain-node pattern
return "sqlite:///./data/coordinator.db" return "sqlite:////opt/aitbc/data/coordinator.db"
@database_url.setter @database_url.setter
def database_url(self, value: str): def database_url(self, value: str):

View File

@@ -2,13 +2,14 @@
from sqlmodel import create_engine, SQLModel from sqlmodel import create_engine, SQLModel
from sqlalchemy import StaticPool 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( engine = create_engine(
"sqlite:///./data/coordinator.db", settings.database_url,
connect_args={"check_same_thread": False}, connect_args={"check_same_thread": False} if settings.database_url.startswith("sqlite") else {},
poolclass=StaticPool, poolclass=StaticPool if settings.database_url.startswith("sqlite") else None,
echo=True # Enable SQL logging for debugging echo=settings.test_mode # Enable SQL logging for debugging in test mode
) )

0
dev/scripts/dev_heartbeat.py Normal file → Executable file
View File