def test_publish(self, args=sys.argv[1:]): gossip = GossipMock() LOGGER.info(self.blocks) publisher = BlockPublisher( consensus=TestModePublisher(), transaction_executor=TransactionExecutorMock(), send_message=gossip.send_message, squash_handler=None) LOGGER.info("1") # initial load of existing state publisher.on_chain_updated(self.blocks.chain_head.block, [], []) LOGGER.info("2") # repeat as necessary batch = Batch() publisher.on_batch_received(batch) LOGGER.info("3") # current dev_mode consensus always claims blocks when asked. # this will be called on a polling every so often or possibly triggered # by events in the consensus it's self ... TBD publisher.on_check_publish_block() LOGGER.info("4") LOGGER.info(self.blocks) # repeat as necessary batch = Batch() publisher.on_batch_received(batch) publisher.on_check_publish_block() LOGGER.info(self.blocks)
class BlockTreeManager(object): 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.block_store = BlockStore(DictDatabase()) self.block_cache = BlockCache(self.block_store) self.state_db = {} # add the mock reference to the consensus consensus_setting_addr = ConfigView.setting_address( 'sawtooth.consensus.algorithm') self.state_db[consensus_setting_addr] = _setting_entry( 'sawtooth.consensus.algorithm', 'test_journal.mock_consensus') self.state_view_factory = MockStateViewFactory(self.state_db) self.signing_key = signing.generate_privkey() self.public_key = signing.generate_pubkey(self.signing_key) self.identity_signing_key = signing.generate_privkey() chain_head = None if with_genesis: self.genesis_block = self.generate_genesis_block() self.set_chain_head(self.genesis_block) chain_head = self.genesis_block self.block_publisher = BlockPublisher( transaction_executor=MockTransactionExecutor(), block_cache=self.block_cache, state_view_factory=self.state_view_factory, block_sender=self.block_sender, batch_sender=self.block_sender, squash_handler=None, chain_head=chain_head, identity_signing_key=self.identity_signing_key, data_dir=None, config_dir=None) @property def chain_head(self): return self.block_store.chain_head def set_chain_head(self, block): self.block_store.update_chain([block], []) def generate_block(self, previous_block=None, add_to_store=False, add_to_cache=False, batch_count=0, 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 self.block_publisher.on_chain_updated(previous) while self.block_sender.new_block is None: self.block_publisher.on_batch_received( self._generate_batch_from_payload('')) self.block_publisher.on_check_publish_block(True) block_from_sender = self.block_sender.new_block self.block_sender.new_block = None block_wrapper = BlockWrapper(block_from_sender) if invalid_signature: block_wrapper.block.header_signature = "BAD" if invalid_consensus: block_wrapper.header.consensus = b'BAD' if invalid_batch: block_wrapper.block.batches.extend( [self._generate_batch_from_payload('BAD')]) block_wrapper.weight = weight block_wrapper.status = status if add_to_cache: self.block_cache[block_wrapper.identifier] = block_wrapper if add_to_store: self.block_store[block_wrapper.identifier] = block_wrapper return block_wrapper def generate_chain(self, root_block, blocks, params=None): """ 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[previous.identifier] = previous else: previous = self._get_block(root_block) try: block_defs = [self._block_def(**params) for _ in range(blocks)] 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 _generate_block(self, payload, previous_block_id, block_num): header = BlockHeader(previous_block_id=previous_block_id, signer_pubkey=self.public_key, block_num=block_num) block_builder = BlockBuilder(header) block_builder.add_batches([self._generate_batch_from_payload(payload)]) header_bytes = block_builder.block_header.SerializeToString() signature = signing.sign(header_bytes, self.identity_signing_key) block_builder.set_signature(signature) return BlockWrapper(block_builder.build_block()) def generate_genesis_block(self): return self._generate_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=0, 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) or\ isinstance(block, BlockWrapper): return block.header_signature elif isinstance(block, basestring): return block 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): if txns is None: 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_pubkey=self.public_key, transaction_ids=[ txn.header_signature for txn in txns ]).SerializeToString() batch = Batch(header=batch_header, header_signature=self._signed_header(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_pubkey=self.public_key, family_name='test', family_version='1', nonce=_generate_id(16), payload_encoding="text", payload_sha512=hasher.hexdigest().encode(), signer_pubkey=self.public_key).SerializeToString() txn = Transaction(header=txn_header, header_signature=self._signed_header(txn_header), payload=payload_encoded) return txn def _generate_batch_from_payload(self, payload): txn = self.generate_transaction(payload) batch_header = BatchHeader(signer_pubkey=self.public_key, transaction_ids=[txn.header_signature ]).SerializeToString() batch = Batch(header=batch_header, header_signature=self._signed_header(batch_header), transactions=[txn]) return batch def _signed_header(self, header): return signing.sign(header, self.signing_key)
class BlockTreeManager(object): def block_def(self, add_to_store=False, batch_count=0, status=BlockStatus.Unknown, invalid_consensus=False, invalid_batch=False, invalid_signature=False, weight=1 ): return { "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 __init__(self): self.block_store = {} self._new_block = None self.block_publisher = BlockPublisher( consensus=TestModePublisher(), transaction_executor=MockTransactionExecutor(), send_message=self._send_message, squash_handler=None) block = self.generate_block(add_to_store=True, status=BlockStatus.Valid) self.set_chain_head(block) def _send_message(self, block): self._new_block = block def _get_block_id(self, block): if (block is None): return None elif isinstance(block, Block) or isinstance(block, BlockState) or \ isinstance(block, BlockWrapper): return block.header_signature elif isinstance(block, basestring): return block else: return str(block) def _get_block(self, block): if (block is None): return None elif isinstance(block, Block): return block elif isinstance(block, BlockWrapper): return block elif isinstance(block, BlockState): return block.block elif isinstance(block, str): return self.block_store[block] else: # WTF try something crazy return self.block_store[str(block)] def set_chain_head(self, block): self.block_store["chain_head_id"] = self._get_block_id(block) @property def chain_head(self): return self.block_store[self.block_store["chain_head_id"]] def generate_block(self, previous_block=None, add_to_store=False, batch_count=0, status=BlockStatus.Unknown, invalid_consensus=False, invalid_batch=False, invalid_signature=False, weight=1): previous = self._get_block(previous_block) if previous is None: previous = BlockWrapper(BlockHeader( block_num=0, previous_block_id="0000000000000000", )) previous.set_signature(_generate_id()) previous_block_state = BlockState( block_wrapper=previous, weight=0, status=BlockStatus.Valid) self.block_store[previous.header_signature] = previous_block_state self.block_publisher.on_chain_updated(previous) while self._new_block is None: self.block_publisher.on_batch_received(Batch()) self.block_publisher.on_check_publish_block(True) block = self._new_block self._new_block = None header = BlockHeader() header.ParseFromString(block.header) block = BlockWrapper(header, block) if invalid_signature: block.set_signature("BAD") if add_to_store: block_state = BlockState(block_wrapper=block, weight=0) block_state.status = status self.block_store[block.header_signature] = block_state return block def generate_chain(self, root_block, blocks): # block options # valid/invalid how # add to store out = [] if not isinstance(blocks, list): blocks = self.generate_chain_definition(int(blocks)) previous = self._get_block(root_block) for b in blocks: new_block = self.generate_block(previous_block=previous, **b) out.append(new_block) previous = new_block return out def generate_chain_definition(self, count): out = [] for _ in range(0, count): out.append(self.block_def()) return out def __str__(self): return str(self.block_store) def __repr__(self): return repr(self.block_store)
class BlockTreeManager(object): def block_def(self, add_to_store=False, add_to_cache=False, batch_count=0, status=BlockStatus.Unknown, invalid_consensus=False, invalid_batch=False, invalid_signature=False, weight=None ): 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 __init__(self): self.block_sender = MockBlockSender() self.block_store = BlockStoreAdapter({}) self.block_cache = BlockCache(self.block_store) self.signing_key = signing.generate_privkey() self.public_key = signing.encode_pubkey( signing.generate_pubkey(self.signing_key), "hex") self.genesis_block = self._generate_genesis_block() self.block_store[self.genesis_block.identifier] = self.genesis_block self.set_chain_head(self.genesis_block) self.block_publisher = BlockPublisher( consensus=TestModePublisher(), transaction_executor=MockTransactionExecutor(), block_sender=self.block_sender, squash_handler=None, chain_head=self.genesis_block) def _get_block_id(self, block): if (block is None): return None elif isinstance(block, Block) or\ isinstance(block, BlockWrapper): return block.header_signature elif isinstance(block, basestring): return block 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 set_chain_head(self, block): self.block_store.set_chain_head(self._get_block_id(block)) @property def chain_head(self): return self.block_store.chain_head def set_chain_head(self, block): self.block_store.set_chain_head(block.identifier) def generate_block(self, previous_block=None, add_to_store=False, add_to_cache=False, batch_count=0, status=BlockStatus.Unknown, invalid_consensus=False, invalid_batch=False, invalid_signature=False, weight=None): previous = self._get_block(previous_block) if previous is None: previous = self.chain_head self.block_publisher.on_chain_updated(previous) while self.block_sender.new_block is None: self.block_publisher.on_batch_received(Batch()) self.block_publisher.on_check_publish_block(True) block = self.block_sender.new_block self.block_sender.new_block = None block = BlockWrapper(block) if invalid_signature: block.block.header_signature = "BAD" block.weight = weight block.status = status if add_to_cache: self.block_cache[block.identifier] = block if add_to_store: if block.weight is None: tmv = TestModeVerifier() block.weight = tmv.compute_block_weight(block) self.block_store[block.identifier] = block return block def _generate_batch(self, payload): payload_encoded = payload.encode('utf-8') hasher = hashlib.sha512() hasher.update(payload_encoded) header = TransactionHeader() header.batcher_pubkey = self.public_key # txn.dependencies not yet header.family_name = 'test' header.family_version = '1' header.nonce = _generate_id(16) header.payload_encoding = "text" header.payload_sha512 = hasher.hexdigest().encode() header.signer_pubkey = self.public_key txn = Transaction() header_bytes = header.SerializeToString() txn.header = header_bytes txn.header_signature = signing.sign(header_bytes, self.signing_key) txn.payload = payload_encoded batch_header = BatchHeader() batch_header.signer_pubkey = self.public_key batch_header.transaction_ids.extend([txn.header_signature]) batch = Batch() header_bytes = batch_header.SerializeToString() batch.header = header_bytes batch.header_signature = signing.sign(header_bytes, self.signing_key) batch.transactions.extend([txn]) return batch def _generate_genesis_block(self): genesis_header = BlockHeader( previous_block_id=NULL_BLOCK_IDENTIFIER, signer_pubkey=self.public_key, block_num=0) block = BlockBuilder(genesis_header) block.add_batches([self._generate_batch("Genesis")]) header_bytes = block.block_header.SerializeToString() signature = signing.sign(header_bytes, self.signing_key) block.set_signature(signature) return BlockWrapper(block.build_block()) def generate_chain(self, root_block, blocks, params=None): """ Generate a new chain based on the root block and place it in the block cache. """ if params is None: params = {} out = [] if not isinstance(blocks, list): blocks = self.generate_chain_definition(int(blocks), params) if root_block is None: previous = self._generate_genesis_block() self.block_store[previous.identifier] = previous else: previous = self._get_block(root_block) for block in blocks: new_block = self.generate_block(previous_block=previous, **block) out.append(new_block) previous = new_block return out def generate_chain_definition(self, count, params=None): if params is None: params = {} out = [] for _ in range(0, count): out.append(self.block_def(**params)) return out def __str__(self): return str(self.block_cache) def __repr__(self): return repr(self.block_cache)