From e93bf68b641d885d67a26f7b99132afa3c2cbb41 Mon Sep 17 00:00:00 2001 From: Neylix Date: Thu, 24 Mar 2022 01:31:05 +0100 Subject: [PATCH 1/7] Fix GeoPatch algorithm Fixes #253 --- lib/archethic/p2p/geo_patch.ex | 74 ++++++++------------------- test/archethic/p2p/geo_patch_test.exs | 13 +++-- 2 files changed, 29 insertions(+), 58 deletions(-) diff --git a/lib/archethic/p2p/geo_patch.ex b/lib/archethic/p2p/geo_patch.ex index 1f02673b1..be88f91dd 100755 --- a/lib/archethic/p2p/geo_patch.ex +++ b/lib/archethic/p2p/geo_patch.ex @@ -29,68 +29,34 @@ defmodule ArchEthic.P2P.GeoPatch do end defp compute_patch(lat, lon) do - lat_sign = sign(lat) - lon_sign = sign(lon) + lat_pos = (lat + 90) / 11.25 + lon_pos = (lon + 180) / 22.5 - fdc = [lat / 90, lon / 180] + first_digit = main_index_patch(trunc(lat_pos)) + second_digit = main_index_patch(trunc(lon_pos)) - sd = - [(lat - lat_sign * 45) / 2, (lon - lon_sign * 90) / 2] - |> resolve_with_sign([lat, lon]) + lat_precision = ((lat_pos - trunc(lat_pos)) / 0.25) |> trunc() + lon_precision = ((lon_pos - trunc(lon_pos)) / 0.25) |> trunc() - sdc = [List.first(sd) / 22.5, List.last(sd) / 45] + third_digit = precision_index_patch(lat_precision, lon_precision) - td = - [ - (List.first(sd) - lat_sign * 11.25) / 2, - (List.last(sd) - lon_sign * 22.5) / 2 - ] - |> resolve_with_sign(sd) - - tdc = [List.first(td) / 5.625, List.last(td) / 11.25] - - patch = - [index_patch(fdc), index_patch(sdc), index_patch(tdc)] - |> Enum.join("") - - patch + [first_digit, second_digit, third_digit] + |> Enum.join("") end - defp index_patch([f_i, s_i]) when f_i > 0.5 and f_i <= 1 and s_i < -0.5 and s_i >= -1, do: '0' - defp index_patch([f_i, s_i]) when f_i > 0.5 and f_i <= 1 and s_i < 0 and s_i >= -0.5, do: '1' - defp index_patch([f_i, s_i]) when f_i > 0.5 and f_i <= 1 and s_i < 0.5 and s_i >= 0, do: '2' - defp index_patch([f_i, s_i]) when f_i > 0.5 and f_i <= 1 and s_i < 1 and s_i >= 0.5, do: '3' - - defp index_patch([f_i, s_i]) when f_i > 0 and f_i <= 0.5 and s_i < -0.5 and s_i >= -1, do: '4' - defp index_patch([f_i, s_i]) when f_i > 0 and f_i <= 0.5 and s_i < 0 and s_i >= -0.5, do: '5' - defp index_patch([f_i, s_i]) when f_i > 0 and f_i <= 0.5 and s_i < 0.5 and s_i >= 0, do: '6' - defp index_patch([f_i, s_i]) when f_i > 0 and f_i <= 0.5 and s_i < 1 and s_i >= 0.5, do: '7' - - defp index_patch([f_i, s_i]) when f_i > -0.5 and f_i <= 0 and s_i < -0.5 and s_i >= -1, do: '8' - defp index_patch([f_i, s_i]) when f_i > -0.5 and f_i <= 0 and s_i < 0 and s_i >= -0.5, do: '9' - defp index_patch([f_i, s_i]) when f_i > -0.5 and f_i <= 0 and s_i < 0.5 and s_i >= 0, do: 'A' - defp index_patch([f_i, s_i]) when f_i > -0.5 and f_i <= 0 and s_i < 1 and s_i >= 0.5, do: 'B' - - defp index_patch([f_i, s_i]) when f_i > -1 and f_i <= -0.5 and s_i < -0.5 and s_i >= -1, do: 'C' - defp index_patch([f_i, s_i]) when f_i > -1 and f_i <= -0.5 and s_i < 0 and s_i >= -0.5, do: 'D' - defp index_patch([f_i, s_i]) when f_i > -1 and f_i <= -0.5 and s_i < 0.5 and s_i >= 0, do: 'E' - defp index_patch([f_i, s_i]) when f_i > -1 and f_i <= -0.5 and s_i < 1 and s_i >= 0.5, do: 'F' - - defp sign(number) when number < 0, do: -1 - defp sign(number) when number >= 0, do: 1 + defp main_index_patch(index) do + ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7'] + |> Enum.at(index) + end - defp resolve_with_sign([first, second], [first2, second2]) do + defp precision_index_patch(index1, index2) do [ - do_resolve_with_sign(first, first2), - do_resolve_with_sign(second, second2) + ['0', '1', '2', '3'], + ['4', '5', '6', '7'], + ['8', '9', 'A', 'B'], + ['C', 'D', 'E', 'F'] ] - end - - defp do_resolve_with_sign(x1, x2) do - if sign(x1) == sign(x2) do - x1 - else - x2 / 2 - end + |> Enum.at(index1) + |> Enum.at(index2) end end diff --git a/test/archethic/p2p/geo_patch_test.exs b/test/archethic/p2p/geo_patch_test.exs index 13961b474..534ff6c99 100644 --- a/test/archethic/p2p/geo_patch_test.exs +++ b/test/archethic/p2p/geo_patch_test.exs @@ -1,4 +1,9 @@ defmodule ArchEthic.P2P.GeoPatchTest do + @moduledoc """ + This module defines the test case to be used by + geopatch tests. + """ + use ExUnit.Case alias ArchEthic.P2P.GeoPatch @@ -26,9 +31,9 @@ defmodule ArchEthic.P2P.GeoPatchTest do end end) - assert "511" == GeoPatch.from_ip({88, 22, 30, 229}) - assert "500" == GeoPatch.from_ip({161, 235, 112, 33}) - assert "410" == GeoPatch.from_ip({15, 62, 246, 57}) - assert "266" == GeoPatch.from_ip({109, 164, 214, 168}) + assert "3F7" == GeoPatch.from_ip({88, 22, 30, 229}) + assert "3C9" == GeoPatch.from_ip({161, 235, 112, 33}) + assert "3A6" == GeoPatch.from_ip({15, 62, 246, 57}) + assert "401" == GeoPatch.from_ip({109, 164, 214, 168}) end end From 488f8607a02a012d4abf383ff2c9768c99346785 Mon Sep 17 00:00:00 2001 From: Neylix Date: Sun, 3 Apr 2022 22:00:43 +0200 Subject: [PATCH 2/7] Update geo patch calculation --- lib/archethic/p2p/geo_patch.ex | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/archethic/p2p/geo_patch.ex b/lib/archethic/p2p/geo_patch.ex index be88f91dd..74fa58110 100755 --- a/lib/archethic/p2p/geo_patch.ex +++ b/lib/archethic/p2p/geo_patch.ex @@ -24,16 +24,21 @@ defmodule ArchEthic.P2P.GeoPatch do end defp compute_random_patch do - list_char = Enum.concat([?0..?9, ?A..?F]) - Enum.take_random(list_char, 3) |> List.to_string() + list_char1 = Enum.concat([?0..?9, ?A..?F]) + list_char2 = Enum.concat([?0..?3, ?C..?F]) + + Enum.take_random(list_char1, 2) + |> List.insert_at(1, Enum.take_random(list_char2, 1)) + |> List.to_string() end defp compute_patch(lat, lon) do - lat_pos = (lat + 90) / 11.25 lon_pos = (lon + 180) / 22.5 + # Adding 4 to have second digit hex value from C to 3 + lat_pos = (lat + 90) / 22.5 + 4 - first_digit = main_index_patch(trunc(lat_pos)) - second_digit = main_index_patch(trunc(lon_pos)) + first_digit = main_index_patch(trunc(lon_pos)) + second_digit = main_index_patch(trunc(lat_pos)) lat_precision = ((lat_pos - trunc(lat_pos)) / 0.25) |> trunc() lon_precision = ((lon_pos - trunc(lon_pos)) / 0.25) |> trunc() From 094d088deaf806dff45daab86f734c437f049865 Mon Sep 17 00:00:00 2001 From: Neylix Date: Sun, 3 Apr 2022 22:00:58 +0200 Subject: [PATCH 3/7] update geo patch tests --- test/archethic/bootstrap_test.exs | 3 +++ test/archethic/p2p/geo_patch_test.exs | 15 ++++++++++----- test/test_helper.exs | 2 ++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/test/archethic/bootstrap_test.exs b/test/archethic/bootstrap_test.exs index 5c955c4ba..66ad8a349 100644 --- a/test/archethic/bootstrap_test.exs +++ b/test/archethic/bootstrap_test.exs @@ -305,6 +305,9 @@ defmodule ArchEthic.BootstrapTest do MockDB |> stub(:get_first_public_key, fn _ -> first_public_key end) + MockGeoIP + |> stub(:get_coordinates, fn {200, 50, 20, 10} -> {0.0, 0.0} end) + assert :ok = Bootstrap.run( {200, 50, 20, 10}, diff --git a/test/archethic/p2p/geo_patch_test.exs b/test/archethic/p2p/geo_patch_test.exs index 534ff6c99..247d81898 100644 --- a/test/archethic/p2p/geo_patch_test.exs +++ b/test/archethic/p2p/geo_patch_test.exs @@ -11,7 +11,7 @@ defmodule ArchEthic.P2P.GeoPatchTest do import Mox test "from_ip/1 should compute patch from coordinates" do - expect(MockGeoIP, :get_coordinates, fn ip -> + stub(MockGeoIP, :get_coordinates, fn ip -> case ip do # Spain (Alicante) {88, 22, 30, 229} -> @@ -28,12 +28,17 @@ defmodule ArchEthic.P2P.GeoPatchTest do # Switzerland (Zurich) {109, 164, 214, 168} -> {47.366670, 8.550000} + + # Edge value + {1, 2, 3, 4} -> + {-45.0, 0.0} end end) - assert "3F7" == GeoPatch.from_ip({88, 22, 30, 229}) - assert "3C9" == GeoPatch.from_ip({161, 235, 112, 33}) - assert "3A6" == GeoPatch.from_ip({15, 62, 246, 57}) - assert "401" == GeoPatch.from_ip({109, 164, 214, 168}) + assert "F1B" == GeoPatch.from_ip({88, 22, 30, 229}) + assert "C1D" == GeoPatch.from_ip({161, 235, 112, 33}) + assert "A1A" == GeoPatch.from_ip({15, 62, 246, 57}) + assert "021" == GeoPatch.from_ip({109, 164, 214, 168}) + assert "0E0" == GeoPatch.from_ip({1, 2, 3, 4}) end end diff --git a/test/test_helper.exs b/test/test_helper.exs index bbc2136de..443bbd494 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -17,3 +17,5 @@ Mox.defmock(MockGeoIP, for: ArchEthic.P2P.GeoPatch.GeoIP) Mox.defmock(MockUCOPriceProvider, for: ArchEthic.OracleChain.Services.UCOPrice.Providers.Impl) Mox.defmock(MockMetricsCollector, for: ArchEthic.Metrics.Collector) + +Application.put_env(:archethic, ArchEthic.P2P.GeoPatch.GeoIP, MockGeoIP) From 98965359b5321421fc1e918c31098b78a476cd53 Mon Sep 17 00:00:00 2001 From: Neylix Date: Mon, 4 Apr 2022 12:24:32 +0200 Subject: [PATCH 4/7] Switch env value to config --- config/test.exs | 1 + test/test_helper.exs | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/config/test.exs b/config/test.exs index aaa907a74..1f6c7db04 100755 --- a/config/test.exs +++ b/config/test.exs @@ -98,6 +98,7 @@ config :archethic, ArchEthic.P2P.Listener, enabled: false config :archethic, ArchEthic.P2P.MemTableLoader, enabled: false config :archethic, ArchEthic.P2P.MemTable, enabled: false config :archethic, ArchEthic.P2P.Client, MockClient +config :archethic, ArchEthic.P2P.GeoPatch.GeoIP, MockGeoIP config :archethic, ArchEthic.P2P.BootstrappingSeeds, enabled: false diff --git a/test/test_helper.exs b/test/test_helper.exs index 443bbd494..bbc2136de 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -17,5 +17,3 @@ Mox.defmock(MockGeoIP, for: ArchEthic.P2P.GeoPatch.GeoIP) Mox.defmock(MockUCOPriceProvider, for: ArchEthic.OracleChain.Services.UCOPrice.Providers.Impl) Mox.defmock(MockMetricsCollector, for: ArchEthic.Metrics.Collector) - -Application.put_env(:archethic, ArchEthic.P2P.GeoPatch.GeoIP, MockGeoIP) From e5b0d04b550e2ad631b156869f8524d3d34aeb6e Mon Sep 17 00:00:00 2001 From: Neylix Date: Wed, 6 Apr 2022 01:49:31 +0200 Subject: [PATCH 5/7] Correct out of bound index --- lib/archethic/p2p/geo_patch.ex | 4 ++++ test/archethic/p2p/geo_patch_test.exs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/archethic/p2p/geo_patch.ex b/lib/archethic/p2p/geo_patch.ex index 74fa58110..0f2867476 100755 --- a/lib/archethic/p2p/geo_patch.ex +++ b/lib/archethic/p2p/geo_patch.ex @@ -33,6 +33,10 @@ defmodule ArchEthic.P2P.GeoPatch do end defp compute_patch(lat, lon) do + # convert 90 and 180 to -90 and -180 to not get an out of bound index for array + lat = if(lat == 90, do: -90) || lat + lon = if(lon == 180, do: -180) || lon + lon_pos = (lon + 180) / 22.5 # Adding 4 to have second digit hex value from C to 3 lat_pos = (lat + 90) / 22.5 + 4 diff --git a/test/archethic/p2p/geo_patch_test.exs b/test/archethic/p2p/geo_patch_test.exs index 247d81898..7fb5cd6fb 100644 --- a/test/archethic/p2p/geo_patch_test.exs +++ b/test/archethic/p2p/geo_patch_test.exs @@ -31,7 +31,7 @@ defmodule ArchEthic.P2P.GeoPatchTest do # Edge value {1, 2, 3, 4} -> - {-45.0, 0.0} + {90, 180} end end) @@ -39,6 +39,6 @@ defmodule ArchEthic.P2P.GeoPatchTest do assert "C1D" == GeoPatch.from_ip({161, 235, 112, 33}) assert "A1A" == GeoPatch.from_ip({15, 62, 246, 57}) assert "021" == GeoPatch.from_ip({109, 164, 214, 168}) - assert "0E0" == GeoPatch.from_ip({1, 2, 3, 4}) + assert "8C0" == GeoPatch.from_ip({1, 2, 3, 4}) end end From 7e67cde67df208a0a3b601f047562aef0008dfd8 Mon Sep 17 00:00:00 2001 From: Neylix Date: Thu, 7 Apr 2022 17:23:41 +0200 Subject: [PATCH 6/7] Convert list to tuple to improve execution time --- lib/archethic/p2p/geo_patch.ex | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/archethic/p2p/geo_patch.ex b/lib/archethic/p2p/geo_patch.ex index 0f2867476..19d32c92e 100755 --- a/lib/archethic/p2p/geo_patch.ex +++ b/lib/archethic/p2p/geo_patch.ex @@ -33,7 +33,7 @@ defmodule ArchEthic.P2P.GeoPatch do end defp compute_patch(lat, lon) do - # convert 90 and 180 to -90 and -180 to not get an out of bound index for array + # convert 90 and 180 to -90 and -180 to not get an out of bound index lat = if(lat == 90, do: -90) || lat lon = if(lon == 180, do: -180) || lon @@ -54,18 +54,18 @@ defmodule ArchEthic.P2P.GeoPatch do end defp main_index_patch(index) do - ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7'] - |> Enum.at(index) + {'8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7'} + |> elem(index) end defp precision_index_patch(index1, index2) do - [ - ['0', '1', '2', '3'], - ['4', '5', '6', '7'], - ['8', '9', 'A', 'B'], - ['C', 'D', 'E', 'F'] - ] - |> Enum.at(index1) - |> Enum.at(index2) + { + {'0', '1', '2', '3'}, + {'4', '5', '6', '7'}, + {'8', '9', 'A', 'B'}, + {'C', 'D', 'E', 'F'} + } + |> elem(index1) + |> elem(index2) end end From 6b722f96158c05f53b0075a45d922c15645ca408 Mon Sep 17 00:00:00 2001 From: Neylix Date: Fri, 8 Apr 2022 11:35:06 +0200 Subject: [PATCH 7/7] Add near location city in test --- test/archethic/p2p/geo_patch_test.exs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/archethic/p2p/geo_patch_test.exs b/test/archethic/p2p/geo_patch_test.exs index 7fb5cd6fb..8bb2aa995 100644 --- a/test/archethic/p2p/geo_patch_test.exs +++ b/test/archethic/p2p/geo_patch_test.exs @@ -32,6 +32,22 @@ defmodule ArchEthic.P2P.GeoPatchTest do # Edge value {1, 2, 3, 4} -> {90, 180} + + # France (Bordeaux) + {1, 1, 1, 1} -> + {44.828114, -0.584424} + + # France (Limoges) + {2, 2, 2, 2} -> + {45.819792, 1.256239} + + # US (Las Vegas) + {3, 3, 3, 3} -> + {36.165362, -115.102552} + + # US (Phoenix) + {4, 4, 4, 4} -> + {33.456609, -112.033383} end end) @@ -40,5 +56,9 @@ defmodule ArchEthic.P2P.GeoPatchTest do assert "A1A" == GeoPatch.from_ip({15, 62, 246, 57}) assert "021" == GeoPatch.from_ip({109, 164, 214, 168}) assert "8C0" == GeoPatch.from_ip({1, 2, 3, 4}) + assert "F1F" == GeoPatch.from_ip({1, 1, 1, 1}) + assert "020" == GeoPatch.from_ip({2, 2, 2, 2}) + assert "A1B" == GeoPatch.from_ip({3, 3, 3, 3}) + assert "B14" == GeoPatch.from_ip({4, 4, 4, 4}) end end