add get_interchain: trace a transaction/block to validator blocks + interchain anchors
New transaction.get_interchain and block.get_interchain call the prime-node
/api/v1/{transaction,block}/{id}/interchain endpoints, returning an
InterchainTrace {block_id, validator_blocks, interchain_transactions}. Adds
VerificationBlock / InterchainTransaction / InterchainTrace dataclasses with
from_dict, exports them, and a from_dict test.
This commit is contained in:
@@ -48,6 +48,8 @@ from .models import (
|
|||||||
BlockHeader,
|
BlockHeader,
|
||||||
BlockProof,
|
BlockProof,
|
||||||
GrpcConnectionInfo,
|
GrpcConnectionInfo,
|
||||||
|
InterchainTrace,
|
||||||
|
InterchainTransaction,
|
||||||
ListResponse,
|
ListResponse,
|
||||||
ListTransactionsResponse,
|
ListTransactionsResponse,
|
||||||
SmartContract,
|
SmartContract,
|
||||||
@@ -67,6 +69,7 @@ from .models import (
|
|||||||
TransactionType,
|
TransactionType,
|
||||||
TransactionTypeCreateRequest,
|
TransactionTypeCreateRequest,
|
||||||
TransactionTypeCreateResponse,
|
TransactionTypeCreateResponse,
|
||||||
|
VerificationBlock,
|
||||||
)
|
)
|
||||||
from .system import SystemClient
|
from .system import SystemClient
|
||||||
from .transaction import TransactionClient
|
from .transaction import TransactionClient
|
||||||
@@ -125,6 +128,8 @@ __all__ = [
|
|||||||
"BlockHeader",
|
"BlockHeader",
|
||||||
"BlockProof",
|
"BlockProof",
|
||||||
"GrpcConnectionInfo",
|
"GrpcConnectionInfo",
|
||||||
|
"InterchainTrace",
|
||||||
|
"InterchainTransaction",
|
||||||
"ListResponse",
|
"ListResponse",
|
||||||
"ListTransactionsResponse",
|
"ListTransactionsResponse",
|
||||||
"SmartContract",
|
"SmartContract",
|
||||||
@@ -144,4 +149,5 @@ __all__ = [
|
|||||||
"TransactionType",
|
"TransactionType",
|
||||||
"TransactionTypeCreateRequest",
|
"TransactionTypeCreateRequest",
|
||||||
"TransactionTypeCreateResponse",
|
"TransactionTypeCreateResponse",
|
||||||
|
"VerificationBlock",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Block endpoints."""
|
"""Block endpoints."""
|
||||||
|
|
||||||
from .client import Client
|
from .client import Client
|
||||||
from .models import Block
|
from .models import Block, InterchainTrace
|
||||||
|
|
||||||
|
|
||||||
class BlockClient:
|
class BlockClient:
|
||||||
@@ -10,3 +10,11 @@ class BlockClient:
|
|||||||
|
|
||||||
def get(self, block_id: str) -> Block:
|
def get(self, block_id: str) -> Block:
|
||||||
return self._client.get(f"/api/v1/block/{block_id}", Block)
|
return self._client.get(f"/api/v1/block/{block_id}", Block)
|
||||||
|
|
||||||
|
def get_interchain(self, block_id: str) -> InterchainTrace:
|
||||||
|
"""Trace a block to the validator (verification) blocks that validated it
|
||||||
|
and the public-chain interchain anchors those validator blocks were
|
||||||
|
bundled into."""
|
||||||
|
return self._client.get(
|
||||||
|
f"/api/v1/block/{block_id}/interchain", InterchainTrace
|
||||||
|
)
|
||||||
|
|||||||
@@ -350,6 +350,92 @@ class Block:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Interchain trace
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VerificationBlock:
|
||||||
|
"""A validator's verification of a prime block."""
|
||||||
|
|
||||||
|
version: str = ""
|
||||||
|
prime_chain_id: str = ""
|
||||||
|
prime_block_id: str = ""
|
||||||
|
timestamp: str = ""
|
||||||
|
verifier_public_key: str = ""
|
||||||
|
verifier_signature: str = ""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, d: Dict[str, Any]) -> "VerificationBlock":
|
||||||
|
return cls(
|
||||||
|
version=d.get("version", ""),
|
||||||
|
prime_chain_id=d.get("primeChainId", ""),
|
||||||
|
prime_block_id=d.get("primeBlockId", ""),
|
||||||
|
timestamp=d.get("timestamp", ""),
|
||||||
|
verifier_public_key=d.get("verifierPublicKey", ""),
|
||||||
|
verifier_signature=d.get("verifierSignature", ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class InterchainTransaction:
|
||||||
|
"""An anchor broadcast to a public blockchain (e.g. ETH/BTC) bundling one or
|
||||||
|
more validator blocks. ``validator_blocks`` holds the covered prime block ids;
|
||||||
|
``covered_prime_chain_ids`` the prime chains they belong to."""
|
||||||
|
|
||||||
|
id: int = 0
|
||||||
|
version: str = ""
|
||||||
|
timestamp: str = ""
|
||||||
|
chain_id: str = ""
|
||||||
|
trans_hash: str = ""
|
||||||
|
block_id: str = ""
|
||||||
|
validator_blocks: List[str] = field(default_factory=list)
|
||||||
|
validator_blockhash: str = ""
|
||||||
|
signature: str = ""
|
||||||
|
covered_prime_chain_ids: List[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, d: Dict[str, Any]) -> "InterchainTransaction":
|
||||||
|
return cls(
|
||||||
|
id=d.get("id", 0),
|
||||||
|
version=d.get("version", ""),
|
||||||
|
timestamp=d.get("timestamp", ""),
|
||||||
|
chain_id=d.get("chainId", ""),
|
||||||
|
trans_hash=d.get("transHash", ""),
|
||||||
|
block_id=d.get("blockId", ""),
|
||||||
|
validator_blocks=d.get("validatorBlocks") or [],
|
||||||
|
validator_blockhash=d.get("validatorBlockhash", ""),
|
||||||
|
signature=d.get("signature", ""),
|
||||||
|
covered_prime_chain_ids=d.get("coveredPrimeChainIds") or [],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class InterchainTrace:
|
||||||
|
"""Links a prime block to the validator (verification) blocks that validated
|
||||||
|
it and the public-chain interchain anchors those validator blocks were
|
||||||
|
bundled into. Returned by ``transaction.get_interchain`` and
|
||||||
|
``block.get_interchain``."""
|
||||||
|
|
||||||
|
block_id: str = ""
|
||||||
|
validator_blocks: List[VerificationBlock] = field(default_factory=list)
|
||||||
|
interchain_transactions: List[InterchainTransaction] = field(default_factory=list)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, d: Dict[str, Any]) -> "InterchainTrace":
|
||||||
|
return cls(
|
||||||
|
block_id=d.get("blockId", ""),
|
||||||
|
validator_blocks=[
|
||||||
|
VerificationBlock.from_dict(v) for v in (d.get("validatorBlocks") or [])
|
||||||
|
],
|
||||||
|
interchain_transactions=[
|
||||||
|
InterchainTransaction.from_dict(v)
|
||||||
|
for v in (d.get("interchainTransactions") or [])
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# System / generic
|
# System / generic
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from .client import CONTENT_TYPE_JSON, Client
|
from .client import CONTENT_TYPE_JSON, Client
|
||||||
from .models import (
|
from .models import (
|
||||||
|
InterchainTrace,
|
||||||
ListTransactionsResponse,
|
ListTransactionsResponse,
|
||||||
Transaction,
|
Transaction,
|
||||||
TransactionBulkRequest,
|
TransactionBulkRequest,
|
||||||
@@ -39,5 +40,14 @@ class TransactionClient:
|
|||||||
def get(self, transaction_id: str) -> Transaction:
|
def get(self, transaction_id: str) -> Transaction:
|
||||||
return self._client.get(f"/api/v1/transaction/{transaction_id}", Transaction)
|
return self._client.get(f"/api/v1/transaction/{transaction_id}", Transaction)
|
||||||
|
|
||||||
|
def get_interchain(self, transaction_id: str) -> InterchainTrace:
|
||||||
|
"""Trace a transaction to the validator (verification) blocks that
|
||||||
|
validated its prime block and the public-chain interchain anchors those
|
||||||
|
validator blocks were bundled into. If the transaction is still pending
|
||||||
|
(not yet in a block) the trace's lists are empty."""
|
||||||
|
return self._client.get(
|
||||||
|
f"/api/v1/transaction/{transaction_id}/interchain", InterchainTrace
|
||||||
|
)
|
||||||
|
|
||||||
def list(self) -> ListTransactionsResponse:
|
def list(self) -> ListTransactionsResponse:
|
||||||
return self._client.get("/api/v1/transaction/", ListTransactionsResponse)
|
return self._client.get("/api/v1/transaction/", ListTransactionsResponse)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from prime_sdk import (
|
|||||||
Block,
|
Block,
|
||||||
DragonchainAPIError,
|
DragonchainAPIError,
|
||||||
DragonchainSDK,
|
DragonchainSDK,
|
||||||
|
InterchainTrace,
|
||||||
SmartContractCreateRequest,
|
SmartContractCreateRequest,
|
||||||
Transaction,
|
Transaction,
|
||||||
TransactionCreateRequest,
|
TransactionCreateRequest,
|
||||||
@@ -191,6 +192,42 @@ def test_block_from_dict_nested_header():
|
|||||||
assert len(blk.transactions) == 3
|
assert len(blk.transactions) == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_interchain_trace_from_dict_nested():
|
||||||
|
# Server shape: validatorBlocks + interchainTransactions arrays, camelCase.
|
||||||
|
raw = {
|
||||||
|
"blockId": "69636602",
|
||||||
|
"validatorBlocks": [
|
||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"primeChainId": "zDYr",
|
||||||
|
"primeBlockId": "69636602",
|
||||||
|
"verifierPublicKey": "02c4...",
|
||||||
|
"verifierSignature": "MEUC...",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interchainTransactions": [
|
||||||
|
{
|
||||||
|
"id": 19,
|
||||||
|
"chainId": "1",
|
||||||
|
"transHash": "0xd46e",
|
||||||
|
"validatorBlocks": ["69636602"],
|
||||||
|
"coveredPrimeChainIds": ["zDYr"],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
trace = InterchainTrace.from_dict(raw)
|
||||||
|
assert trace.block_id == "69636602"
|
||||||
|
assert len(trace.validator_blocks) == 1
|
||||||
|
assert trace.validator_blocks[0].prime_block_id == "69636602"
|
||||||
|
assert trace.validator_blocks[0].verifier_public_key == "02c4..."
|
||||||
|
assert len(trace.interchain_transactions) == 1
|
||||||
|
assert trace.interchain_transactions[0].id == 19
|
||||||
|
assert trace.interchain_transactions[0].trans_hash == "0xd46e"
|
||||||
|
assert trace.interchain_transactions[0].chain_id == "1"
|
||||||
|
assert trace.interchain_transactions[0].validator_blocks == ["69636602"]
|
||||||
|
assert trace.interchain_transactions[0].covered_prime_chain_ids == ["zDYr"]
|
||||||
|
|
||||||
|
|
||||||
def test_contract_create_request_omitempty():
|
def test_contract_create_request_omitempty():
|
||||||
req = SmartContractCreateRequest(
|
req = SmartContractCreateRequest(
|
||||||
environment="python3.8",
|
environment="python3.8",
|
||||||
|
|||||||
Reference in New Issue
Block a user