def vote(self, block, previous_block_id, decision, invalid_reason=None): """Cast your vote on the block given the previous_block_hash and the decision (valid/invalid) return the block to the updated in the database. Args: block (dict): Block to vote. previous_block_id (str): The id of the previous block. decision (bool): Whether the block is valid or invalid. invalid_reason (Optional[str]): Reason the block is invalid """ vote = { 'voting_for_block': block['id'], 'previous_block': previous_block_id, 'is_block_valid': decision, 'invalid_reason': invalid_reason, 'timestamp': util.timestamp() } vote_data = util.serialize(vote) signature = crypto.SigningKey(self.me_private).sign(vote_data) vote_signed = { 'node_pubkey': self.me, 'signature': signature, 'vote': vote } return vote_signed
def create_block(self, validated_transactions): """Creates a block given a list of `validated_transactions`. Note that this method does not validate the transactions. Transactions should be validated before calling create_block. Args: validated_transactions (list): list of validated transactions. Returns: dict: created block. """ # Create the new block block = { 'timestamp': util.timestamp(), 'transactions': validated_transactions, 'node_pubkey': self.me, 'voters': self.federation_nodes + [self.me] } # Calculate the hash of the new block block_data = util.serialize(block) block_hash = crypto.hash_data(block_data) block_signature = crypto.SigningKey(self.me_private).sign(block_data) block = { 'id': block_hash, 'block': block, 'signature': block_signature, 'votes': [] } return block
def test_invalid_transactions_in_block(self, b, user_public_key, ): # invalid transaction valid_input = b.get_owned_ids(user_public_key).pop() tx_invalid = b.create_transaction('a', 'b', valid_input, 'c') block = b.create_block([tx_invalid]) # create a block with invalid transactions block = { 'timestamp': util.timestamp(), 'transactions': [tx_invalid], 'node_pubkey': b.me, 'voters': b.federation_nodes } block_data = util.serialize(block) block_hash = crypto.hash_data(block_data) block_signature = crypto.SigningKey(b.me_private).sign(block_data) block = { 'id': block_hash, 'block': block, 'signature': block_signature, 'votes': [] } with pytest.raises(exceptions.TransactionOwnerError) as excinfo: b.validate_block(block) assert excinfo.value.args[0] == 'current_owner `a` does not own the input `{}`'.format(valid_input)
def sign_tx(transaction, signing_keys, bigchain=None): """Sign a transaction A transaction signed with the `current_owner` corresponding private key. Args: transaction (dict): transaction to sign. signing_keys (list): list of base58 encoded private keys to create the fulfillments of the transaction. bigchain (obj): bigchain instance used to get the details of the previous transaction outputs. Useful if the `Bigchain` instance was instantiated with parameters that override the config file. Returns: dict: transaction with the `fulfillment` fields populated. """ # validate sk if not isinstance(signing_keys, list): signing_keys = [signing_keys] # create a mapping between sk and vk so that we can match the private key to the current_owners key_pairs = {} for sk in signing_keys: signing_key = crypto.SigningKey(sk) vk = signing_key.get_verifying_key().to_ascii().decode() key_pairs[vk] = signing_key tx = copy.deepcopy(transaction) bigchain = bigchain if bigchain is not None else bigchaindb.Bigchain() for fulfillment in tx['transaction']['fulfillments']: fulfillment_message = get_fulfillment_message(transaction, fulfillment) # TODO: avoid instantiation, pass as argument! input_condition = get_input_condition(bigchain, fulfillment) parsed_fulfillment = cc.Fulfillment.from_dict( input_condition['condition']['details']) # for the case in which the type of fulfillment is not covered by this method parsed_fulfillment_signed = parsed_fulfillment # single current owner if isinstance(parsed_fulfillment, cc.Ed25519Fulfillment): parsed_fulfillment_signed = fulfill_simple_signature_fulfillment( fulfillment, parsed_fulfillment, fulfillment_message, key_pairs) # multiple current owners elif isinstance(parsed_fulfillment, cc.ThresholdSha256Fulfillment): parsed_fulfillment_signed = fulfill_threshold_signature_fulfillment( fulfillment, parsed_fulfillment, fulfillment_message, key_pairs) signed_fulfillment = parsed_fulfillment_signed.serialize_uri() fulfillment.update({'fulfillment': signed_fulfillment}) return tx
def sign_tx(transaction, signing_keys): """Sign a transaction A transaction signed with the `current_owner` corresponding private key. Args: transaction (dict): transaction to sign. signing_keys (list): list of base58 encoded private keys to create the fulfillments of the transaction. Returns: dict: transaction with the `fulfillment` fields populated. """ # validate sk if not isinstance(signing_keys, list): signing_keys = [signing_keys] # create a mapping between sk and vk so that we can match the private key to the current_owners key_pairs = {} for sk in signing_keys: signing_key = crypto.SigningKey(sk) vk = signing_key.get_verifying_key().to_ascii().decode() key_pairs[vk] = signing_key tx = copy.deepcopy(transaction) for fulfillment in tx['transaction']['fulfillments']: fulfillment_message = get_fulfillment_message(transaction, fulfillment) parsed_fulfillment = cc.Fulfillment.from_json( fulfillment_message['condition']['condition']['details']) # for the case in which the type of fulfillment is not covered by this method parsed_fulfillment_signed = parsed_fulfillment # single current owner if isinstance(parsed_fulfillment, cc.Ed25519Fulfillment): parsed_fulfillment_signed = fulfill_simple_signature_fulfillment( fulfillment, parsed_fulfillment, fulfillment_message, key_pairs) # multiple current owners elif isinstance(parsed_fulfillment, cc.ThresholdSha256Fulfillment): parsed_fulfillment_signed = fulfill_threshold_signature_fulfillment( fulfillment, parsed_fulfillment, fulfillment_message, key_pairs) signed_fulfillment = parsed_fulfillment_signed.serialize_uri() fulfillment.update({'fulfillment': signed_fulfillment}) return tx
def sign_tx(transaction, private_key): """Sign a transaction A transaction signed with the `current_owner` corresponding private key. Args: transaction (dict): transaction to sign. private_key (str): base58 encoded private key to create a signature of the transaction. Returns: dict: transaction with the `signature` field included. """ private_key = crypto.SigningKey(private_key) signature = private_key.sign(serialize(transaction)) signed_transaction = transaction.copy() signed_transaction.update({'signature': signature.decode()}) return signed_transaction
def create_block(self, validated_transactions): """Creates a block given a list of `validated_transactions`. Note that this method does not validate the transactions. Transactions should be validated before calling create_block. Args: validated_transactions (list): list of validated transactions. Returns: dict: created block. """ # Prevent the creation of empty blocks if len(validated_transactions) == 0: raise exceptions.OperationError( 'Empty block creation is not allowed') # Create the new block block = { 'timestamp': util.timestamp(), 'transactions': validated_transactions, 'node_pubkey': self.me, 'voters': self.nodes_except_me + [self.me] } # Calculate the hash of the new block block_data = util.serialize(block) block_hash = crypto.hash_data(block_data) block_signature = crypto.SigningKey(self.me_private).sign(block_data) block = { 'id': block_hash, 'block': block, 'signature': block_signature, 'votes': [] } return block