Skip to content

Commit

Permalink
Fix remote updating channel node with type change
Browse files Browse the repository at this point in the history
  • Loading branch information
ichorid authored and devos50 committed Sep 18, 2020
1 parent 9edbcca commit b31f5c8
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ def update_properties(self, update_dict):
updated_self.delete(recursive=False)
self_dict.pop("rowid")
self_dict.pop("metadata_type")
self_dict.pop("timestamp")
self_dict['infohash'] = random_infohash()
self_dict["sign_with"] = self._my_key
updated_self = db.ChannelMetadata.from_dict(self_dict)
Expand Down
29 changes: 26 additions & 3 deletions src/tribler-core/tribler_core/modules/metadata_store/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,9 +459,32 @@ def check_update_opportunity():
node = self.ChannelNode.get_for_update(public_key=database_blob(payload.public_key), id_=payload.id_)
if node:
if node.timestamp < payload.timestamp:
node.set(**payload.to_dict())
result.append((node, UPDATED_OUR_VERSION))
return result
# Workaround for a corner case of remote change of md type.
# We delete the original node and replace it with the updated one
if node.metadata_type != payload.metadata_type:
if payload.metadata_type == REGULAR_TORRENT:
node.delete()
renewed_node = self.TorrentMetadata.from_payload(payload)
elif payload.metadata_type == CHANNEL_TORRENT:
node.delete()
renewed_node = self.ChannelMetadata.from_payload(payload)
elif payload.metadata_type == COLLECTION_NODE:
node.delete()
renewed_node = self.CollectionNode.from_payload(payload)
else:
self._logger.warning(
f"Tried to update channel node to illegal type: "
f" original type: {node.metadata_type}"
f" updated type: {payload.metadata_type}"
f" {hexlify(payload.public_key)}, {payload.id_} "
)
return result
result.append((renewed_node, UPDATED_OUR_VERSION))
return result
else:
node.set(**payload.to_dict())
result.append((node, UPDATED_OUR_VERSION))
return result
elif node.timestamp > payload.timestamp:
result.append((node, GOT_NEWER_VERSION))
return result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from tribler_core.modules.metadata_store.orm_bindings.channel_metadata import CHANNEL_DIR_NAME_LENGTH, entries_to_chunk
from tribler_core.modules.metadata_store.orm_bindings.channel_node import NEW
from tribler_core.modules.metadata_store.serialization import (
CHANNEL_TORRENT,
ChannelMetadataPayload,
DeletedMetadataPayload,
SignedPayload,
Expand All @@ -39,6 +40,13 @@
)


def get_payloads(entity_class):
c = entity_class(infohash=database_blob(random_infohash()))
payload = c._payload_class.from_signed_blob(c.serialized())
deleted_payload = DeletedMetadataPayload.from_signed_blob(c.serialized_delete())
return c, payload, deleted_payload


def make_wrong_payload(filename):
key = default_eccrypto.generate_key(u"curve25519")
metadata_payload = SignedPayload(
Expand Down Expand Up @@ -245,11 +253,6 @@ def test_process_channel_dir(self):

@db_session
def test_process_payload(self):
def get_payloads(entity_class):
c = entity_class(infohash=database_blob(random_infohash()))
payload = c._payload_class.from_signed_blob(c.serialized())
deleted_payload = DeletedMetadataPayload.from_signed_blob(c.serialized_delete())
return c, payload, deleted_payload

_, node_payload, node_deleted_payload = get_payloads(self.mds.ChannelNode)

Expand Down Expand Up @@ -278,6 +281,24 @@ def get_payloads(entity_class):
self.assertEqual(UNKNOWN_CHANNEL, result[0][1])
self.assertEqual(node_dict['metadata_type'], result[0][0].to_dict()['metadata_type'])

@db_session
def test_process_payload_update_type(self):
# Check if applying class-changing update to an entry works
# First, create a node and get a payload from it, then update it to another type, then get payload
# for the updated version, then delete the updated version, then bring back the original one by processing it,
# then try processing the payload of updated version and see if it works. Phew!
node, node_payload, node_deleted_payload = get_payloads(self.mds.CollectionNode)
updated_node = node.update_properties(
{"origin_id": 0}
) # This will implicitly change the node to ChannelTorrent
self.assertEqual(updated_node.metadata_type, CHANNEL_TORRENT)
updated_node_payload = updated_node._payload_class.from_signed_blob(updated_node.serialized())
updated_node.delete()

old_node, _ = self.mds.process_payload(node_payload, skip_personal_metadata_payload=False)[0]
updated_node2, _ = self.mds.process_payload(updated_node_payload, skip_personal_metadata_payload=False)[0]
self.assertEqual(updated_node2.metadata_type, CHANNEL_TORRENT)

@db_session
def test_process_payload_ffa(self):
infohash = b"1" * 20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,10 @@ def test_update_properties(self):
Test the updating of several properties of a TorrentMetadata object
"""
metadata = self.mds.TorrentMetadata(title='foo', infohash=random_infohash())
orig_timestamp = metadata.timestamp

# Test updating the status only
self.assertEqual(metadata.update_properties({"status": 456}).status, 456)
self.assertEqual(orig_timestamp, metadata.timestamp)
self.assertEqual(metadata.update_properties({"title": "bar"}).title, "bar")
self.assertLess(orig_timestamp, metadata.timestamp)

0 comments on commit b31f5c8

Please sign in to comment.