# beacon_chain # Copyright (c) 2018-2023 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. {.push raises: [].} {.used.} import std/strutils import unittest2 import ../beacon_chain/validator_client/[common, scoring] const HostNames = [ "[2001:db8::1]", "127.0.0.1", "hostname.com", "localhost", "username:password@[2001:db8::1]", "username:password@127.0.0.1", "username:password@hostname.com", "username:password@localhost", ] GoodTestVectors = [ ("http://$1", "ok(http://$1)"), ("http://$1?q=query", "ok(http://$1?q=query)"), ("http://$1?q=query#anchor", "ok(http://$1?q=query#anchor)"), ("http://$1/subpath/", "ok(http://$1/subpath/)"), ("http://$1/subpath/q=query", "ok(http://$1/subpath/q=query)"), ("http://$1/subpath/q=query#anchor", "ok(http://$1/subpath/q=query#anchor)"), ("http://$1/subpath", "ok(http://$1/subpath)"), ("http://$1/subpath?q=query", "ok(http://$1/subpath?q=query)"), ("http://$1/subpath?q=query#anchor", "ok(http://$1/subpath?q=query#anchor)"), ("https://$1", "ok(https://$1)"), ("https://$1?q=query", "ok(https://$1?q=query)"), ("https://$1?q=query#anchor", "ok(https://$1?q=query#anchor)"), ("https://$1/subpath/", "ok(https://$1/subpath/)"), ("https://$1/subpath/q=query", "ok(https://$1/subpath/q=query)"), ("https://$1/subpath/q=query#anchor", "ok(https://$1/subpath/q=query#anchor)"), ("https://$1/subpath", "ok(https://$1/subpath)"), ("https://$1/subpath?q=query", "ok(https://$1/subpath?q=query)"), ("https://$1/subpath?q=query#anchor", "ok(https://$1/subpath?q=query#anchor)"), ("$1:5052", "ok(http://$1:5052)"), ("$1:5052?q=query", "ok(http://$1:5052?q=query)"), ("$1:5052?q=query#anchor", "ok(http://$1:5052?q=query#anchor)"), ("$1:5052/subpath/", "ok(http://$1:5052/subpath/)"), ("$1:5052/subpath/q=query", "ok(http://$1:5052/subpath/q=query)"), ("$1:5052/subpath/q=query#anchor", "ok(http://$1:5052/subpath/q=query#anchor)"), ("$1:5052/subpath", "ok(http://$1:5052/subpath)"), ("$1:5052/subpath?q=query", "ok(http://$1:5052/subpath?q=query)"), ("$1:5052/subpath?q=query#anchor", "ok(http://$1:5052/subpath?q=query#anchor)"), ("bnode://$1:5052", "err(Unknown scheme value)"), ("bnode://$1:5052?q=query", "err(Unknown scheme value)"), ("bnode://$1:5052?q=query#anchor", "err(Unknown scheme value)"), ("bnode://$1:5052/subpath/", "err(Unknown scheme value)"), ("bnode://$1:5052/subpath/q=query", "err(Unknown scheme value)"), ("bnode://$1:5052/subpath/q=query#anchor", "err(Unknown scheme value)"), ("bnode://$1:5052/subpath", "err(Unknown scheme value)"), ("bnode://$1:5052/subpath?q=query", "err(Unknown scheme value)"), ("bnode://$1:5052/subpath?q=query#anchor", "err(Unknown scheme value)"), ("//$1:5052", "ok(http://$1:5052)"), ("//$1:5052?q=query", "ok(http://$1:5052?q=query)"), ("//$1:5052?q=query#anchor", "ok(http://$1:5052?q=query#anchor)"), ("//$1:5052/subpath/", "ok(http://$1:5052/subpath/)"), ("//$1:5052/subpath/q=query", "ok(http://$1:5052/subpath/q=query)"), ("//$1:5052/subpath/q=query#anchor", "ok(http://$1:5052/subpath/q=query#anchor)"), ("//$1:5052/subpath", "ok(http://$1:5052/subpath)"), ("//$1:5052/subpath?q=query", "ok(http://$1:5052/subpath?q=query)"), ("//$1:5052/subpath?q=query#anchor", "ok(http://$1:5052/subpath?q=query#anchor)"), ("//$1", "err(Missing port number)"), ("//$1?q=query", "err(Missing port number)"), ("//$1?q=query#anchor", "err(Missing port number)"), ("//$1/subpath/", "err(Missing port number)"), ("//$1/subpath/q=query", "err(Missing port number)"), ("//$1/subpath/q=query#anchor", "err(Missing port number)"), ("//$1/subpath", "err(Missing port number)"), ("//$1/subpath?q=query", "err(Missing port number)"), ("//$1/subpath?q=query#anchor", "err(Missing port number)"), ("$1", "err(Missing port number)"), ("$1?q=query", "err(Missing port number)"), ("$1?q=query#anchor", "err(Missing port number)"), ("$1/subpath/", "err(Missing port number)"), ("$1/subpath/q=query", "err(Missing port number)"), ("$1/subpath/q=query#anchor", "err(Missing port number)"), ("$1/subpath", "err(Missing port number)"), ("$1/subpath?q=query", "err(Missing port number)"), ("$1/subpath?q=query#anchor", "err(Missing port number)"), ("", "err(Missing hostname)") ] type AttestationDataTuple* = tuple[ slot: uint64, index: uint64, beacon_block_root: string, source: uint64, target: uint64 ] const AttestationDataVectors = [ # Attestation score with block monitoring enabled (perfect). ((6002798'u64, 10'u64, "22242212", 187586'u64, 187587'u64), ("22242212", 6002798'u64), ""), ((6002811'u64, 24'u64, "26ec78d6", 187586'u64, 187587'u64), ("26ec78d6", 6002811'u64), ""), ((6002821'u64, 11'u64, "10c6d1a2", 187587'u64, 187588'u64), ("10c6d1a2", 6002821'u64), ""), ((6002836'u64, 15'u64, "42354ded", 187587'u64, 187588'u64), ("42354ded", 6002836'u64), ""), ((6002859'u64, 10'u64, "97d8ac69", 187588'u64, 187589'u64), ("97d8ac69", 6002859'u64), ""), # Attestation score with block monitoring enabled #1 (not perfect). ((6002871'u64, 25'u64, "524a9e2b", 187588'u64, 187589'u64), ("524a9e2b", 6002870'u64), "375177.5000"), ((6002871'u64, 25'u64, "524a9e2b", 187588'u64, 187589'u64), ("524a9e2b", 6002869'u64), "375177.3333"), ((6002871'u64, 25'u64, "524a9e2b", 187588'u64, 187589'u64), ("524a9e2b", 6002868'u64), "375177.2500"), ((6002871'u64, 25'u64, "524a9e2b", 187588'u64, 187589'u64), ("524a9e2b", 6002867'u64), "375177.2000"), ((6002871'u64, 25'u64, "524a9e2b", 187588'u64, 187589'u64), ("524a9e2b", 6002866'u64), "375177.1667"), # Attestation score with block monitoring enabled #2 (not perfect). ((6002962'u64, 14'u64, "22a19d87", 187591'u64, 187592'u64), ("22a19d87", 6002961'u64), "375183.5000"), ((6002962'u64, 14'u64, "22a19d87", 187591'u64, 187592'u64), ("22a19d87", 6002960'u64), "375183.3333"), ((6002962'u64, 14'u64, "22a19d87", 187591'u64, 187592'u64), ("22a19d87", 6002959'u64), "375183.2500"), ((6002962'u64, 14'u64, "22a19d87", 187591'u64, 187592'u64), ("22a19d87", 6002958'u64), "375183.2000"), ((6002962'u64, 14'u64, "22a19d87", 187591'u64, 187592'u64), ("22a19d87", 6002957'u64), "375183.1667"), # Attestation score with block monitoring disabled #1. ((6003217'u64, 52'u64, "5e945218", 187599'u64, 187600'u64), ("00000000", 0'u64), "375199.0000"), ((6003217'u64, 52'u64, "5e945218", 187598'u64, 187600'u64), ("00000000", 0'u64), "375198.0000"), ((6003217'u64, 52'u64, "5e945218", 187597'u64, 187600'u64), ("00000000", 0'u64), "375197.0000"), ((6003217'u64, 52'u64, "5e945218", 187596'u64, 187600'u64), ("00000000", 0'u64), "375196.0000"), ((6003217'u64, 52'u64, "5e945218", 187595'u64, 187600'u64), ("00000000", 0'u64), "375195.0000"), # Attestation score with block monitoring disabled #2. ((6003257'u64, 9'u64, "7bfa464e", 187600'u64, 187601'u64), ("00000000", 0'u64), "375201.0000"), ((6003257'u64, 9'u64, "7bfa464e", 187599'u64, 187601'u64), ("00000000", 0'u64), "375200.0000"), ((6003257'u64, 9'u64, "7bfa464e", 187598'u64, 187601'u64), ("00000000", 0'u64), "375199.0000"), ((6003257'u64, 9'u64, "7bfa464e", 187597'u64, 187601'u64), ("00000000", 0'u64), "375198.0000"), ((6003257'u64, 9'u64, "7bfa464e", 187596'u64, 187601'u64), ("00000000", 0'u64), "375197.0000"), ] proc init(t: typedesc[Eth2Digest], data: string): Eth2Digest = let length = len(data) var dst = Eth2Digest() try: hexToByteArray(data.toOpenArray(0, len(data) - 1), dst.data.toOpenArray(0, (length div 2) - 1)) except ValueError: discard dst proc init*(t: typedesc[ProduceAttestationDataResponse], ad: AttestationDataTuple): ProduceAttestationDataResponse = ProduceAttestationDataResponse(data: AttestationData( slot: Slot(ad.slot), index: ad.index, beacon_block_root: Eth2Digest.init(ad.beacon_block_root), source: Checkpoint(epoch: Epoch(ad.source)), target: Checkpoint(epoch: Epoch(ad.target)) )) proc createRootsSeen( root: tuple[root: string, slot: uint64]): Table[Eth2Digest, Slot] = var res: Table[Eth2Digest, Slot] res[Eth2Digest.init(root.root)] = Slot(root.slot) res suite "Validator Client test suite": test "normalizeUri() test vectors": for hostname in HostNames: for vector in GoodTestVectors: let expect = vector[1] % (hostname) check $normalizeUri(parseUri(vector[0] % (hostname))) == expect test "getAttestationDataScore() test vectors": for vector in AttestationDataVectors: let adata = ProduceAttestationDataResponse.init(vector[0]) roots = createRootsSeen(vector[1]) score = shortScore(roots.getAttestationDataScore(adata)) check score == vector[2]