fix: parent block validation in importBlock + no retry on 4xx in AITBCHTTPClient
Some checks failed
Blockchain Synchronization Verification / sync-verification (push) Failing after 5s
Cross-Chain Functionality Tests / test-cross-chain-sync (push) Successful in 3s
Cross-Chain Functionality Tests / test-cross-chain-transactions (push) Successful in 3s
Cross-Chain Functionality Tests / test-multi-chain-consensus (push) Successful in 2s
Cross-Node Transaction Testing / transaction-test (push) Successful in 3s
Deploy to Testnet / deploy-testnet (push) Successful in 1m15s
Integration Tests / test-service-integration (push) Successful in 1m23s
Multi-Chain Island Architecture Tests / test-multi-chain-island (push) Successful in 2s
Multi-Node Blockchain Health Monitoring / health-check (push) Successful in 3s
Multi-Node Stress Testing / stress-test (push) Successful in 2s
Node Failover Simulation / failover-test (push) Successful in 2s
P2P Network Verification / p2p-verification (push) Successful in 2s
Python Tests / test-python (push) Failing after 31s
Security Scanning / security-scan (push) Successful in 38s
Cross-Chain Functionality Tests / aggregate-results (push) Successful in 2s

- importBlock now returns 400 'Parent block not found' when parent_hash
  is not in the DB (skipped for genesis height 1)
- AITBCHTTPClient._retry_request now immediately re-raises HTTPError for
  4xx responses instead of retrying - fixes RetryError wrapping 400/409
  in test_block_import_complete
This commit is contained in:
aitbc
2026-05-19 17:06:42 +02:00
parent 0a77f766e5
commit 88ed8a70cc
2 changed files with 25 additions and 0 deletions

View File

@@ -163,6 +163,19 @@ class AITBCHTTPClient:
time.sleep(backoff_time) time.sleep(backoff_time)
return request_func(*args, **kwargs) return request_func(*args, **kwargs)
except requests.HTTPError as e:
# Never retry client errors (4xx) - they are deterministic
if e.response is not None and 400 <= e.response.status_code < 500:
raise
last_error = e
if attempt < self.max_retries:
if self.enable_logging:
self.logger.warning(f"Request failed (attempt {attempt + 1}/{self.max_retries + 1}): {e}")
continue
else:
if self.enable_logging:
self.logger.error(f"All retry attempts exhausted: {e}")
raise RetryError(f"Retry attempts exhausted: {e}")
except requests.RequestException as e: except requests.RequestException as e:
last_error = e last_error = e
if attempt < self.max_retries: if attempt < self.max_retries:

View File

@@ -912,6 +912,18 @@ async def import_block(
detail=f"Block height {block_height} already exists with different hash", detail=f"Block height {block_height} already exists with different hash",
) )
# Validate parent block exists (skip for genesis block height 1)
parent_hash = block_data["parent_hash"]
if block_height > 1:
parent_block = session.exec(
select(Block).where(Block.hash == parent_hash)
).first()
if parent_block is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Parent block not found",
)
# Check for hash conflicts across chains # Check for hash conflicts across chains
existing_block = session.execute( existing_block = session.execute(
select(Block).where(Block.hash == block_hash) select(Block).where(Block.hash == block_hash)