Пример #1
0
class TestBlockManager(unittest.TestCase):

    def setUp(self):
        self.block_manager = BlockManager()

    def test_block_manager(self):
        block_a = _build_block(1, "A", NULL_BLOCK_IDENTIFIER)
        block_b = _build_block(2, "B", "A")
        block_c = _build_block(3, "C", "B")

        self.block_manager.put([block_a, block_b, block_c])

        block_e = _build_block(5, "E", "D")

        with self.assertRaises(MissingPredecessor):
            self.block_manager.put([block_e])

        block_d = _build_block(4, "D", "C")

        self.block_manager.put([block_d, block_e])

        block_c2 = _build_block(3, "C2", "B")

        block_d2 = _build_block(4, "D2", "C2")

        block_e2 = _build_block(5, "E2", "D2")

        with self.assertRaises(MissingPredecessorInBranch):
            self.block_manager.put([block_c2, block_e2, block_d2])

        block_id = "D"
        for block in self.block_manager.branch("D"):
            self.assertEqual(block.header_signature, block_id)
            header = block_pb2.BlockHeader()
            header.ParseFromString(block.header)
            block_id = header.previous_block_id

        self.block_manager.put([block_c2, block_d2, block_e2])

        block_id = "D"
        for block in self.block_manager.branch_diff("D", "E2"):
            self.assertEqual(block.header_signature, block_id)
            header = block_pb2.BlockHeader()
            header.ParseFromString(block.header)
            block_id = header.previous_block_id

        for block in self.block_manager.get("C"):
            self.assertEqual(block.header_signature, "C")
Пример #2
0
class BlockTreeManager:
    def __str__(self):
        return str(self.block_cache)

    def __repr__(self):
        return repr(self.block_cache)

    def __init__(self, with_genesis=True):
        self.block_sender = MockBlockSender()
        self.batch_sender = MockBatchSender()
        self.dir = tempfile.mkdtemp()
        self.block_db = NativeLmdbDatabase(
            os.path.join(self.dir, 'block.lmdb'),
            BlockStore.create_index_configuration())
        self.block_store = BlockStore(self.block_db)
        self.block_cache = BlockCache(self.block_store)
        self.state_db = NativeLmdbDatabase(
            os.path.join(self.dir, "merkle.lmdb"),
            MerkleDatabase.create_index_configuration())

        self.state_view_factory = NativeStateViewFactory(self.state_db)

        self.block_manager = BlockManager()
        self.block_manager.add_commit_store(self.block_store)

        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        self.signer = crypto_factory.new_signer(private_key)

        identity_private_key = context.new_random_private_key()
        self.identity_signer = crypto_factory.new_signer(identity_private_key)
        chain_head = None
        if with_genesis:
            self.genesis_block = self.generate_genesis_block()
            chain_head = self.genesis_block
            self.block_manager.put([chain_head.block])
            self.block_manager.persist(chain_head.block.header_signature,
                                       "commit_store")

        self.block_publisher = BlockPublisher(
            block_store=self.block_store,
            block_manager=self.block_manager,
            transaction_executor=MockTransactionExecutor(),
            state_view_factory=self.state_view_factory,
            block_sender=self.block_sender,
            batch_sender=self.block_sender,
            identity_signer=self.identity_signer,
            data_dir=None,
            config_dir=None,
            permission_verifier=MockPermissionVerifier(),
            batch_observers=[])

    @property
    def chain_head(self):
        return self.block_store.chain_head

    def generate_block(self,
                       previous_block=None,
                       add_to_store=False,
                       add_to_cache=False,
                       batch_count=1,
                       batches=None,
                       status=BlockStatus.Unknown,
                       invalid_consensus=False,
                       invalid_batch=False,
                       invalid_signature=False,
                       weight=0):

        previous = self._get_block(previous_block)
        if previous is None:
            previous = self.chain_head

        header = BlockHeader(
            previous_block_id=previous.identifier,
            signer_public_key=self.identity_signer.get_public_key().as_hex(),
            block_num=previous.block_num + 1)

        block_builder = BlockBuilder(header)
        if batches:
            block_builder.add_batches(batches)

        if batch_count != 0:
            block_builder.add_batches(
                [self._generate_batch() for _ in range(batch_count)])

        if invalid_batch:
            block_builder.add_batches(
                [self._generate_batch_from_payload('BAD')])

        block_builder.set_state_hash('0' * 70)

        consensus = mock_consensus.BlockPublisher()
        consensus.finalize_block(block_builder.block_header, weight=weight)

        if invalid_consensus:
            block_builder.block_header.consensus = b'BAD'

        header_bytes = block_builder.block_header.SerializeToString()
        if invalid_signature:
            block_builder.set_signature('BAD')
        else:
            signature = self.identity_signer.sign(header_bytes)
            block_builder.set_signature(signature)

        block_wrapper = BlockWrapper(block_builder.build_block())

        if batches:
            block_wrapper.block.batches.extend(batches)

        if batch_count:
            block_wrapper.block.batches.extend(
                [self.generate_batch() for _ in range(batch_count)])

        if invalid_signature:
            block_wrapper.block.header_signature = "BAD"

        if invalid_consensus:
            block_wrapper.header.consensus = b'BAD'

        block_wrapper.status = status

        self.block_manager.put([block_wrapper.block])
        if add_to_cache:
            self.block_cache[block_wrapper.identifier] = block_wrapper

        if add_to_store:
            self.block_store.put_blocks([block_wrapper.block])

        LOGGER.debug("Generated %s", dumps_block(block_wrapper))
        return block_wrapper

    def generate_chain(self,
                       root_block,
                       blocks,
                       params=None,
                       exclude_head=True):
        """
        Generate a new chain based on the root block and place it in the
        block cache.
        """
        if params is None:
            params = {}

        if root_block is None:
            previous = self.generate_genesis_block()
            self.block_store.put_blocks([previous.block])
        else:
            previous = self._get_block(root_block)

        try:
            block_defs = [self._block_def(**params) for _ in range(blocks)]
            if exclude_head:
                block_defs[-1] = self._block_def()
        except TypeError:
            block_defs = blocks

        out = []
        for block_def in block_defs:
            new_block = self.generate_block(previous_block=previous,
                                            **block_def)
            out.append(new_block)
            previous = new_block
        return out

    def create_block(self,
                     payload='payload',
                     batch_count=1,
                     previous_block_id=NULL_BLOCK_IDENTIFIER,
                     block_num=0):
        header = BlockHeader(
            previous_block_id=previous_block_id,
            signer_public_key=self.identity_signer.get_public_key().as_hex(),
            block_num=block_num)

        block_builder = BlockBuilder(header)
        block_builder.add_batches([
            self._generate_batch_from_payload(payload)
            for _ in range(batch_count)
        ])
        block_builder.set_state_hash('0' * 70)

        header_bytes = block_builder.block_header.SerializeToString()
        signature = self.identity_signer.sign(header_bytes)
        block_builder.set_signature(signature)

        block_wrapper = BlockWrapper(block_builder.build_block())
        LOGGER.debug("Generated %s", dumps_block(block_wrapper))
        return block_wrapper

    def generate_genesis_block(self):
        return self.create_block(payload='Genesis',
                                 previous_block_id=NULL_BLOCK_IDENTIFIER,
                                 block_num=0)

    def _block_def(self,
                   add_to_store=False,
                   add_to_cache=False,
                   batch_count=1,
                   status=BlockStatus.Unknown,
                   invalid_consensus=False,
                   invalid_batch=False,
                   invalid_signature=False,
                   weight=0):
        return {
            "add_to_cache": add_to_cache,
            "add_to_store": add_to_store,
            "batch_count": batch_count,
            "status": status,
            "invalid_consensus": invalid_consensus,
            "invalid_batch": invalid_batch,
            "invalid_signature": invalid_signature,
            "weight": weight
        }

    def _get_block_id(self, block):
        if block is None:
            return None
        elif isinstance(block, (Block, BlockWrapper)):
            return block.header_signature
        else:
            return str(block)

    def _get_block(self, block):
        if block is None:
            return None
        elif isinstance(block, Block):
            return BlockWrapper(block)
        elif isinstance(block, BlockWrapper):
            return block
        elif isinstance(block, str):
            return self.block_cache[block]
        else:  # WTF try something crazy
            return self.block_cache[str(block)]

    def generate_batch(self, txn_count=2, missing_deps=False, txns=None):

        batch = self._generate_batch(txn_count, missing_deps, txns)

        LOGGER.debug("Generated Batch:\n%s", dumps_batch(batch))

        return batch

    def _generate_batch(self, txn_count=2, missing_deps=False, txns=None):
        if txns is None:
            txns = []

        if txn_count != 0:
            txns += [
                self.generate_transaction('txn_' + str(i))
                for i in range(txn_count)
            ]

        if missing_deps:
            target_txn = txns[-1]
            txn_missing_deps = self.generate_transaction(
                payload='this one has a missing dependency',
                deps=[target_txn.header_signature])
            # replace the targeted txn with the missing deps txn
            txns[-1] = txn_missing_deps

        batch_header = BatchHeader(
            signer_public_key=self.signer.get_public_key().as_hex(),
            transaction_ids=[txn.header_signature
                             for txn in txns]).SerializeToString()

        batch = Batch(header=batch_header,
                      header_signature=self.signer.sign(batch_header),
                      transactions=txns)

        return batch

    def generate_transaction(self, payload='txn', deps=None):
        payload_encoded = payload.encode('utf-8')
        hasher = hashlib.sha512()
        hasher.update(payload_encoded)

        txn_header = TransactionHeader(
            dependencies=([] if deps is None else deps),
            batcher_public_key=self.signer.get_public_key().as_hex(),
            family_name='test',
            family_version='1',
            nonce=_generate_id(16),
            payload_sha512=hasher.hexdigest().encode(),
            signer_public_key=self.signer.get_public_key().as_hex(
            )).SerializeToString()

        txn = Transaction(header=txn_header,
                          header_signature=self.signer.sign(txn_header),
                          payload=payload_encoded)

        return txn

    def _generate_batch_from_payload(self, payload):
        txn = self.generate_transaction(payload)

        batch_header = BatchHeader(
            signer_public_key=self.signer.get_public_key().as_hex(),
            transaction_ids=[txn.header_signature]).SerializeToString()

        batch = Batch(header=batch_header,
                      header_signature=self.signer.sign(batch_header),
                      transactions=[txn])
        return batch
Пример #3
0
class BlockTreeManager:
    def __str__(self):
        return str(self.block_cache)

    def __repr__(self):
        return repr(self.block_cache)

    def __init__(self, with_genesis=True):
        self.block_sender = MockBlockSender()
        self.batch_sender = MockBatchSender()
        self.dir = tempfile.mkdtemp()
        self.block_db = NativeLmdbDatabase(
            os.path.join(self.dir, 'block.lmdb'),
            BlockStore.create_index_configuration())
        self.block_store = BlockStore(self.block_db)
        self.block_cache = BlockCache(self.block_store)
        self.state_db = NativeLmdbDatabase(
            os.path.join(self.dir, "merkle.lmdb"),
            MerkleDatabase.create_index_configuration())

        self.state_view_factory = NativeStateViewFactory(self.state_db)

        self.block_manager = BlockManager()
        self.block_manager.add_commit_store(self.block_store)

        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        self.signer = crypto_factory.new_signer(private_key)

        identity_private_key = context.new_random_private_key()
        self.identity_signer = crypto_factory.new_signer(identity_private_key)
        chain_head = None
        if with_genesis:
            self.genesis_block = self.generate_genesis_block()
            chain_head = self.genesis_block
            self.block_manager.put([chain_head.block])
            self.block_manager.persist(
                chain_head.block.header_signature,
                "commit_store")

        self.block_publisher = BlockPublisher(
            block_manager=self.block_manager,
            transaction_executor=MockTransactionExecutor(),
            transaction_committed=self.block_store.has_transaction,
            batch_committed=self.block_store.has_batch,
            state_view_factory=self.state_view_factory,
            block_sender=self.block_sender,
            batch_sender=self.block_sender,
            chain_head=chain_head.block,
            identity_signer=self.identity_signer,
            data_dir=None,
            config_dir=None,
            permission_verifier=MockPermissionVerifier(),
            batch_observers=[])

    @property
    def chain_head(self):
        return self.block_store.chain_head

    def generate_block(self, previous_block=None,
                       add_to_store=False,
                       add_to_cache=False,
                       batch_count=1,
                       batches=None,
                       status=BlockStatus.Unknown,
                       invalid_consensus=False,
                       invalid_batch=False,
                       invalid_signature=False,
                       weight=0):

        previous = self._get_block(previous_block)
        if previous is None:
            previous = self.chain_head

        header = BlockHeader(
            previous_block_id=previous.identifier,
            signer_public_key=self.identity_signer.get_public_key().as_hex(),
            block_num=previous.block_num + 1)

        block_builder = BlockBuilder(header)
        if batches:
            block_builder.add_batches(batches)

        if batch_count != 0:
            block_builder.add_batches(
                [self._generate_batch()
                    for _ in range(batch_count)])

        if invalid_batch:
            block_builder.add_batches(
                [self._generate_batch_from_payload('BAD')])

        block_builder.set_state_hash('0' * 70)

        consensus = mock_consensus.BlockPublisher()
        consensus.finalize_block(block_builder.block_header, weight=weight)

        if invalid_consensus:
            block_builder.block_header.consensus = b'BAD'

        header_bytes = block_builder.block_header.SerializeToString()
        if invalid_signature:
            block_builder.set_signature('BAD')
        else:
            signature = self.identity_signer.sign(header_bytes)
            block_builder.set_signature(signature)

        block_wrapper = BlockWrapper(block_builder.build_block())

        if batches:
            block_wrapper.block.batches.extend(batches)

        if batch_count:
            block_wrapper.block.batches.extend(
                [self.generate_batch() for _ in range(batch_count)])

        if invalid_signature:
            block_wrapper.block.header_signature = "BAD"

        if invalid_consensus:
            block_wrapper.header.consensus = b'BAD'

        block_wrapper.status = status

        self.block_manager.put([block_wrapper.block])
        if add_to_cache:
            self.block_cache[block_wrapper.identifier] = block_wrapper

        if add_to_store:
            self.block_store.put_blocks([block_wrapper.block])

        LOGGER.debug("Generated %s", dumps_block(block_wrapper))
        return block_wrapper

    def generate_chain(self, root_block, blocks, params=None,
                       exclude_head=True):
        """
        Generate a new chain based on the root block and place it in the
        block cache.
        """
        if params is None:
            params = {}

        if root_block is None:
            previous = self.generate_genesis_block()
            self.block_store.put_blocks([previous.block])
        else:
            previous = self._get_block(root_block)

        try:
            block_defs = [self._block_def(**params) for _ in range(blocks)]
            if exclude_head:
                block_defs[-1] = self._block_def()
        except TypeError:
            block_defs = blocks

        out = []
        for block_def in block_defs:
            new_block = self.generate_block(
                previous_block=previous, **block_def)
            out.append(new_block)
            previous = new_block
        return out

    def create_block(self, payload='payload', batch_count=1,
                     previous_block_id=NULL_BLOCK_IDENTIFIER, block_num=0):
        header = BlockHeader(
            previous_block_id=previous_block_id,
            signer_public_key=self.identity_signer.get_public_key().as_hex(),
            block_num=block_num)

        block_builder = BlockBuilder(header)
        block_builder.add_batches(
            [self._generate_batch_from_payload(payload)
                for _ in range(batch_count)])
        block_builder.set_state_hash('0' * 70)

        header_bytes = block_builder.block_header.SerializeToString()
        signature = self.identity_signer.sign(header_bytes)
        block_builder.set_signature(signature)

        block_wrapper = BlockWrapper(block_builder.build_block())
        LOGGER.debug("Generated %s", dumps_block(block_wrapper))
        return block_wrapper

    def generate_genesis_block(self):
        return self.create_block(
            payload='Genesis',
            previous_block_id=NULL_BLOCK_IDENTIFIER,
            block_num=0)

    def _block_def(self,
                   add_to_store=False,
                   add_to_cache=False,
                   batch_count=1,
                   status=BlockStatus.Unknown,
                   invalid_consensus=False,
                   invalid_batch=False,
                   invalid_signature=False,
                   weight=0):
        return {
            "add_to_cache": add_to_cache,
            "add_to_store": add_to_store,
            "batch_count": batch_count,
            "status": status,
            "invalid_consensus": invalid_consensus,
            "invalid_batch": invalid_batch,
            "invalid_signature": invalid_signature,
            "weight": weight
        }

    def _get_block_id(self, block):
        if block is None:
            return None
        elif isinstance(block, (Block, BlockWrapper)):
            return block.header_signature
        else:
            return str(block)

    def _get_block(self, block):
        if block is None:
            return None
        elif isinstance(block, Block):
            return BlockWrapper(block)
        elif isinstance(block, BlockWrapper):
            return block
        elif isinstance(block, str):
            return self.block_cache[block]
        else:  # WTF try something crazy
            return self.block_cache[str(block)]

    def generate_batch(self, txn_count=2, missing_deps=False,
                       txns=None):

        batch = self._generate_batch(txn_count, missing_deps, txns)

        LOGGER.debug("Generated Batch:\n%s", dumps_batch(batch))

        return batch

    def _generate_batch(self, txn_count=2, missing_deps=False,
                        txns=None):
        if txns is None:
            txns = []

        if txn_count != 0:
            txns += [
                self.generate_transaction('txn_' + str(i))
                for i in range(txn_count)
            ]

        if missing_deps:
            target_txn = txns[-1]
            txn_missing_deps = self.generate_transaction(
                payload='this one has a missing dependency',
                deps=[target_txn.header_signature])
            # replace the targeted txn with the missing deps txn
            txns[-1] = txn_missing_deps

        batch_header = BatchHeader(
            signer_public_key=self.signer.get_public_key().as_hex(),
            transaction_ids=[txn.header_signature for txn in txns]
        ).SerializeToString()

        batch = Batch(
            header=batch_header,
            header_signature=self.signer.sign(batch_header),
            transactions=txns)

        return batch

    def generate_transaction(self, payload='txn', deps=None):
        payload_encoded = payload.encode('utf-8')
        hasher = hashlib.sha512()
        hasher.update(payload_encoded)

        txn_header = TransactionHeader(
            dependencies=([] if deps is None else deps),
            batcher_public_key=self.signer.get_public_key().as_hex(),
            family_name='test',
            family_version='1',
            nonce=_generate_id(16),
            payload_sha512=hasher.hexdigest().encode(),
            signer_public_key=self.signer.get_public_key().as_hex()
        ).SerializeToString()

        txn = Transaction(
            header=txn_header,
            header_signature=self.signer.sign(txn_header),
            payload=payload_encoded)

        return txn

    def _generate_batch_from_payload(self, payload):
        txn = self.generate_transaction(payload)

        batch_header = BatchHeader(
            signer_public_key=self.signer.get_public_key().as_hex(),
            transaction_ids=[txn.header_signature]
        ).SerializeToString()

        batch = Batch(
            header=batch_header,
            header_signature=self.signer.sign(batch_header),
            transactions=[txn])
        return batch