def write_blocks(self): """ Write blocks to the bigchain """ # create bigchain instance b = Bigchain() # Write blocks while True: block = self.q_block.get() # poison pill if block == 'stop': return b.write_block(block)
def bft(): # Cryptographic Identities Generation alice, bob = generate_keypair(), generate_keypair() print(" ") # Digital Asset Definition (e.g. bicycle) asset = Asset(data={ "bicycle": { "manufacturer": "bkfab", "serial_number": "abcd1234" } }) # Metadata Definition metadata = {'planet': 'earth'} # create trnsaction TODO : owners_before might be node_pubkey in v0.8.0 tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], metadata=metadata, asset=asset) # sign with private key tx = tx.sign([alice.private_key]) tx_id = tx.to_dict()['id'] print("tx_id : ", tx_id) # create block b = Bigchain() block = b.create_block([tx]) print("valid block timestamp : ", block.to_dict()['block']['timestamp']) # tamper block block.timestamp = '1' print("tamper block.timestamp to 1 : ") block_id = block.to_dict()['id'] block_voters = block.to_dict()['block']['voters'] print("invalid block timestamp : ", block.to_dict()['block']['timestamp']) print("tamper_block_id : ", block_id) print("db response of block : ", b.write_block(block)) sleep(0) last_voted_id = b.get_last_voted_block().id vote = b.vote(block_id, last_voted_id, True) print("crate vote 'True' : ", vote) print("db response of vote : ", b.write_vote(vote)) print("tamper_block status : ", b.block_election_status(block_id, block_voters)) print("blocks_status_containing_tx : ", b.get_blocks_status_containing_tx(tx_id)) print("wait for 20 sec : ") sleep(20) print("blocks_status_containing_tx : ", b.get_blocks_status_containing_tx(tx_id)) print(" ")
def tamper_block(): # Cryptographic Identities Generation alice, bob = generate_keypair(), generate_keypair() print(" ") # Digital Asset Definition (e.g. bicycle) asset = Asset(data={ "bicycle": { "manufacturer": "bkfab", "serial_number": "abcd1234" } }) # Metadata Definition metadata = {'planet': 'earth'} # create trnsaction TODO : owners_before might be node_pubkey in v0.8.0 tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], metadata=metadata, asset=asset) # did not sign with private key # tx = tx.sign([alice.private_key]) tx_id = tx.to_dict()['id'] print("dummy tx id : ", tx_id) # create block b = Bigchain() block = b.create_block([tx]) print("block voters right now : ", block.to_dict()['block']['voters']) # tamper block block.voters = [bob.public_key] block_id = block.to_dict()['id'] block_voters = block.to_dict()['block']['voters'] print("tamper block voters : ", block.to_dict()['block']['voters']) print("tamper block id : ", block_id) print("db response : ", b.write_block(block)) sleep(delay) print("tamper_block status : ", b.block_election_status(block_id, block_voters)) print("blocks_status_containing_tx : ", b.get_blocks_status_containing_tx(tx_id)) print(" ")
class Block: """This class encapsulates the logic to create blocks. Note: Methods of this class will be executed in different processes. """ def __init__(self): """Initialize the Block creator""" self.bigchain = Bigchain() self.txs = [] def filter_tx(self, tx): """Filter a transaction. Args: tx (dict): the transaction to process. Returns: The transaction if assigned to the current node, ``None`` otherwise. """ if tx['assignee'] == self.bigchain.me: tx.pop('assignee') tx.pop('assignment_timestamp') return tx def validate_tx(self, tx): """Validate a transaction. Also checks if the transaction already exists in the blockchain. If it does, or it's invalid, it's deleted from the backlog immediately. Args: tx (dict): the transaction to validate. Returns: The transaction if valid, ``None`` otherwise. """ if self.bigchain.transaction_exists(tx['id']): # if the transaction already exists, we must check whether # it's in a valid or undecided block tx, status = self.bigchain.get_transaction(tx['id'], include_status=True) if status == self.bigchain.TX_VALID \ or status == self.bigchain.TX_UNDECIDED: # if the tx is already in a valid or undecided block, # then it no longer should be in the backlog, or added # to a new block. We can delete and drop it. r.table('backlog').get(tx['id']) \ .delete(durability='hard') \ .run(self.bigchain.conn) return None tx_validated = self.bigchain.is_valid_transaction(tx) if tx_validated: return tx else: # if the transaction is not valid, remove it from the # backlog r.table('backlog').get(tx['id']) \ .delete(durability='hard') \ .run(self.bigchain.conn) return None def create(self, tx, timeout=False): """Create a block. This method accumulates transactions to put in a block and outputs a block when one of the following conditions is true: - the size limit of the block has been reached, or - a timeout happened. Args: tx (dict): the transaction to validate, might be None if a timeout happens. timeout (bool): ``True`` if a timeout happened (Default: ``False``). Returns: The block, if a block is ready, or ``None``. """ if tx: self.txs.append(tx) if len(self.txs) == 1000 or (timeout and self.txs): block = self.bigchain.create_block(self.txs) self.txs = [] return block def write(self, block): """Write the block to the Database. Args: block (dict): the block of transactions to write to the database. Returns: The block. """ logger.info('Write new block %s with %s transactions', block['id'], len(block['block']['transactions'])) self.bigchain.write_block(block) return block def delete_tx(self, block): """Delete transactions. Args: block (dict): the block containg the transactions to delete. Returns: The block. """ r.table('backlog')\ .get_all(*[tx['id'] for tx in block['block']['transactions']])\ .delete(durability='hard')\ .run(self.bigchain.conn) return block
class BlockPipeline: """This class encapsulates the logic to create blocks. Note: Methods of this class will be executed in different processes. """ def __init__(self): """Initialize the BlockPipeline creator""" self.bigchain = Bigchain() self.txs = tx_collector() def filter_tx(self, tx): """Filter a transaction. Args: tx (dict): the transaction to process. Returns: dict: The transaction if assigned to the current node, ``None`` otherwise. """ if tx['assignee'] == self.bigchain.me: tx.pop('assignee') tx.pop('assignment_timestamp') return tx def validate_tx(self, tx): """Validate a transaction. Also checks if the transaction already exists in the blockchain. If it does, or it's invalid, it's deleted from the backlog immediately. Args: tx (dict): the transaction to validate. Returns: :class:`~bigchaindb.models.Transaction`: The transaction if valid, ``None`` otherwise. """ try: tx = Transaction.from_dict(tx) except ValidationError: return None # If transaction is in any VALID or UNDECIDED block we # should not include it again if not self.bigchain.is_new_transaction(tx.id): self.bigchain.delete_transaction(tx.id) return None # If transaction is not valid it should not be included try: # Do not allow an externally submitted GENESIS transaction. # A simple check is enough as a pipeline is started only after the # creation of GENESIS block, or after the verification of a GENESIS # block. Voting will fail at a later stage if the GENESIS block is # absent. if tx.operation == Transaction.GENESIS: raise GenesisBlockAlreadyExistsError( 'Duplicate GENESIS transaction') tx.validate(self.bigchain) return tx except ValidationError as e: logger.warning('Invalid tx: %s', e) self.bigchain.delete_transaction(tx.id) return None def create(self, tx, timeout=False): """Create a block. This method accumulates transactions to put in a block and outputs a block when one of the following conditions is true: - the size limit of the block has been reached, or - a timeout happened. Args: tx (:class:`~bigchaindb.models.Transaction`): the transaction to validate, might be None if a timeout happens. timeout (bool): ``True`` if a timeout happened (Default: ``False``). Returns: :class:`~bigchaindb.models.Block`: The block, if a block is ready, or ``None``. """ txs = self.txs.send(tx) if len(txs) == 1000 or (timeout and txs): block = self.bigchain.create_block(txs) self.txs = tx_collector() return block def write(self, block): """Write the block to the Database. Args: block (:class:`~bigchaindb.models.Block`): the block of transactions to write to the database. Returns: :class:`~bigchaindb.models.Block`: The Block. """ logger.info('Write new block %s with %s transactions', block.id, len(block.transactions)) self.bigchain.write_block(block) self.bigchain.statsd.incr('pipelines.block.throughput', len(block.transactions)) return block def delete_tx(self, block): """Delete transactions. Args: block (:class:`~bigchaindb.models.Block`): the block containg the transactions to delete. Returns: :class:`~bigchaindb.models.Block`: The block. """ self.bigchain.delete_transaction(*[tx.id for tx in block.transactions]) return block
class Block: """This class encapsulates the logic to create blocks. Note: Methods of this class will be executed in different processes. """ def __init__(self): """Initialize the Block creator""" self.bigchain = Bigchain() self.txs = [] def filter_tx(self, tx): """Filter a transaction. Args: tx (dict): the transaction to process. Returns: The transaction if assigned to the current node, ``None`` otherwise. """ if tx['assignee'] == self.bigchain.me: tx.pop('assignee') return tx def delete_tx(self, tx): """Delete a transaction. Args: tx (dict): the transaction to delete. Returns: The transaction. """ r.table('backlog')\ .get(tx['id'])\ .delete(durability='hard')\ .run(self.bigchain.conn) return tx def validate_tx(self, tx): """Validate a transaction. Args: tx (dict): the transaction to validate. Returns: The transaction if valid, ``None`` otherwise. """ tx = self.bigchain.is_valid_transaction(tx) if tx: return tx def create(self, tx, timeout=False): """Create a block. This method accumulates transactions to put in a block and outputs a block when one of the following conditions is true: - the size limit of the block has been reached, or - a timeout happened. Args: tx (dict): the transaction to validate, might be None if a timeout happens. timeout (bool): ``True`` if a timeout happened (Default: ``False``). Returns: The block, if a block is ready, or ``None``. """ if tx: self.txs.append(tx) if len(self.txs) == 1000 or (timeout and self.txs): block = self.bigchain.create_block(self.txs) self.txs = [] return block def write(self, block): """Write the block to the Database. Args: block (dict): the block of transactions to write to the database. Returns: The block. """ logger.info('Write new block %s with %s transactions', block['id'], len(block['block']['transactions'])) self.bigchain.write_block(block) return block
class BlockPipeline: """This class encapsulates the logic to create blocks. Note: Methods of this class will be executed in different processes. """ def __init__(self): """Initialize the BlockPipeline creator""" self.bigchain = Bigchain() self.txs = tx_collector() def filter_tx(self, tx): """Filter a transaction. Args: tx (dict): the transaction to process. Returns: dict: The transaction if assigned to the current node, ``None`` otherwise. """ if tx['assignee'] == self.bigchain.me: tx.pop('assignee') tx.pop('assignment_timestamp') return tx def validate_tx(self, tx): """Validate a transaction. Also checks if the transaction already exists in the blockchain. If it does, or it's invalid, it's deleted from the backlog immediately. Args: tx (dict): the transaction to validate. Returns: :class:`~bigchaindb.models.Transaction`: The transaction if valid, ``None`` otherwise. """ try: tx = Transaction.from_dict(tx) except ValidationError: return None # If transaction is in any VALID or UNDECIDED block we # should not include it again if not self.bigchain.is_new_transaction(tx.id): self.bigchain.delete_transaction(tx.id) return None # If transaction is not valid it should not be included try: # Do not allow an externally submitted GENESIS transaction. # A simple check is enough as a pipeline is started only after the # creation of GENESIS block, or after the verification of a GENESIS # block. Voting will fail at a later stage if the GENESIS block is # absent. if tx.operation == Transaction.GENESIS: raise GenesisBlockAlreadyExistsError('Duplicate GENESIS transaction') tx.validate(self.bigchain) return tx except ValidationError as e: logger.warning('Invalid tx: %s', e) self.bigchain.delete_transaction(tx.id) return None def create(self, tx, timeout=False): """Create a block. This method accumulates transactions to put in a block and outputs a block when one of the following conditions is true: - the size limit of the block has been reached, or - a timeout happened. Args: tx (:class:`~bigchaindb.models.Transaction`): the transaction to validate, might be None if a timeout happens. timeout (bool): ``True`` if a timeout happened (Default: ``False``). Returns: :class:`~bigchaindb.models.Block`: The block, if a block is ready, or ``None``. """ txs = self.txs.send(tx) if len(txs) == 1000 or (timeout and txs): block = self.bigchain.create_block(txs) self.txs = tx_collector() return block def write(self, block): """Write the block to the Database. Args: block (:class:`~bigchaindb.models.Block`): the block of transactions to write to the database. Returns: :class:`~bigchaindb.models.Block`: The Block. """ logger.info('Write new block %s with %s transactions', block.id, len(block.transactions)) self.bigchain.write_block(block) self.bigchain.statsd.incr('pipelines.block.throughput', len(block.transactions)) return block def delete_tx(self, block): """Delete transactions. Args: block (:class:`~bigchaindb.models.Block`): the block containg the transactions to delete. Returns: :class:`~bigchaindb.models.Block`: The block. """ self.bigchain.delete_transaction(*[tx.id for tx in block.transactions]) return block
class BlockPipeline: """This class encapsulates the logic to create blocks. Note: Methods of this class will be executed in different processes. """ def __init__(self): """Initialize the BlockPipeline creator""" self.bigchain = Bigchain() self.txs = [] def filter_tx(self, tx): """Filter a transaction. Args: tx (dict): the transaction to process. Returns: dict: The transaction if assigned to the current node, ``None`` otherwise. """ if tx['assignee'] == self.bigchain.me: tx.pop('assignee') tx.pop('assignment_timestamp') return tx def validate_tx(self, tx): """Validate a transaction. Also checks if the transaction already exists in the blockchain. If it does, or it's invalid, it's deleted from the backlog immediately. Args: tx (dict): the transaction to validate. Returns: :class:`~bigchaindb.models.Transaction`: The transaction if valid, ``None`` otherwise. """ try: tx = Transaction.from_dict(tx) except (SchemaValidationError, InvalidHash, InvalidSignature, AmountError): return None # If transaction is in any VALID or UNDECIDED block we # should not include it again if not self.bigchain.is_new_transaction(tx.id): self.bigchain.delete_transaction(tx.id) return None # If transaction is not valid it should not be included if not self.bigchain.is_valid_transaction(tx): self.bigchain.delete_transaction(tx.id) return None return tx def create(self, tx, timeout=False): """Create a block. This method accumulates transactions to put in a block and outputs a block when one of the following conditions is true: - the size limit of the block has been reached, or - a timeout happened. Args: tx (:class:`~bigchaindb.models.Transaction`): the transaction to validate, might be None if a timeout happens. timeout (bool): ``True`` if a timeout happened (Default: ``False``). Returns: :class:`~bigchaindb.models.Block`: The block, if a block is ready, or ``None``. """ if tx: self.txs.append(tx) if len(self.txs) == 1000 or (timeout and self.txs): block = self.bigchain.create_block(self.txs) self.txs = [] return block def write(self, block): """Write the block to the Database. Args: block (:class:`~bigchaindb.models.Block`): the block of transactions to write to the database. Returns: :class:`~bigchaindb.models.Block`: The Block. """ logger.info('Write new block %s with %s transactions', block.id, len(block.transactions)) self.bigchain.write_block(block) return block def delete_tx(self, block): """Delete transactions. Args: block (:class:`~bigchaindb.models.Block`): the block containg the transactions to delete. Returns: :class:`~bigchaindb.models.Block`: The block. """ self.bigchain.delete_transaction(*[tx.id for tx in block.transactions]) return block