LCOV - code coverage report
Current view: top level - flamenco/runtime/program/vote - fd_validator_location.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 24 24 100.0 %
Date: 2026-11-12 04:25:03 Functions: 13 672 1.9 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_program_vote_fd_validator_location_h
       2             : #define HEADER_fd_src_flamenco_runtime_program_vote_fd_validator_location_h
       3             : 
       4             : #include "../../../fd_flamenco_base.h"
       5             : 
       6             : /* fd_validator_location_t is the self-reported location of a
       7             :    validator, as described in SIMD-0674.
       8             : 
       9             :    A location is a WGS84 ECEF "Earth-Centered, Earth-Fixed" point
      10             :    in meters, measured from the center of the Earth. See
      11             :    https://en.wikipedia.org/wiki/Earth-centered,_Earth-fixed_coordinate_system
      12             : 
      13             :                   +z (North Pole)
      14             :                    |
      15             :                    |    . (x,y,z)
      16             :                    |   /
      17             :                    |  /
      18             :                    O------------ +y (equator, 90E)
      19             :                   /
      20             :                  /
      21             :                +x (equator, 0E)
      22             : 
      23             :    Validators are required to report the ECEF point on the Earth's
      24             :    surface directly below them, about 6400km from the center.  Their
      25             :    height above the surface should be set to 0:
      26             : 
      27             :                validator
      28             :                    o
      29             :                    |   height h (= 0)
      30             :          ----------*----------  the Earth's surface
      31             :                    ^
      32             :                    reported location
      33             : 
      34             :    To get this point:
      35             : 
      36             :      1. Look up the validator's latitude and longitude.
      37             :      2. Convert them to (x,y,z) with height h = 0, using a GPS library
      38             :         or an online converter such as
      39             :         https://geodesy.noaa.gov/TOOLS/XYZ/xyz.shtml
      40             :      3. Round x, y and z to the nearest meter.
      41             : 
      42             :    The conversion with h = 0:
      43             :      N = r / sqrt( 1 - e2*sin(lat)^2 )      r  = 6378137
      44             :                                             e2 = 0.00669437999014
      45             :      x = round( (N+h)        * cos(lat) * cos(lon) )
      46             :      y = round( (N+h)        * cos(lat) * sin(lon) )
      47             :      z = round( (N*(1-e2)+h) * sin(lat) )
      48             : 
      49             :    Frankfurt (50.11N, 8.68E) is (4051542, 618526, 4870645).
      50             : 
      51             :    See below for how we validate that the ECEF point reported is a
      52             :    valid point on the Earth's surface. */
      53             : 
      54             : struct fd_validator_location {
      55             :   int x;
      56             :   int y;
      57             :   int z;
      58             : };
      59             : typedef struct fd_validator_location fd_validator_location_t;
      60             : 
      61             : /* A self-reported location is valid if it describes a point on the
      62             :    Earth's surface (not above - in space - or below - underground).
      63             :    Here the Earth's surface is defined as being the WGS84 ellipsoid,
      64             :    which is roughly sea level. The criteria for checking this are
      65             :    defined in SIMD-0674 and explained below.
      66             : 
      67             :    The Earth is not a perfect sphere, but slightly flattened. It is
      68             :    about 43km wider at the equator than at the poles.
      69             :    Cut in half through the poles:
      70             : 
      71             :                                z
      72             :                                |
      73             :              +-----------------+-----------------+  <- COORD_MAX
      74             :              |        ..--'''''|'''''--..        |
      75             :              |    .-''         b         ''-.    |
      76             :              |  .'             |             '.  |
      77             :              | /               |               \ |
      78             :         -----+-----------------O-------r-------+-----> x, y
      79             :              | \               |               / |
      80             :              |  '.             |             .'  |
      81             :              |    '-..         |         ..-'    |
      82             :              |        ''--.....|.....--''        |
      83             :              +-----------------+-----------------+
      84             : 
      85             :      r = 6378137m, the radius at the equator
      86             :      b = 6356752m, the radius at the poles
      87             : 
      88             :    To check that a location is indeed a point on the Earth's surface,
      89             :    we don't want to do floating point trigonometry, so we instead
      90             :    stretch the Earth into a perfect sphere, and then a simple integer
      91             :    magnitude check works for all points:
      92             :    - Stretch z slightly (FLATTENING_CORRECTION), which turns the
      93             :      flattened Earth into an almost perfect sphere of radius r.
      94             :    - Check that the stretched point is within a +-1km SURFACE_TOLERANCE
      95             :      above or below the Earth's surface (SURFACE_DIST2).
      96             : 
      97             :          too low                 valid                too high
      98             :        <---------|=================|=================|--------->  dist2
      99             :            SURFACE_DIST2     SURFACE_DIST2     SURFACE_DIST2
     100             :         - SURFACE_TOLERANCE                 + SURFACE_TOLERANCE
     101             :              1km below          ground           1km above
     102             : 
     103             :    Example: Frankfurt is at (4051542, 618526, 4870645).  Every
     104             :    coordinate is within COORD_MAX (6378138), and:
     105             : 
     106             :        x^2                                   16414992577764
     107             :      + y^2                                     382574412676
     108             :      + z^2                                   23723182716025
     109             :      + (FLATTENING_CORRECTION * z^2) >> 16     159998272102
     110             :      ------------------------------------------------------
     111             :      = dist2                                 40680747978567
     112             :      - SURFACE_DIST2                         40680631590769
     113             :      ------------------------------------------------------
     114             :      = difference                                 116387798
     115             : 
     116             :    116387798 is less than SURFACE_TOLERANCE (12756274000), so Frankfurt
     117             :    is valid.  A point 2km higher, (4052815, 618720, 4872175), is
     118             :    25680309853 away, which is too far:
     119             : 
     120             :          too low                 valid                too high
     121             :        <---------|=================|=================|--------->  dist2
     122             :                                    ^                     ^
     123             :                                Frankfurt             2km above
     124             :                                                      Frankfurt */
     125     4014675 : #define FD_VALIDATOR_LOCATION_SURFACE_DIST2         (40680631590769UL)
     126     2398944 : #define FD_VALIDATOR_LOCATION_FLATTENING_CORRECTION (442UL)
     127     6413574 : #define FD_VALIDATOR_LOCATION_SURFACE_TOLERANCE     (12756274000UL)
     128             : 
     129             : /* The largest allowed magnitude of each coordinate: the Earth's radius
     130             :    at the equator (6378137m) plus 1m. */
     131             : 
     132           6 : #define FD_VALIDATOR_LOCATION_COORD_MAX (6378138)
     133             : 
     134             : FD_PROTOTYPES_BEGIN
     135             : 
     136             : /* Returns the squared distance of loc from the center of the Earth,
     137             :    with the flattening correction as described above, treating the
     138             :    Earth as a perfect sphere.
     139             : 
     140             :    Assumes every coordinate is no larger than
     141             :    FD_VALIDATOR_LOCATION_COORD_MAX. */
     142             : FD_FN_PURE static inline ulong
     143     2398944 : fd_validator_location_dist2_on_sphere( fd_validator_location_t const * loc ) {
     144     2398944 :   ulong x2 = (ulong)( (long)loc->x*(long)loc->x );
     145     2398944 :   ulong y2 = (ulong)( (long)loc->y*(long)loc->y );
     146     2398944 :   ulong z2 = (ulong)( (long)loc->z*(long)loc->z );
     147     2398944 :   return x2 + y2 + z2 + ( ( FD_VALIDATOR_LOCATION_FLATTENING_CORRECTION*z2 )>>16 );
     148     2398944 : }
     149             : 
     150             : /* Returns 1 if loc is a valid location on the Earth's surface,
     151             :    0 otherwise. */
     152             : FD_FN_PURE static inline int
     153     3898851 : fd_validator_location_is_valid( fd_validator_location_t const * loc ) {
     154     3898851 :   if( FD_UNLIKELY( loc->x<-FD_VALIDATOR_LOCATION_COORD_MAX || loc->x>FD_VALIDATOR_LOCATION_COORD_MAX ||
     155     3898851 :                    loc->y<-FD_VALIDATOR_LOCATION_COORD_MAX || loc->y>FD_VALIDATOR_LOCATION_COORD_MAX ||
     156     3898851 :                    loc->z<-FD_VALIDATOR_LOCATION_COORD_MAX || loc->z>FD_VALIDATOR_LOCATION_COORD_MAX ) ) return 0;
     157     2398929 :   ulong dist2 = fd_validator_location_dist2_on_sphere( loc );
     158     2398929 :   return dist2>=FD_VALIDATOR_LOCATION_SURFACE_DIST2-FD_VALIDATOR_LOCATION_SURFACE_TOLERANCE &&
     159     2398929 :          dist2<=FD_VALIDATOR_LOCATION_SURFACE_DIST2+FD_VALIDATOR_LOCATION_SURFACE_TOLERANCE;
     160     3898851 : }
     161             : 
     162             : FD_FN_PURE static inline ulong
     163             : fd_validator_location_dist2( fd_validator_location_t const * a,
     164   133474377 :                              fd_validator_location_t const * b ) {
     165   133474377 :   long dx = (long)a->x - (long)b->x;
     166   133474377 :   long dy = (long)a->y - (long)b->y;
     167   133474377 :   long dz = (long)a->z - (long)b->z;
     168   133474377 :   return (ulong)( dx*dx ) + (ulong)( dy*dy ) + (ulong)( dz*dz );
     169   133474377 : }
     170             : 
     171             : FD_PROTOTYPES_END
     172             : 
     173             : #endif /* HEADER_fd_src_flamenco_runtime_program_vote_fd_validator_location_h */

Generated by: LCOV version 1.14