def setUp(self): self.private_key = SigningKey.generate() self.public_keys = tuple(PublicKey.from_signing_key(SigningKey.generate()) for _ in range(2)) self.operation = Operation(OperationRev(), 'http://example.com', self.public_keys) sign_object(PublicKey.from_signing_key(self.private_key), self.private_key, self.operation) self.uuid = self.operation.uuid self.identifier = Identifier.from_operation(self.operation)
def test_delete_blocks(self): blocks = self.add_blocks(self.add_operations()) bc = get_blockchain() with patch.object(BlockChain, '_get_new_blocks', return_value=blocks): bc.update_blocks() with self.assertRaisesRegex(Block.ChainOperationBlockedError, "can't remove: blocked by another block"): blocks[4].remove() self.assertEqual(bc.max_depth, 5) self.assertEqual(bc.head, blocks[5].id) for block_to_remove, max_depth, heads in ( (blocks[5], 5, [blocks[6].id]), (blocks[6], 4, [blocks[3].id, blocks[4].id]), (blocks[4], 4, [blocks[3].id]), (blocks[3], 3, [blocks[2].id]), (blocks[2], 2, [blocks[1].id]), (blocks[1], 1, [blocks[0].id]), (blocks[0], 0, [BlockRev().id]) ): block_to_remove.remove() self.assertEqual(bc.max_depth, max_depth) self.assertIn(bc.head, heads) with patch.object(BlockChain, '_get_new_blocks', return_value=blocks): bc.update_blocks() self.assertEqual(bc.max_depth, 5) self.assertEqual(bc.head, blocks[5].id) self.assertCountEqual([op.uuid for op in blocks[0].operations + blocks[2].operations[1:2]], Identifier.get_uuid_list())
def test_no_database(self): with self.assertRaisesRegex(pmpi.database.Database.InitialisationError, "initialise database first"): Identifier.get_uuid_list() with self.assertRaisesRegex(pmpi.database.Database.InitialisationError, "initialise database first"): Identifier.get(uuid4()) operation = Operation(OperationRev(), 'http://example.com/', []) sk = SigningKey.generate() sign_object(PublicKey.from_signing_key(sk), sk, operation) identifier = Identifier.from_operation(operation) with self.assertRaisesRegex(pmpi.database.Database.InitialisationError, "initialise database first"): identifier.put() with self.assertRaisesRegex(pmpi.database.Database.InitialisationError, "initialise database first"): identifier.remove()
def test_2_put_remove(self): for identifier in self.identifiers: identifier.put() uuid_list = Identifier.get_uuid_list() self.assertEqual(len(uuid_list), 2) self.assertCountEqual(uuid_list, [identifier.uuid for identifier in self.identifiers]) for identifier in self.identifiers: new_id = Identifier.get(identifier.uuid) self.assertEqual(new_id.uuid, identifier.uuid) self.assertEqual(new_id.operation_rev, identifier.operation_rev) self.identifiers[0].remove() with self.assertRaises(Identifier.DoesNotExist): self.identifiers[0].remove() # already removed identifier self.assertCountEqual(Identifier.get_uuid_list(), [self.identifiers[1].uuid]) with self.assertRaises(Identifier.DoesNotExist): Identifier.get(self.identifiers[0].uuid)
def __set_head(self, new_head_id): lca_id = self.__lowest_common_ancestor(self.head, new_head_id) blocks_after_lca = self.backward_blocks_chain(self.head, lca_id)[:-1] for identifier in [Identifier.get(uuid) for uuid in Identifier.get_uuid_list()]: op = identifier.operation_rev.obj containing_blocks = list(filter(lambda bl: bl in blocks_after_lca, op.containing_blocks)) if len(containing_blocks) == 1: while len(containing_blocks) == 1: # while operation is in a block that belongs to path to the LCA op = op.previous_operation_rev.obj if op is not None: containing_blocks = list(filter(lambda bl: bl in blocks_after_lca, op.containing_blocks)) else: break identifier.remove() if op is not None: identifier.operation_rev = op.get_rev() identifier.put() for block_id in reversed(self.backward_blocks_chain(new_head_id, lca_id)[:-1]): for op in pmpi.block.Block.get(block_id).operations: try: identifier = Identifier.get(op.uuid) if identifier.operation_rev == op.previous_operation_rev: identifier.remove() identifier.operation_rev = op.get_rev() identifier.put() else: raise self.TreeError("inconsistency of operations") except Identifier.DoesNotExist: if op.previous_operation_rev.is_none(): Identifier(op.uuid, op.get_rev()).put() else: raise self.TreeError("multiple minting of the identifier") self.__head = new_head_id
def new_operation(self): print("Choose UUID:") uuids_number = self.show_uuids() print('\n {}) mint new uuid'.format(uuids_number)) def send_operation(operation): self.user.sign_object(operation) x = None while x not in ('y', 'n'): x = input("Send operation? (y/n) ") if x == 'y': self.transport.write(b'OP' + operation.raw()) # TODO also -- length of operation? try: x = int(input("index=")) if x < uuids_number: uuid = Identifier.get_uuid_list()[x] operation = Identifier.get(uuid).operation_rev.obj if self.user._public_key.der not in operation.owners_der: print("You do not own this identifier!") return # TODO show sth address = input("address=") # TODO owners choose owners send_operation(Operation(operation.get_rev(), address, [self.user._public_key])) elif x == uuids_number: address = input("address=") # TODO owners choose owners send_operation(Operation(OperationRev(), address, [self.user._public_key])) else: print("Wrong number.") except ValueError: print("Value Error, aborting.")
def setUp(self): initialise_database('test_database_file') self.operations = [ Operation(OperationRev(), 'http://example.com/' + url, [PublicKey.from_signing_key(SigningKey.generate())]) for url in ('first/', 'second/')] for op in self.operations: sk = SigningKey.generate() sign_object(PublicKey.from_signing_key(sk), sk, op) block = Block.from_operations_list(BlockRev(), 42, self.operations) block.mine() sk = SigningKey.generate() sign_object(PublicKey.from_signing_key(sk), sk, block) block.put() self.identifiers = [Identifier.from_operation(op) for op in self.operations]
def test(): initialise_database('test_database_file') private_keys = [SigningKey.generate() for _ in range(3)] public_keys = [PublicKey.from_signing_key(private_key) for private_key in private_keys] uuids = [uuid4() for _ in range(3)] # BUILD # blocks = add_blocks() # # for block in blocks: # block.put() # # block_chain = BlockChain() # # block_chain_records_pattern = [ # BlockChain.Record(1, b'\x00'*32, [blocks[1].id]), # BlockChain.Record(2, blocks[0].id, [blocks[2].id]), # BlockChain.Record(3, blocks[1].id, sorted([blocks[3].id, blocks[4].id])), # BlockChain.Record(4, blocks[2].id, [blocks[5].id]), # BlockChain.Record(4, blocks[2].id, [blocks[6].id]), # BlockChain.Record(5, blocks[3].id, []), # BlockChain.Record(5, blocks[4].id, []) # ] # # for i in range(6): # assertEqual(block_chain.get(blocks[i].id), block_chain_records_pattern[i]) # UPDATE BLOCKS # blocks = add_blocks() # bc = get_blockchain() # # with patch.object(BlockChain, '_get_new_blocks', return_value=blocks): # bc.update_blocks() # # assertEqual(bc.max_depth, 5) # assertEqual(bc.head, blocks[5].id) # # for block in blocks: # assertEqual(bc.get(block.id).previous_id, block.previous_block_rev.id) # MULTIPLE UPDATE BLOCKS # blocks = add_blocks() # bc = get_blockchain() # # def patched_update_blocks(block_list): # with patch.object(BlockChain, '_get_new_blocks', return_value=block_list): # bc.update_blocks() # # for blocks_to_add, max_depth, head in ( # (blocks[0:2], 2, blocks[1].id), # (blocks[2:3], 3, blocks[2].id), # (blocks[4:5], 4, blocks[4].id), # (blocks[3:4], 4, blocks[4].id), # (blocks[5:6], 5, blocks[5].id), # (blocks[6:7], 5, blocks[5].id) # ): # patched_update_blocks(blocks_to_add) # assertEqual(bc.max_depth, max_depth) # assertEqual(bc.head, head) # DELETE blocks = add_blocks(uuids, private_keys, public_keys) bc = get_blockchain() with patch.object(BlockChain, '_get_new_blocks', return_value=blocks): bc.update_blocks() try: blocks[4].remove() raise AssertionError except Block.ChainOperationBlockedError: pass assert bc.max_depth == 5 assert bc.head == blocks[5].id for block_to_remove, max_depth, heads in ( (blocks[5], 5, [blocks[6].id]), (blocks[6], 4, [blocks[3].id, blocks[4].id]), (blocks[4], 4, [blocks[3].id]), (blocks[3], 3, [blocks[2].id]), (blocks[2], 2, [blocks[1].id]), (blocks[1], 1, [blocks[0].id]), (blocks[0], 0, [BlockRev().id]) ): block_to_remove.remove() assert bc.max_depth == max_depth assert bc.head in heads with patch.object(BlockChain, '_get_new_blocks', return_value=blocks): bc.update_blocks() assert bc.max_depth == 5 assert bc.head == blocks[5].id assert sorted([op.uuid for op in blocks[0].operations + blocks[2].operations[1:2]]) == sorted( Identifier.get_uuid_list()) close_database() os.remove('test_database_file')
def test_1_get_from_empty(self): with self.assertRaises(Identifier.DoesNotExist): Identifier.get(self.identifiers[0].uuid)
def test_0_empty(self): self.assertEqual(len(Identifier.get_uuid_list()), 0)
def show_uuids(): uuid_list = Identifier.get_uuid_list() digits = len(str(len(uuid_list))) for index, identifier in enumerate(Identifier.get_uuid_list()): print("{}) {} | {}".format(str(index).rjust(digits), identifier, Identifier.get(identifier).operation_rev.obj.address)) return len(uuid_list)