def __init__( self, transaction: bytes = None, previous: Links = None, key: LibNaCLSK = None, links: Links = None, com_prefix: bytes = b"", com_id: Any = None, block_type: bytes = b"test", ): crypto = default_eccrypto if not links: links = GENESIS_LINK com_seq_num = 1 else: com_seq_num = max(links)[0] + 1 if not previous: previous = GENESIS_LINK pers_seq_num = max(previous)[0] + 1 if not com_id: com_id = crypto.generate_key(u"curve25519").pub().key_to_bin() if key: self.key = key else: self.key = crypto.generate_key(u"curve25519") if not transaction: transaction = encode_raw({"id": 42}) BamiBlock.__init__( self, ( block_type, transaction, self.key.pub().key_to_bin(), pers_seq_num, encode_links(previous), encode_links(links), com_prefix, com_id, com_seq_num, EMPTY_SIG, 0, 0, ), ) self.sign(self.key)
def __init__(self, data: List = None, serializer=default_serializer) -> None: """ Create a new PlexusBlock or load from an existing database entry. :param data: Optional data to initialize this block with. :type data: Block.Data or list :param serializer: An optional custom serializer to use for this block. :type serializer: Serializer """ super(BamiBlock, self).__init__() self.serializer = serializer if data is None: # data self.type = b"unknown" self.transaction = b"" # block identity self.public_key = EMPTY_PK self.sequence_number = GENESIS_SEQ # previous hash in the personal chain self.previous = GENESIS_LINK self._previous = encode_links(self.previous) # Linked blocks => links to the block in other chains self.links = GENESIS_LINK self._links = encode_links(self.links) # Metadata for community identifiers self.com_prefix = b"" self.com_id = EMPTY_PK self.com_seq_num: int = UNKNOWN_SEQ # Creation timestamp self.timestamp = int(time.time() * 1000) # Signature for the block self.signature = EMPTY_SIG # debug stuff self.insert_time = None else: self.transaction = data[1] if isinstance(data[1], bytes) else bytes(data[1]) self._previous = (BytesLinks(data[4]) if isinstance( data[4], bytes) else bytes(data[4])) self._links = (BytesLinks(data[5]) if isinstance(data[5], bytes) else bytes(data[5])) self.previous = decode_links(self._previous) self.links = decode_links(self._links) self.type, self.public_key, self.sequence_number = data[0], data[ 2], data[3] self.com_prefix, self.com_id, self.com_seq_num = ( data[6], data[7], int(data[8]), ) self.signature, self.timestamp, self.insert_time = ( data[9], data[10], data[11], ) self.type = (self.type if isinstance(self.type, bytes) else str( self.type).encode("utf-8")) self.public_key = (self.public_key if isinstance( self.public_key, bytes) else bytes(self.public_key)) self.signature = (self.signature if isinstance( self.signature, bytes) else bytes(self.signature)) self.hash = self.calculate_hash() self.crypto = default_eccrypto self._logger = logging.getLogger(self.__class__.__name__)
def create( cls, block_type: bytes, transaction: bytes, database: BaseDB, public_key: bytes, com_prefix: bytes = b"", com_id: bytes = None, com_links: Links = None, pers_links: Links = None, use_consistent_links: bool = True, ): """ Create PlexusBlock wrt local database knowledge. Args: block_type: type of the block in bytes transaction: transaction blob bytes database: local database with chains public_key: public key of the block creator com_prefix: prefix for the chain identification [optional] com_id: id of the community which block is part of [optional] com_links: Explicitly link with these blocks [optional] pers_links: Create a block at a certain [optional] use_consistent_links: Build on top of blocks that are known. By default: True Returns: PlexusBlock """ if public_key == com_id: full_pers_chain_id = com_prefix + public_key else: full_pers_chain_id = public_key personal_chain = database.get_chain(full_pers_chain_id) # Decide to link blocks in the personal chain: if not personal_chain: # There are no blocks in the personal chain yet last_link = Links((GENESIS_DOT, )) else: last_link = (personal_chain.consistent_terminal if use_consistent_links else personal_chain.terminal) # Fork personal chain at the if pers_links: # There is an explicit link for the previous link last_link = pers_links per_seq_num = max(last_link)[0] + 1 # TODO: Add link filtering and choose links ret = cls() ret.type = block_type ret.transaction = transaction ret.sequence_number = per_seq_num ret.previous = last_link # --- Community related logic --- if com_id: ret.com_id = com_id # There is community specified => will base block on the latest known information + filters if com_links: last_com_links = com_links com_seq_num = max(last_com_links)[0] else: com_chain = database.get_chain(com_prefix + com_id) if not com_chain: last_com_links = Links((GENESIS_DOT, )) else: last_com_links = (com_chain.consistent_terminal if use_consistent_links else com_chain.terminal) # TODO: add link filtering here com_seq_num = max(last_com_links)[0] + 1 ret.links = last_com_links ret.com_seq_num = com_seq_num ret.com_id = com_id ret.com_prefix = com_prefix ret._links = encode_links(ret.links) ret._previous = encode_links(ret.previous) ret.public_key = public_key ret.signature = EMPTY_SIG ret.hash = ret.calculate_hash() return ret
def test_encode_decode_links(keys_fixture): links = Links(((1, shorten(keys_fixture)), )) raw_bytes = encode_links(links) assert decode_links(raw_bytes) == links