def test_generate_key_pair(self): private_value_base58, public_value_compressed_base58 = generate_key_pair( ) assert PrivateKey.encode( PrivateKey.decode(private_value_base58)) == private_value_base58 assert PublicKey.encode(*PublicKey.decode( public_value_compressed_base58)) == public_value_compressed_base58
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]) assert invalid_transactions == [tx_invalid] # create a block with invalid transactions block = { 'timestamp': b.timestamp(), 'transactions': [tx_invalid], 'node_pubkey': b.me, 'voters': b.federation_nodes } block_data = b.serialize(block) block_hash = hash_data(block_data) block_signature = PrivateKey(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': self.timestamp() } vote_data = self.serialize(vote) signature = PrivateKey(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': self.timestamp(), 'transactions': validated_transactions, 'node_pubkey': self.me, 'voters': self.federation_nodes + [self.me] } # Calculate the hash of the new block block_data = self.serialize(block) block_hash = hash_data(block_data) block_signature = PrivateKey(self.me_private).sign(block_data) block = { 'id': block_hash, 'block': block, 'signature': block_signature, 'votes': [] } return block
def sign_transaction(self, 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 = PrivateKey(private_key) signature = private_key.sign(self.serialize(transaction)) signed_transaction = transaction.copy() signed_transaction.update({'signature': signature}) return signed_transaction
def sign_transaction(self, transaction, private_key, public_key=None): """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. public_key (str): (optional) base58 encoded public key to identify each signature of a multisig transaction. Returns: dict: transaction with the `signature` field included. """ private_key = PrivateKey(private_key) if len(transaction['transaction']['current_owners']) == 1: signatures_updated = private_key.sign(self.serialize(transaction)) else: # multisig, sign for each input and store {pub_key: signature_for_priv_key} if public_key is None: raise ValueError( 'public_key must be provided for signing multisig transactions' ) transaction_without_signatures = transaction.copy() signatures = transaction_without_signatures.pop('signatures') \ if 'signatures' in transaction_without_signatures else [] signatures_updated = signatures.copy() signatures_updated = [ s for s in signatures_updated if not s['public_key'] == public_key ] signatures_updated.append({ 'public_key': public_key, 'signature': private_key.sign( self.serialize(transaction_without_signatures)) }) signed_transaction = transaction.copy() signed_transaction.update({'signatures': signatures_updated}) return signed_transaction
def test_sign_verify(self): message = 'Hello World!' public_key = PublicKey(self.PUBLIC_VALUE_COMPRESSED_B58) private_key = PrivateKey(self.PRIVATE_VALUE_B58) assert public_key.verify(message, private_key.sign(message)) is True
def test_private_key_decode(self): private_value = PrivateKey.decode(self.PRIVATE_VALUE_B58) assert private_value == self.PRIVATE_VALUE
def test_private_key_encode(self): private_value_base58 = PrivateKey.encode(self.PRIVATE_VALUE) assert private_value_base58 == self.PRIVATE_VALUE_B58
def test_generate_key_pair(self): private_value_base58, public_value_compressed_base58 = generate_key_pair() assert PrivateKey.encode( PrivateKey.decode(private_value_base58)) == private_value_base58 assert PublicKey.encode( *PublicKey.decode(public_value_compressed_base58)) == public_value_compressed_base58
def test_sign_verify(self): message = 'Hello World!' public_key = PublicKey(self.PUBLIC_VALUE_COMPRESSED_B58) private_key = PrivateKey(self.PRIVATE_VALUE_B58) assert public_key.verify(message, private_key.sign(message)) == True