def test_fake_ownership(self): # Trying to spend someone else's output # (Re)Starting from GenBlock genesis_block = classes.GenesisBlock(self.address) fullnode_api.add_genesis_block(genesis_block) # Tx1 -> We send it to an address belonging to seed dict_of_inputs = {genesis_block.block_content[0].txhash: 0} dict_of_outputs = {self.address: 100} first_tx = classes.Transaction(dict_of_inputs, dict_of_outputs) first_tx.sign(self.seed) # Block1 first_block = classes.Block([first_tx]) first_mined_block = fullnode_api.mine_block(first_block) fullnode_api.add_block_to_db(first_mined_block) # Tx2 -> we try to spend someone else's output since we sign with seed2 dict_of_inputs2 = {first_mined_block.block_content[0].txhash: 0} dict_of_outputs2 = {self.address3: 100} second_tx = classes.Transaction(dict_of_inputs2, dict_of_outputs2) second_tx.sign(self.seed2) # Block2 second_block = classes.Block([second_tx]) second_mined_block = fullnode_api.mine_block(second_block) fullnode_api.add_block_to_db(second_mined_block) with self.assertRaises(exceptions.ValidationError): validation.validate_block(second_mined_block)
def test_wrong_input(self): # Trying to spend inexistant input # (Re)Starting from GenBlock genesis_block = classes.GenesisBlock(self.address) fullnode_api.add_genesis_block(genesis_block) # Tx1 dict_of_inputs = {genesis_block.block_content[0].txhash: 0} dict_of_outputs = {self.address2: 100} first_tx = classes.Transaction(dict_of_inputs, dict_of_outputs) first_tx.sign(self.seed) # Block1 first_block = classes.Block([first_tx]) first_mined_block = fullnode_api.mine_block(first_block) fullnode_api.add_block_to_db(first_mined_block) # Tx2 -> we try to spend an unexisting input dict_of_inputs2 = {first_mined_block.block_content[0].txhash: 1} dict_of_outputs2 = {self.address3: 100} second_tx = classes.Transaction(dict_of_inputs2, dict_of_outputs2) second_tx.sign(self.seed2) # Block2 second_block = classes.Block([second_tx]) second_mined_block = fullnode_api.mine_block(second_block) fullnode_api.add_block_to_db(second_mined_block) with self.assertRaises( exceptions.APIError ): # Since the exceptions comes from one level deeper. validation.validate_block(second_mined_block)
def test_incorrect_amounts(self): # Trying to spend more than what we have in the inputs # (Re)Starting from GenBlock genesis_block = classes.GenesisBlock(self.address) fullnode_api.add_genesis_block(genesis_block) # Tx1 dict_of_inputs = {genesis_block.block_content[0].txhash: 0} dict_of_outputs = {self.address2: 100} first_tx = classes.Transaction(dict_of_inputs, dict_of_outputs) first_tx.sign(self.seed) # Block1 first_block = classes.Block([first_tx]) first_mined_block = fullnode_api.mine_block(first_block) fullnode_api.add_block_to_db(first_mined_block) # Tx2 -> We try to put 101 as output amount dict_of_inputs2 = {first_mined_block.block_content[0].txhash: 0} dict_of_outputs2 = {self.address3: 101} second_tx = classes.Transaction(dict_of_inputs2, dict_of_outputs2) second_tx.sign(self.seed2) # Block2 second_block = classes.Block([second_tx]) second_mined_block = fullnode_api.mine_block(second_block) fullnode_api.add_block_to_db(second_mined_block) with self.assertRaises(exceptions.ValidationError): validation.validate_block(second_mined_block)
def setUp(self): # Seed&Address (2 pairs) self.seed = crypto.new_seed() self.address = crypto.get_address(self.seed) self.verifying_key_string = crypto._get_verifying_key_string(self.seed) self.seed2 = crypto.new_seed() self.address2 = crypto.get_address(self.seed2) self.verifying_key_string2 = crypto._get_verifying_key_string( self.seed2) self.address3 = self.address2 # For testing purposes only # Db self.db_path = 'database/db_test' database.init_database_path(self.db_path) # GenBlock self.genesis_block = classes.GenesisBlock(self.address) fullnode_api.add_genesis_block(self.genesis_block) # Tx1 self.dict_of_inputs = {self.genesis_block.block_content[0].txhash: 0} self.dict_of_outputs = {self.address2: 100} self.first_tx = classes.Transaction(self.dict_of_inputs, self.dict_of_outputs) self.first_tx.sign(self.seed) # Block1 self.first_block = classes.Block([self.first_tx]) self.first_mined_block = fullnode_api.mine_block(self.first_block) fullnode_api.add_block_to_db(self.first_mined_block) # Tx2 self.dict_of_inputs2 = { self.first_mined_block.block_content[0].txhash: 0 } self.dict_of_outputs2 = {self.address3: 100} self.second_tx = classes.Transaction(self.dict_of_inputs2, self.dict_of_outputs2) self.second_tx.sign(self.seed2) # Block2 self.second_block = classes.Block([self.second_tx]) self.second_mined_block = fullnode_api.mine_block(self.second_block) fullnode_api.add_block_to_db(self.second_mined_block)
def test_transaction_signing(self): first_tx = classes.Transaction(self.dict_of_inputs, self.dict_of_outputs) first_tx.sign(self.seed) self.assertTrue( crypto.verify_signing(first_tx.txhash, first_tx.signature, first_tx.verifying_key))
def test_double_spend(self): # (Re)Starting from GenBlock genesis_block = classes.GenesisBlock(self.address) fullnode_api.add_genesis_block(genesis_block) # Tx1 dict_of_inputs = {genesis_block.block_content[0].txhash: 0} dict_of_outputs = {self.address2: 100} first_tx = classes.Transaction(dict_of_inputs, dict_of_outputs) first_tx.sign(self.seed) # Block1 first_block = classes.Block([first_tx]) first_mined_block = fullnode_api.mine_block(first_block) fullnode_api.add_block_to_db(first_mined_block) # Tx2 dict_of_inputs2 = {first_mined_block.block_content[0].txhash: 0} dict_of_outputs2 = {self.address3: 100} second_tx = classes.Transaction(dict_of_inputs2, dict_of_outputs2) second_tx.sign(self.seed2) # Block2 second_block = classes.Block([second_tx]) second_mined_block = fullnode_api.mine_block(second_block) fullnode_api.add_block_to_db(second_mined_block) # Tx3 -> We try to double spend the same input as we spent in the previous block dict_of_inputs3 = {first_mined_block.block_content[0].txhash: 0} dict_of_outputs3 = {self.address3: 100} third_tx = classes.Transaction(dict_of_inputs3, dict_of_outputs3) third_tx.sign(self.seed2) third_block = classes.Block([third_tx]) third_mined_block = fullnode_api.mine_block(third_block) with self.assertRaises(exceptions.ValidationError): validation.validate_block(third_mined_block)
def create_transaction(from_address, to_address, amount=0): """Creates an unsigned transaction. If amount=0, it spends everything. If not everything is spend, returns the remainder to the sender.""" global stack_of_used_inputs valid_inputs_list = get_valid_inputs_from_address(from_address) balance = get_balance_from_address(from_address) dict_of_inputs = {} dict_of_outputs = {} if amount == 0: # We spend everything for inpt in valid_inputs_list: dict_of_inputs[inpt[0]] = inpt[1] dict_of_outputs[to_address] = amount if balance == amount: # We spend everything for inpt in valid_inputs_list: dict_of_inputs[inpt[0]] = inpt[1] dict_of_outputs[to_address] = amount if balance > amount: # We return part of the amount to the sender for inpt in valid_inputs_list: dict_of_inputs[inpt[0]] = inpt[ 1] # Even when not spending all the balance, we burn all the inputs dict_of_outputs[to_address] = amount dict_of_outputs[from_address] = balance - amount if balance < amount: raise exceptions.APIError( "Balance of address not sufficient to create transaction") for txhash, pos in dict_of_inputs.items( ): # We update the local state of the ledger to include the new tx. stack_of_used_inputs.append((txhash, pos)) if not dict_of_inputs: raise exceptions.APIError( "Trying to create a transaction with no inputs.") return classes.Transaction(dict_of_inputs, dict_of_outputs)