From 58b11e683d5c2eacbc1a1670c7604dd21c45aca7 Mon Sep 17 00:00:00 2001 From: KonradStaniec Date: Tue, 14 Sep 2021 13:36:55 +0200 Subject: [PATCH] Implement custom distance function (#827) * Implement custom distance function * More docs about function equivalence --- fluffy/network/state/custom_distance.nim | 32 ++++++++++++++++++++++++ fluffy/tests/all_fluffy_tests.nim | 3 ++- fluffy/tests/test_custom_distance.nim | 30 ++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 fluffy/network/state/custom_distance.nim create mode 100644 fluffy/tests/test_custom_distance.nim diff --git a/fluffy/network/state/custom_distance.nim b/fluffy/network/state/custom_distance.nim new file mode 100644 index 000000000..1c877856a --- /dev/null +++ b/fluffy/network/state/custom_distance.nim @@ -0,0 +1,32 @@ +import stint + +const MID* = u256(2).pow(u256(255)) +const MAX* = high(Uint256) + +# Custom distance function described in: https://notes.ethereum.org/h58LZcqqRRuarxx4etOnGQ#Storage-Layout +# The implementation looks different than in spec, due to the fact that in practice +# we are operating on unsigned 256bit integers instead of signed big ints. +# Thanks to this we do not need to use: +# - modulo operations +# - abs operation +# and the results are eqivalent to function described in spec. +# +# The way it works is as follows. Let say we have integers modulo 8: +# [0, 1, 2, 3, 4, 5, 6, 7] +# and we want to calculate minimal distance between 0 and 5. +# Raw difference is: 5 - 0 = 5, which is larger than mid point which is equal to 4. +# From this we know that the shorter distance is the one wraping around 0, which +# is equal to 3 +proc distance*(node_id: UInt256, content_id: UInt256): UInt256 = + let rawDiff = + if node_id > content_id: + node_id - content_id + else: + content_id - node_id + + if rawDiff > MID: + # If rawDiff is larger than mid this means that distance between node_id and + # content_id is smaller when going from max side. + MAX - rawDiff + UInt256.one + else: + rawDiff diff --git a/fluffy/tests/all_fluffy_tests.nim b/fluffy/tests/all_fluffy_tests.nim index cad531a0a..169a333ea 100644 --- a/fluffy/tests/all_fluffy_tests.nim +++ b/fluffy/tests/all_fluffy_tests.nim @@ -13,7 +13,8 @@ import ./test_portal_encoding, ./test_portal, ./test_content_network, - ./test_discovery_rpc + ./test_discovery_rpc, + ./test_custom_distance cliBuilder: import diff --git a/fluffy/tests/test_custom_distance.nim b/fluffy/tests/test_custom_distance.nim new file mode 100644 index 000000000..afba0daf3 --- /dev/null +++ b/fluffy/tests/test_custom_distance.nim @@ -0,0 +1,30 @@ +# Nimbus - Portal Network +# Copyright (c) 2021 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.used.} + +import + std/unittest, + stint, + ../network/state/custom_distance + + +suite "State network custom distance function": + test "Calculate distance according to spec": + check: + # Test cases from spec + distance(u256(10), u256(10)) == 0 + distance(u256(5), high(UInt256)) == 6 + distance(high(UInt256), u256(6)) == 7 + distance(u256(5), u256(1)) == 4 + distance(u256(1), u256(5)) == 4 + distance(UInt256.zero, MID) == MID + distance(UInt256.zero, MID + UInt256.one) == MID - UInt256.one + + # Additional test cases to check some basic properties + distance(UInt256.zero, MID + MID) == UInt256.zero + distance(UInt256.zero, UInt256.one) == distance(UInt256.zero, high(UInt256))