def validate_block(bigchain, block): """Validate a block. Args: bigchain (Bigchain): an instantiated bigchaindb.Bigchain object. block (dict): block to validate. Returns: The block if the block is valid else it raises an exception describing the reason why the block is invalid. Raises: InvalidHash: if the hash of the block is wrong. """ # Check if current hash is correct calculated_hash = crypto.hash_data(util.serialize(block['block'])) if calculated_hash != block['id']: raise exceptions.InvalidHash() # Check if the block was created by a federation node if block['block']['node_pubkey'] not in (bigchain.federation_nodes + [bigchain.me]): raise exceptions.OperationError('Only federation nodes can create blocks') # Check if block signature is valid verifying_key = crypto.VerifyingKey(block['block']['node_pubkey']) if not verifying_key.verify(util.serialize(block['block']), block['signature']): raise exceptions.InvalidSignature('Invalid block signature') return block
def validate_block(bigchain, block): """Validate a block. Args: bigchain (Bigchain): an instantiated bigchaindb.Bigchain object. block (dict): block to validate. Returns: The block if the block is valid else it raises an exception describing the reason why the block is invalid. Raises: InvalidHash: if the hash of the block is wrong. """ # Check if current hash is correct calculated_hash = crypto.hash_data(util.serialize(block['block'])) if calculated_hash != block['id']: raise exceptions.InvalidHash() # Check if the block was created by a federation node if block['block']['node_pubkey'] not in (bigchain.nodes_except_me + [bigchain.me]): raise exceptions.OperationError( 'Only federation nodes can create blocks') # Check if block signature is valid verifying_key = crypto.VerifyingKey(block['block']['node_pubkey']) if not verifying_key.verify(util.serialize(block['block']), block['signature']): raise exceptions.InvalidSignature('Invalid block signature') return block
def test_create_new_block(self, b): new_block = b.create_block([]) block_hash = crypto.hash_data(util.serialize(new_block['block'])) assert new_block['block']['voters'] == [b.me] assert new_block['block']['node_pubkey'] == b.me assert crypto.VerifyingKey(b.me).verify(util.serialize(new_block['block']), new_block['signature']) is True assert new_block['id'] == block_hash assert new_block['votes'] == []
def test_read_transaction(self, b, user_public_key, user_private_key): input_tx = b.get_owned_ids(user_public_key).pop() tx = b.create_transaction(user_public_key, 'b', input_tx, 'd') tx_signed = b.sign_transaction(tx, user_private_key) b.write_transaction(tx_signed) # create block and write it to the bighcain before retrieving the transaction block = b.create_block([tx_signed]) b.write_block(block, durability='hard') response = b.get_transaction(tx_signed["id"]) assert util.serialize(tx_signed) == util.serialize(response)
def test_valid_block_voting(self, b): # create queue and voter q_new_block = mp.Queue() voter = Voter(q_new_block) genesis = b.create_genesis_block() # create valid block block = b.create_block([]) # assert block is valid assert b.is_valid_block(block) b.write_block(block, durability='hard') # insert into queue # FIXME: we disable this because the voter can currently vote more than one time for a block # q_new_block.put(block) # vote voter.start() # wait for vote to be written time.sleep(1) voter.kill() # retrive block from bigchain bigchain_block = r.table('bigchain').get(block['id']).run(b.conn) # validate vote assert len(bigchain_block['votes']) == 1 vote = bigchain_block['votes'][0] assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == genesis['id'] assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
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 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).decode() 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. """ # 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} return block
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 vote(self, block_id, 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_id (str): The id of the 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 """ if block_id == previous_block_id: raise exceptions.CyclicBlockchainError() 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 exists(digital_asset_payload): payload_hash = crypto.hash_data(util.serialize(digital_asset_payload)) transactions = b.get_tx_by_payload_hash(payload_hash) result = transactions is not None and len(transactions) > 0 return result
def test_valid_block_voting(self, b): q_new_block = mp.Queue() genesis = b.create_genesis_block() # create valid block block = b.create_block([]) # assert block is valid assert b.is_valid_block(block) b.write_block(block, durability='hard') # create queue and voter voter = Voter(q_new_block) # vote voter.start() # wait for vote to be written time.sleep(1) voter.kill() # retrive block from bigchain blocks = list(r.table('bigchain') .order_by(r.asc((r.row['block']['timestamp']))) .run(b.conn)) # validate vote assert len(blocks[1]['votes']) == 1 vote = blocks[1]['votes'][0] assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == genesis['id'] assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
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).decode() block = { 'id': block_hash, 'block': block, 'signature': block_signature, 'votes': [] } return block
def test_valid_block_voting(self, b): q_new_block = mp.Queue() genesis = b.create_genesis_block() # create valid block block = b.create_block([]) # assert block is valid assert b.is_valid_block(block) b.write_block(block, durability='hard') # create queue and voter voter = Voter(q_new_block) # vote voter.start() # wait for vote to be written time.sleep(1) voter.kill() # retrive block from bigchain blocks = list(r.table('bigchain') .order_by(r.asc((r.row['block']['timestamp']))) .run(b.conn)) # validate vote assert len(blocks[1]['votes']) == 1 vote = blocks[1]['votes'][0] assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == genesis['id'] assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
def test_vote_creation_invalid(self, b): # create valid block block = b.create_block([]) # retrieve vote vote = b.vote(block, 'abc', False) # assert vote is correct assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == 'abc' assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
def test_vote_creation_invalid(self, b): # create valid block block = b.create_block([]) # retrieve vote vote = b.vote(block, 'abc', False) # assert vote is correct assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == 'abc' assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
def test_transaction_hash(self, b): payload = {'cats': 'are awesome'} tx = b.create_transaction('a', 'b', 'c', 'd', payload) tx_calculated = { 'current_owners': ['a'], 'new_owners': ['b'], 'input': 'c', 'operation': 'd', 'timestamp': tx['transaction']['timestamp'], 'data': { 'hash': hash_data(util.serialize(payload)), 'payload': payload } } assert tx['transaction']['data'] == tx_calculated['data']
def test_transaction_hash(self, b): payload = {'cats': 'are awesome'} tx = b.create_transaction('a', 'b', 'c', 'd', payload) tx_calculated = { 'current_owner': 'a', 'new_owner': 'b', 'input': 'c', 'operation': 'd', 'timestamp': tx['transaction']['timestamp'], 'data': { 'hash': crypto.hash_data(util.serialize(payload)), 'payload': payload } } assert tx['transaction']['data'] == tx_calculated['data']
def test_invalid_block_voting(self, b, user_public_key): # create queue and voter q_new_block = mp.Queue() voter = Voter(q_new_block) # create transaction transaction = b.create_transaction(b.me, user_public_key, None, 'CREATE') transaction_signed = b.sign_transaction(transaction, b.me_private) genesis = b.create_genesis_block() # create invalid block block = b.create_block([transaction_signed]) # change transaction id to make it invalid block['block']['transactions'][0]['id'] = 'abc' assert b.is_valid_block(block) is False b.write_block(block, durability='hard') # insert into queue # FIXME: we disable this because the voter can currently vote more than one time for a block # q_new_block.put(block) # vote voter.start() # wait for the vote to be written time.sleep(1) voter.kill() # retrive block from bigchain bigchain_block = r.table('bigchain').get(block['id']).run(b.conn) # validate vote assert len(bigchain_block['votes']) == 1 vote = bigchain_block['votes'][0] assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == genesis['id'] assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
def test_valid_block_voting_with_create_transaction(self, b): q_new_block = mp.Queue() genesis = b.create_genesis_block() # create a `CREATE` transaction test_user_priv, test_user_pub = crypto.generate_key_pair() tx = b.create_transaction(b.me, test_user_pub, None, 'CREATE') tx_signed = b.sign_transaction(tx, b.me_private) assert b.is_valid_transaction(tx_signed) # create valid block block = b.create_block([tx_signed]) # assert block is valid assert b.is_valid_block(block) b.write_block(block, durability='hard') # create queue and voter voter = Voter(q_new_block) # vote voter.start() # wait for vote to be written time.sleep(1) voter.kill() # retrive block from bigchain blocks = list(r.table('bigchain') .order_by(r.asc((r.row['block']['timestamp']))) .run(b.conn)) # validate vote assert len(blocks[1]['votes']) == 1 vote = blocks[1]['votes'][0] assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == genesis['id'] assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
def validate_block(bigchain, block): """Validate a block. Args: bigchain (Bigchain): an instantiated bigchaindb.Bigchain object. block (dict): block to validate. Returns: The block if the block is valid else it raises an exception describing the reason why the block is invalid. Raises: InvalidHash: if the hash of the block is wrong. """ # Check if current hash is correct calculated_hash = crypto.hash_data(util.serialize(block['block'])) if calculated_hash != block['id']: raise exceptions.InvalidHash() return block
def test_invalid_block_voting(self, b, user_public_key): # create queue and voter q_new_block = mp.Queue() voter = Voter(q_new_block) # create transaction transaction = b.create_transaction(b.me, user_public_key, None, 'CREATE') transaction_signed = b.sign_transaction(transaction, b.me_private) genesis = b.create_genesis_block() # create invalid block block = b.create_block([transaction_signed]) # change transaction id to make it invalid block['block']['transactions'][0]['id'] = 'abc' assert b.is_valid_block(block) is False b.write_block(block, durability='hard') # insert into queue # FIXME: we disable this because the voter can currently vote more than one time for a block # q_new_block.put(block) # vote voter.start() # wait for the vote to be written time.sleep(1) voter.kill() # retrive block from bigchain bigchain_block = r.table('bigchain').get(block['id']).run(b.conn) # validate vote assert len(bigchain_block['votes']) == 1 vote = bigchain_block['votes'][0] assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == genesis['id'] assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
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
def test_invalid_block_voting(self, b, user_vk): # create queue and voter q_new_block = mp.Queue() voter = Voter(q_new_block) # create transaction transaction = b.create_transaction(b.me, user_vk, None, 'CREATE') transaction_signed = b.sign_transaction(transaction, b.me_private) genesis = b.create_genesis_block() # create invalid block block = b.create_block([transaction_signed]) # change transaction id to make it invalid block['block']['transactions'][0]['id'] = 'abc' assert not b.is_valid_block(block) b.write_block(block, durability='hard') # vote voter.start() time.sleep(1) voter.kill() # retrive block from bigchain blocks = list(r.table('bigchain') .order_by(r.asc((r.row['block']['timestamp']))) .run(b.conn)) # validate vote assert len(blocks[1]['votes']) == 1 vote = blocks[1]['votes'][0] assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == genesis['id'] assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
def test_invalid_block_voting(self, b, user_public_key): # create queue and voter q_new_block = mp.Queue() voter = Voter(q_new_block) # create transaction transaction = b.create_transaction(b.me, user_public_key, None, 'CREATE') transaction_signed = b.sign_transaction(transaction, b.me_private) genesis = b.create_genesis_block() # create invalid block block = b.create_block([transaction_signed]) # change transaction id to make it invalid block['block']['transactions'][0]['id'] = 'abc' assert not b.is_valid_block(block) b.write_block(block, durability='hard') # vote voter.start() time.sleep(1) voter.kill() # retrive block from bigchain blocks = list(r.table('bigchain') .order_by(r.asc((r.row['block']['timestamp']))) .run(b.conn)) # validate vote assert len(blocks[1]['votes']) == 1 vote = blocks[1]['votes'][0] assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['previous_block'] == genesis['id'] assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
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
def validate_block(self, block): """Validate a block. Args: block (dict): block to validate. Returns: The block if the block is valid else it raises and exception describing the reason why the block is invalid. """ # 1. Check if current hash is correct calculated_hash = crypto.hash_data(util.serialize(block['block'])) if calculated_hash != block['id']: raise exceptions.InvalidHash() # 2. Validate all transactions in the block for transaction in block['block']['transactions']: if not self.is_valid_transaction(transaction): # this will raise the exception self.validate_transaction(transaction) return block
def validate_transaction(bigchain, transaction): """Validate a transaction. Args: bigchain (Bigchain): an instantiated bigchaindb.Bigchain object. transaction (dict): transaction to validate. Returns: The transaction if the transaction is valid else it raises an exception describing the reason why the transaction is invalid. Raises: OperationError: if the transaction operation is not supported TransactionDoesNotExist: if the input of the transaction is not found TransactionOwnerError: if the new transaction is using an input it doesn't own DoubleSpend: if the transaction is a double spend InvalidHash: if the hash of the transaction is wrong InvalidSignature: if the signature of the transaction is wrong """ # If the operation is CREATE the transaction should have no inputs and # should be signed by a federation node if transaction['transaction']['operation'] == 'CREATE': if transaction['transaction']['input']: raise ValueError('A CREATE operation has no inputs') if transaction['transaction']['current_owner'] not in ( bigchain.federation_nodes + [bigchain.me]): raise exceptions.OperationError( 'Only federation nodes can use the operation `CREATE`') else: # check if the input exists, is owned by the current_owner if not transaction['transaction']['input']: raise ValueError( 'Only `CREATE` transactions can have null inputs') tx_input = bigchain.get_transaction( transaction['transaction']['input']) if not tx_input: raise exceptions.TransactionDoesNotExist( 'input `{}` does not exist in the bigchain'.format( transaction['transaction']['input'])) if (tx_input['transaction']['new_owner'] != transaction['transaction']['current_owner']): raise exceptions.TransactionOwnerError( 'current_owner `{}` does not own the input `{}`'.format( transaction['transaction']['current_owner'], transaction['transaction']['input'])) # check if the input was already spent by a transaction other than # this one. spent = bigchain.get_spent(tx_input['id']) if spent and spent['id'] != transaction['id']: raise exceptions.DoubleSpend( 'input `{}` was already spent'.format( transaction['transaction']['input'])) # Check hash of the transaction calculated_hash = crypto.hash_data(util.serialize( transaction['transaction'])) if calculated_hash != transaction['id']: raise exceptions.InvalidHash() # Check signature if not util.verify_signature(transaction): raise exceptions.InvalidSignature() return transaction
def validate_transaction(bigchain, transaction): """Validate a transaction. Args: bigchain (Bigchain): an instantiated bigchaindb.Bigchain object. transaction (dict): transaction to validate. Returns: The transaction if the transaction is valid else it raises an exception describing the reason why the transaction is invalid. Raises: OperationError: if the transaction operation is not supported TransactionDoesNotExist: if the input of the transaction is not found TransactionOwnerError: if the new transaction is using an input it doesn't own DoubleSpend: if the transaction is a double spend InvalidHash: if the hash of the transaction is wrong InvalidSignature: if the signature of the transaction is wrong """ # If the operation is CREATE the transaction should have no inputs and # should be signed by a federation node if transaction['transaction']['operation'] == 'CREATE': if transaction['transaction']['input']: raise ValueError('A CREATE operation has no inputs') if transaction['transaction']['current_owner'] not in ( bigchain.federation_nodes + [bigchain.me]): raise exceptions.OperationError( 'Only federation nodes can use the operation `CREATE`') else: # check if the input exists, is owned by the current_owner if not transaction['transaction']['input']: raise ValueError( 'Only `CREATE` transactions can have null inputs') tx_input = bigchain.get_transaction( transaction['transaction']['input']) if not tx_input: raise exceptions.TransactionDoesNotExist( 'input `{}` does not exist in the bigchain'.format( transaction['transaction']['input'])) if (tx_input['transaction']['new_owner'] != transaction['transaction']['current_owner']): raise exceptions.TransactionOwnerError( 'current_owner `{}` does not own the input `{}`'.format( transaction['transaction']['current_owner'], transaction['transaction']['input'])) # check if the input was already spent by a transaction other than # this one. spent = bigchain.get_spent(tx_input['id']) if spent and spent['id'] != transaction['id']: raise exceptions.DoubleSpend( 'input `{}` was already spent'.format( transaction['transaction']['input'])) # Check hash of the transaction calculated_hash = crypto.hash_data( util.serialize(transaction['transaction'])) if calculated_hash != transaction['id']: raise exceptions.InvalidHash() # Check signature if not util.verify_signature(transaction): raise exceptions.InvalidSignature() return transaction
def test_valid_block_voting_with_transfer_transactions(self, b): q_new_block = mp.Queue() b.create_genesis_block() # create a `CREATE` transaction test_user_priv, test_user_pub = crypto.generate_key_pair() tx = b.create_transaction(b.me, test_user_pub, None, 'CREATE') tx_signed = b.sign_transaction(tx, b.me_private) assert b.is_valid_transaction(tx_signed) # create valid block block = b.create_block([tx_signed]) # assert block is valid assert b.is_valid_block(block) b.write_block(block, durability='hard') # create queue and voter voter = Voter(q_new_block) # vote voter.start() # wait for vote to be written time.sleep(1) voter.kill() # retrive block from bigchain blocks = list(r.table('bigchain') .order_by(r.asc((r.row['block']['timestamp']))) .run(b.conn)) # validate vote assert len(blocks[1]['votes']) == 1 # create a `TRANSFER` transaction test_user2_priv, test_user2_pub = crypto.generate_key_pair() tx2 = b.create_transaction(test_user_pub, test_user2_pub, {'txid': tx['id'], 'cid': 0}, 'TRANSFER') tx2_signed = b.sign_transaction(tx2, test_user_priv) assert b.is_valid_transaction(tx2_signed) # create valid block block = b.create_block([tx2_signed]) # assert block is valid assert b.is_valid_block(block) b.write_block(block, durability='hard') # create queue and voter voter = Voter(q_new_block) # vote voter.start() # wait for vote to be written time.sleep(1) voter.kill() # retrive block from bigchain blocks = list(r.table('bigchain') .order_by(r.asc((r.row['block']['timestamp']))) .run(b.conn)) # validate vote assert len(blocks[2]['votes']) == 1 vote = blocks[2]['votes'][0] assert vote['vote']['voting_for_block'] == block['id'] assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
def test_serializer(self, b): tx = b.create_transaction('a', 'b', 'c', 'd') assert util.deserialize(util.serialize(tx)) == tx