Fix Block model to match server: nest header with camelCase keys
The block endpoint returns block id / prev / timestamp nested under a
"header" object with camelCase keys (blockId, dcId, prevId, prevProof,
timestamp) and a proof of just {proof}. The previous flat snake_case
Block fields never matched the response and always deserialized empty.
Add a BlockHeader dataclass, nest it in Block, make proof.scheme
optional, and cover it with a unit test. Verified live against a dev
chain.
This commit is contained in:
@@ -45,6 +45,7 @@ from .contract import ContractClient
|
||||
from .errors import DragonchainAPIError, DragonchainError
|
||||
from .models import (
|
||||
Block,
|
||||
BlockHeader,
|
||||
BlockProof,
|
||||
GrpcConnectionInfo,
|
||||
ListResponse,
|
||||
@@ -121,6 +122,7 @@ __all__ = [
|
||||
"TransactionTypeClient",
|
||||
# models
|
||||
"Block",
|
||||
"BlockHeader",
|
||||
"BlockProof",
|
||||
"GrpcConnectionInfo",
|
||||
"ListResponse",
|
||||
|
||||
@@ -301,26 +301,42 @@ class SmartContract:
|
||||
|
||||
@dataclass
|
||||
class BlockProof:
|
||||
scheme: str = ""
|
||||
proof: str = ""
|
||||
scheme: str = "" # absent on trust-scheme chains; present on PoW
|
||||
nonce: int = 0
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d: Dict[str, Any]) -> "BlockProof":
|
||||
return cls(
|
||||
scheme=d.get("scheme", ""),
|
||||
proof=d.get("proof", ""),
|
||||
scheme=d.get("scheme", ""),
|
||||
nonce=d.get("nonce", 0),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class BlockHeader:
|
||||
block_id: str = ""
|
||||
dc_id: str = ""
|
||||
prev_id: str = ""
|
||||
prev_proof: str = ""
|
||||
timestamp: str = ""
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d: Dict[str, Any]) -> "BlockHeader":
|
||||
return cls(
|
||||
block_id=d.get("blockId", ""),
|
||||
dc_id=d.get("dcId", ""),
|
||||
prev_id=d.get("prevId", ""),
|
||||
prev_proof=d.get("prevProof", ""),
|
||||
timestamp=d.get("timestamp", ""),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Block:
|
||||
version: str = ""
|
||||
id: str = ""
|
||||
timestamp: str = ""
|
||||
prev_id: str = ""
|
||||
prev_proof: str = ""
|
||||
header: BlockHeader = field(default_factory=BlockHeader)
|
||||
transactions: List[str] = field(default_factory=list)
|
||||
proof: BlockProof = field(default_factory=BlockProof)
|
||||
|
||||
@@ -328,10 +344,7 @@ class Block:
|
||||
def from_dict(cls, d: Dict[str, Any]) -> "Block":
|
||||
return cls(
|
||||
version=d.get("version", ""),
|
||||
id=d.get("block_id", ""),
|
||||
timestamp=d.get("timestamp", ""),
|
||||
prev_id=d.get("prev_id", ""),
|
||||
prev_proof=d.get("prev_proof", ""),
|
||||
header=BlockHeader.from_dict(d.get("header") or {}),
|
||||
transactions=d.get("transactions") or [],
|
||||
proof=BlockProof.from_dict(d.get("proof") or {}),
|
||||
)
|
||||
|
||||
@@ -13,6 +13,7 @@ import json
|
||||
import pytest
|
||||
|
||||
from prime_sdk import (
|
||||
Block,
|
||||
DragonchainAPIError,
|
||||
DragonchainSDK,
|
||||
SmartContractCreateRequest,
|
||||
@@ -163,6 +164,33 @@ def test_transaction_from_dict_nested():
|
||||
assert txn.payload == "{}"
|
||||
|
||||
|
||||
def test_block_from_dict_nested_header():
|
||||
# Real server shape: id/prev/timestamp nested under "header" with camelCase
|
||||
# keys; proof carries only "proof" on a trust-scheme chain.
|
||||
raw = {
|
||||
"version": "1",
|
||||
"header": {
|
||||
"blockId": "69569983",
|
||||
"dcId": "chain-xyz",
|
||||
"prevId": "69186326",
|
||||
"prevProof": "MEUCIQ...",
|
||||
"timestamp": "1780088135",
|
||||
},
|
||||
"proof": {"proof": "MEQCIF..."},
|
||||
"transactions": ["{...}", "{...}", "{...}"],
|
||||
}
|
||||
blk = Block.from_dict(raw)
|
||||
assert blk.version == "1"
|
||||
assert blk.header.block_id == "69569983"
|
||||
assert blk.header.dc_id == "chain-xyz"
|
||||
assert blk.header.prev_id == "69186326"
|
||||
assert blk.header.prev_proof == "MEUCIQ..."
|
||||
assert blk.header.timestamp == "1780088135"
|
||||
assert blk.proof.proof == "MEQCIF..."
|
||||
assert blk.proof.scheme == "" # absent on trust-scheme chain
|
||||
assert len(blk.transactions) == 3
|
||||
|
||||
|
||||
def test_contract_create_request_omitempty():
|
||||
req = SmartContractCreateRequest(
|
||||
environment="python3.8",
|
||||
|
||||
Reference in New Issue
Block a user