dragonchain/lib/dto/l5_block_model.py
# Copyright 2020 Dragonchain, Inc.
# Licensed under the Apache License, Version 2.0 (the "Apache License")
# with the following modification; you may not use this file except in
# compliance with the Apache License and the following modification to it:
# Section 6. Trademarks. is deleted and replaced with:
# 6. Trademarks. This License does not grant permission to use the trade
# names, trademarks, service marks, or product names of the Licensor
# and its affiliates, except as required to comply with Section 4(c) of
# the License and to reproduce the content of the NOTICE file.
# You may obtain a copy of the Apache License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the Apache License with the above modification is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the Apache License for the specific
# language governing permissions and limitations under the Apache License.
import json
from typing import Dict, Any
import fastjsonschema
from dragonchain.lib import keys
from dragonchain.lib.dto import schema
from dragonchain.lib.dto import model
_validate_l5_block_at_rest = fastjsonschema.compile(schema.l5_block_at_rest_schema)
def new_from_at_rest(block: dict) -> "L5BlockModel":
"""
Used in querying from the DAO
Input: Block::L5::AtRest DTO
Returns: BlockModel object
"""
# Validate inputted schema
_validate_l5_block_at_rest(block)
if block.get("version") == "1":
return L5BlockModel(
dc_id=block["header"]["dc_id"],
current_ddss=block["header"].get("current_ddss"),
block_id=block["header"]["block_id"],
timestamp=block["header"].get("timestamp") or "-1",
prev_proof=block["header"]["prev_proof"],
scheme=block["proof"]["scheme"],
proof=block["proof"]["proof"],
transaction_hash=block["proof"]["transaction_hash"],
network=block["proof"]["network"],
block_last_sent_at=block["proof"]["block_last_sent_at"],
nonce=block["proof"].get("nonce"),
l4_blocks=block["l4-blocks"],
)
else:
raise NotImplementedError(f"Version {block.get('version')} is not supported")
class L5BlockModel(model.BlockModel):
"""
BlockModel class is an abstracted representation of a block object
"""
# Take in all possible data points for a given type of block, and validate
def __init__(
self,
dc_id=None,
current_ddss=None,
block_id=None,
timestamp=None,
prev_proof="",
scheme="",
proof="",
transaction_hash=None,
network=None,
nonce=None,
l4_blocks=None,
block_last_sent_at=None,
):
"""Model Constructor"""
if l4_blocks is None:
l4_blocks = []
if transaction_hash is None:
transaction_hash = []
self.dc_id = dc_id
self.current_ddss = current_ddss
self.block_id = block_id
if block_id:
self.prev_id = str(int(block_id) - 1)
self.timestamp = timestamp
self.prev_proof = prev_proof
self.transaction_hash = transaction_hash
self.scheme = scheme
self.proof = proof
self.nonce = nonce
self.network = network
self.l4_blocks = l4_blocks
self.block_last_sent_at = block_last_sent_at
def get_associated_l1_block_id(self) -> set:
"""Interface function for compatibility"""
# Scrape the L4 blocks array to find all entries in the L5 block for this L1
l4_blocks_for_l1 = set()
for x in self.l4_blocks:
l4_block_candidate = json.loads(x)
if l4_block_candidate["l1_dc_id"] == keys.get_public_id():
l4_blocks_for_l1.add(l4_block_candidate["l1_block_id"])
# else no-op
return l4_blocks_for_l1
def export_as_at_rest(self) -> dict:
"""Export the L5 block that is stored/brodcast/sent for receipt"""
proof = None
if self.scheme == "trust":
proof = {
"scheme": self.scheme,
"transaction_hash": self.transaction_hash,
"block_last_sent_at": self.block_last_sent_at,
"network": self.network,
"proof": self.proof,
}
else:
proof = {
"scheme": self.scheme,
"proof": self.proof,
"transaction_hash": self.transaction_hash,
"block_last_sent_at": self.block_last_sent_at,
"network": self.network,
"nonce": self.nonce,
}
return {
"version": "1",
"dcrn": schema.DCRN.Block_L5_At_Rest.value,
"header": {
"dc_id": self.dc_id,
"current_ddss": self.current_ddss,
"level": 5,
"block_id": self.block_id,
"timestamp": self.timestamp,
"prev_proof": self.prev_proof,
},
"l4-blocks": self.l4_blocks,
"proof": proof,
}
def export_as_search_index(self) -> Dict[str, Any]:
"""Export as block search index DTO"""
return {
"block_id": int(self.block_id),
"timestamp": int(self.timestamp),
"prev_id": int(self.prev_id) if self.prev_id else 0,
"dc_id": self.dc_id if self.dc_id else "",
}