diff --git a/crawl_data/mobilecoin_crawl_report_completed_manually_2021-08-23.json b/crawl_data/mobilecoin_crawl_report_completed_manually_2021-08-23.json deleted file mode 100644 index 1d52088..0000000 --- a/crawl_data/mobilecoin_crawl_report_completed_manually_2021-08-23.json +++ /dev/null @@ -1,263 +0,0 @@ -{ - "timestamp": "2021-08-23T09:41:54.661515289+00:00", - "duration": { - "secs": 1, - "nanos": 884407016 - }, - "nodeInfo": { - "totalNodes": 10, - "reachableNodes": 10 - }, - "nodes": [ - { - "publicKey": "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "hostname": "blockdaemon.mobilecoin.bdnodes.net", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "United Kingdom" - } - }, - { - "publicKey": "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "hostname": "binance.mobilecoin.bdnodes.net", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "hostname": "thelongnowfoundation.mobilecoin.bdnodes.net", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "hostname": "ideasbeyondborders.mobilecoin.bdnodes.net", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "United Kingdom" - } - }, - { - "publicKey": "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "hostname": "peer3.prod.mobilecoinww.com", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "hostname": "peer1.prod.mobilecoinww.com", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "hostname": "peer2.consensus.mob.production.namda.net", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "hostname": "peer2.prod.mobilecoinww.com", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "hostname": "ams1-mc-peer1.dreamhost.com", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=" - ] - }, - "isp": "Datacamp Limited", - "geoData": { - "countryName": "Germany" - } - }, - { - "publicKey": "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "hostname": "peer1.consensus.mob.production.namda.net", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - } - ] -} diff --git a/crawl_data/mobilecoin_nodes_completed_manually_2021-08-02.json b/crawl_data/mobilecoin_nodes_completed_manually_2021-08-02.json deleted file mode 100644 index 3256030..0000000 --- a/crawl_data/mobilecoin_nodes_completed_manually_2021-08-02.json +++ /dev/null @@ -1,252 +0,0 @@ -[ - { - "publicKey": "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "hostname": "binance.mobilecoin.bdnodes.net", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "hostname": "peer3.prod.mobilecoinww.com", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "hostname": "peer1.consensus.mob.production.namda.net", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "hostname": "peer2.prod.mobilecoinww.com", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "hostname": "peer1.prod.mobilecoinww.com", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "hostname": "peer2.consensus.mob.production.namda.net", - "port": 443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - }, - { - "publicKey": "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "hostname": "blockdaemon.mobilecoin.bdnodes.net", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "United Kingdom" - } - }, - { - "publicKey": "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "hostname": "ams1-mc-peer1.dreamhost.com", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=" - ] - }, - "isp": "Datacamp Limited", - "geoData": { - "countryName": "Germany" - } - }, - { - "publicKey": "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "hostname": "ideasbeyondborders.mobilecoin.bdnodes.net", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "United Kingdom" - } - }, - { - "publicKey": "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=", - "hostname": "thelongnowfoundation.mobilecoin.bdnodes.net", - "port": 8443, - "active": true, - "quorumSet": { - "threshold": 8, - "validators": [ - "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", - "MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", - "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0=", - "ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", - "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs=", - "9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g=", - "/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q=", - "E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI=", - "5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo=", - "Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY=" - ] - }, - "isp": "Microsoft Corporation", - "geoData": { - "countryName": "Netherlands" - } - } -] diff --git a/crawl_data/mobilecoin_organisations_2021-08-02_created_manually.json b/crawl_data/mobilecoin_organisations_2021-08-02_created_manually.json deleted file mode 100644 index 7f63ad6..0000000 --- a/crawl_data/mobilecoin_organisations_2021-08-02_created_manually.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "name": "Dreamhost", - "validators":["9uEO9eq8TKU0vrKt1R6p4wzkGJX7HbXDXyzs8HEX21g="] - }, - { - "name": "MobileCoin Worldwide", - "validators":["MtTj21PtiL+FQW3YbKZXfcfnFztHlVhnbvwvaiWDFuE=", "wxHjdoRQBF9Ozp8lE0wq9pppyP48nKphcQ0GeEb4zYg=", "XVfN4JQH+6vkFzrzBNezoknl9eCiz3ZbubwyCeOdt/0="] - }, - { - "name": "Namda", - "validators":["ExKHKhbtJiJxVSxLIsmIza3quRojV3W46y1s4AFTx3c=", "I8W+znEPauMLeocYpdEy9pPskTshaVBRrHvCEutyYMs="] - }, - { - "name": "The Long Now Foundation", - "validators":["Xd4Xyfv0OizkLKB/Jb7HM/KDjd1mMgbF34MStLqd1WY="] - }, - { - "name": "Binance", - "validators":["E+kgQW/ojERRdqnPFcoN3+e9dfe/eKDbaegmIlRjMRI="] - }, - { - "name": "Blockdaemon", - "validators":["/wMkv3+3MluopGsqtnZx4rbqzPR2axi7bCiqWWnOq0Q="] - }, - { - "name": "Ideas Beyond Borders", - "validators":["5FAlOt1v7CFDeJIq/BIrZ1Gph+WQXZpRTW0cGLZGFyo="] - } -] diff --git a/src/crawl/core_types.rs b/src/crawl/core_types.rs index 6aa1adf..b73e3c8 100644 --- a/src/crawl/core_types.rs +++ b/src/crawl/core_types.rs @@ -9,17 +9,22 @@ use mc_crypto_keys::Ed25519Public; /// A CrawledNode is a MobileCoin network node that we have learned of during the crawl. The /// Crawler keeps a tally of these during a crawl and each will later be transformed to a MobCoinNode. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub(crate) struct CrawledNode { +pub struct CrawledNode { pub(crate) public_key: Ed25519Public, pub(crate) domain: String, pub(crate) port: u16, pub(crate) quorum_set: McQuorumSet, pub(crate) online: bool, + pub(crate) latest_ledger: usize, + pub(crate) network_block_version: usize, + pub(crate) minimum_fee: usize, } /// The Crawler object steers a crawl. #[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct Crawler { + /// initial set of bootstrap peers + pub bootstrap_peers: HashSet, /// A HashSet of discovered nodes pub(crate) mobcoin_nodes: HashSet, /// A HashSet of nodes to be crawled @@ -36,7 +41,14 @@ pub struct Crawler { impl CrawledNode { /// Create a new CrawledNode using its hostname, connectivity status and Qset. - pub(crate) fn new(url: String, online: bool, quorum_set: McQuorumSet) -> Self { + pub(crate) fn new( + url: String, + online: bool, + quorum_set: McQuorumSet, + latest_ledger: usize, + network_block_version: usize, + minimum_fee: usize, + ) -> Self { let (domain, port) = Self::fragment_mc_url(url); CrawledNode { public_key: Ed25519Public::default(), @@ -44,11 +56,14 @@ impl CrawledNode { port, quorum_set, online, + latest_ledger, + network_block_version, + minimum_fee, } } /// Return 0.0.0.0 as an address if not resolvable otherwise the stats functions would return one own's geolocation - fn fragment_mc_url(url: String) -> (String, u16) { + pub (crate) fn fragment_mc_url(url: String) -> (String, u16) { let url = Url::parse(&url).expect("Failed to parse into Url"); let domain = url.domain(); let port = url.port(); @@ -87,6 +102,7 @@ impl Crawler { to_crawl.insert(peer); } Crawler { + bootstrap_peers: to_crawl.clone(), mobcoin_nodes: HashSet::new(), to_crawl, crawled: HashSet::new(), @@ -116,6 +132,7 @@ mod tests { to_crawl.insert(String::from("foo")); to_crawl.insert(String::from("bar")); let expected = Crawler { + bootstrap_peers: bs_peers.clone().into_iter().collect::>(), mobcoin_nodes: HashSet::new(), to_crawl, crawled: HashSet::new(), diff --git a/src/crawl/crawler.rs b/src/crawl/crawler.rs index 9a5ddda..aa9fe2d 100644 --- a/src/crawl/crawler.rs +++ b/src/crawl/crawler.rs @@ -5,7 +5,8 @@ use std::{collections::HashSet, str::FromStr, sync::Arc}; use grpcio::{ChannelBuilder, EnvBuilder}; use mc_common::logger; use mc_consensus_api::{ - consensus_peer::GetLatestMsgResponse, consensus_peer_grpc::ConsensusPeerApiClient, + consensus_common_grpc::BlockchainApiClient, consensus_peer::GetLatestMsgResponse, + consensus_peer_grpc::ConsensusPeerApiClient, }; use mc_consensus_scp::QuorumSet as McQuorumSet; use mc_crypto_keys::Ed25519Public; @@ -16,20 +17,23 @@ use mc_util_uri::ConsensusClientUri as ClientUri; impl Crawler { /// Opens an RPC channel to the peer which can be used for communication later - pub(crate) fn prepare_rpc(peer: String) -> Option { + pub(crate) fn prepare_rpc( + peer: String, + ) -> (Option, Option) { let env = Arc::new(EnvBuilder::new().build()); let logger = logger::create_root_logger(); let node_uri = match ClientUri::from_str(&peer) { Ok(uri) => Some(uri), Err(_) => { warn!("Error in Node URI: {}", peer); - return None; + return (None, None); } }; let ch = ChannelBuilder::default_channel_builder(env) .connect_to_uri(&node_uri.unwrap(), &logger); - let consensus_client = ConsensusPeerApiClient::new(ch); - Some(consensus_client) + let consensus_client = ConsensusPeerApiClient::new(ch.clone()); + let blockchain_client = ::new(ch); + (Some(consensus_client), Some(blockchain_client)) } /// The bytes of the RPC response is deserialised into an McQuorumSet::QuorumSet @@ -107,15 +111,17 @@ mod tests { #[test] fn invalid_peer_address_to_cons_peer() { let peer = "localhost:443"; - let actual = Crawler::prepare_rpc(String::from(peer)); - assert!(actual.is_none()); + let (consenus_client, blockchain_client) = Crawler::prepare_rpc(String::from(peer)); + assert!(consenus_client.is_none()); + assert!(blockchain_client.is_none()); } #[test] fn correct_peer_address_to_cons_peer() { let peer = "mc://localhost:443"; - let actual = Crawler::prepare_rpc(String::from(peer)); - assert!(actual.is_some()); + let (consenus_client, blockchain_client) = Crawler::prepare_rpc(String::from(peer)); + assert!(consenus_client.is_some()); + assert!(blockchain_client.is_some()); } #[test] @@ -130,8 +136,14 @@ mod tests { let mut crawler = Crawler::default(); let reachable = false; let crawled_node_uri = String::from("mc://test.node:11"); - let mut crawled_node = - CrawledNode::new(crawled_node_uri.clone(), reachable, McQuorumSet::empty()); + let mut crawled_node = CrawledNode::new( + crawled_node_uri.clone(), + reachable, + McQuorumSet::empty(), + 4242, // some random latest_ledger value (a.k.a. block height) + 42, // a random network block version for testing purposes + 424242, // a random minimum fee in pMOB + ); crawler.handle_discovered_node(&crawled_node_uri, &mut crawled_node); assert!(crawler.mobcoin_nodes.contains(&crawled_node)); assert!(crawler.crawled.contains(&crawled_node_uri)); @@ -158,6 +170,9 @@ mod tests { ], ), online: false, + latest_ledger: 4242, + network_block_version: 42, + minimum_fee: 424242, }, CrawledNode { public_key: node_0_pk, @@ -171,6 +186,9 @@ mod tests { ], ), online: false, + latest_ledger: 4242, + network_block_version: 42, + minimum_fee: 424242, }, ]); let actual = crawler.get_public_keys_from_quorum_sets(); @@ -187,6 +205,9 @@ mod tests { QuorumSetMember::Node(node_1_id.clone()), ], ), + latest_ledger: 4242, + network_block_version: 42, + minimum_fee: 424242, }, CrawledNode { public_key: Ed25519Public::default(), @@ -200,6 +221,9 @@ mod tests { QuorumSetMember::Node(node_1_id.clone()), ], ), + latest_ledger: 4242, + network_block_version: 42, + minimum_fee: 424242, }, ]); assert_eq!(actual.len(), expected.len()); diff --git a/src/crawl/net.rs b/src/crawl/net.rs index 8e8bd0e..75ff253 100644 --- a/src/crawl/net.rs +++ b/src/crawl/net.rs @@ -5,6 +5,7 @@ use log::{info, warn}; use std::time::Instant; use mc_consensus_api::{ + consensus_common::LastBlockInfoResponse, consensus_common_grpc::BlockchainApiClient, consensus_peer::GetLatestMsgResponse, consensus_peer_grpc::ConsensusPeerApiClient, empty, }; use mc_consensus_scp::QuorumSet; @@ -43,38 +44,75 @@ impl Crawler { /// 3. Call the handle_discovered_node method on the peer. fn crawl_node(&mut self, peer: &String) { info!("Crawling peer: {}", peer); - let mut reachable = false; - let quorum_set = if let Some(client) = Self::prepare_rpc(peer.clone()) { - if let Some(rpc_reply) = Self::send_rpc(client) { - self.reachable_nodes += 1; - reachable = true; - if let Some(qs) = Self::deserialise_payload_to_quorum_set(rpc_reply) { - qs + + if let (Some(consensus_client), Some(blockchain_client)) = Self::prepare_rpc(peer.clone()) { + let mut reachable = false; + let quorum_set = + if let Some(rpc_reply) = Self::send_rpc_get_latest_msg(consensus_client) { + self.reachable_nodes += 1; + reachable = true; + if let Some(qs) = Self::deserialise_payload_to_quorum_set(rpc_reply) { + qs + } else { + warn!("Couldn't deserialise message from {}.", peer); + QuorumSet::empty() + } } else { - warn!("Couldn't deserialise message from {}.", peer); + warn!("Failure sending RPC to {} .", peer); QuorumSet::empty() - } - } else { - warn!("Failure sending RPC to {} .", peer); - QuorumSet::empty() - } + }; + + let (network_block_version, latest_ledger, fee) = + if let Some(rpc_reply) = Self::send_rpc_get_last_block_info(blockchain_client) { + ( + rpc_reply.get_network_block_version(), + rpc_reply.get_index(), + if let Some(fee) = rpc_reply.get_minimum_fees().get(&0) { + *fee + } else { + 0 + }, + ) + } else { + warn!( + "Couldn't get network block version and latest block from {}.", + peer + ); + (0, 0, 0) // network_block_version, latest_ledger, minimum_fee + }; + let mut crawled = CrawledNode::new( + peer.clone(), + reachable, + quorum_set, + latest_ledger.try_into().unwrap(), + network_block_version.try_into().unwrap(), + fee.try_into().unwrap(), + ); + self.handle_discovered_node(peer, &mut crawled); } else { // We didn't even send the RPC so no need to take note of the node warn!("Terminating crawl on peer {} .", peer); - return; }; - let mut crawled = CrawledNode::new(peer.clone(), reachable, quorum_set); - self.handle_discovered_node(peer, &mut crawled); } /// The RPC "get_latest_msg" expects an empty protobuf and returns the last ConsensusMsg a node /// sent (see /// https://github.com/mobilecoinfoundation/mobilecoin/blob/master/peers/src/consensus_msg.rs#L20 for the exact definition) - fn send_rpc(client: ConsensusPeerApiClient) -> Option { + fn send_rpc_get_latest_msg(client: ConsensusPeerApiClient) -> Option { let response = match client.get_latest_msg(&empty::Empty::default()) { Ok(reply) => Some(reply), Err(_) => { - warn!("Error in RPC response."); + warn!("Error in ConsensusPeerApi-RPC response."); + None + } + }; + response + } + fn send_rpc_get_last_block_info(client: BlockchainApiClient) -> Option { + let response = match client.get_last_block_info(&empty::Empty::default()) { + Ok(reply) => Some(reply), + Err(_) => { + warn!("Error in BlockchainApi-RPC response."); None } }; diff --git a/src/io/report.rs b/src/io/report.rs index 122f991..e4f6a2e 100644 --- a/src/io/report.rs +++ b/src/io/report.rs @@ -5,6 +5,7 @@ use base64::{engine::general_purpose::STANDARD, Engine}; use mc_consensus_scp::{QuorumSet as McQuorumSet, QuorumSetMember}; use mc_crypto_keys::Ed25519Public; use serde::{Serialize, Serializer}; +use std::collections::HashMap; use std::time::Duration; #[derive(Clone, Debug, PartialEq, Eq, Default, Serialize)] @@ -21,6 +22,9 @@ pub struct MobcoinNode { #[serde(skip_serializing_if = "String::is_empty")] pub isp: String, pub geo_data: GeoData, + pub latest_ledger: usize, + pub ledger_version: usize, + pub minimum_fee: usize, } #[derive(Clone, Debug, PartialEq, Eq, Default, Serialize)] @@ -57,6 +61,8 @@ pub struct CrawlReport { /// The MobileCoin Nodes pub node_info: NodeInfo, pub nodes: MobcoinFbas, + pub networks_latest_ledger: usize, + pub networks_minimum_fee: usize, } /// Holds (general) data about the crawl and is included in the CrawlReport. @@ -79,6 +85,88 @@ impl MobcoinFbas { } impl CrawlReport { + fn determine_minimum_fee(crawler: &Crawler) -> usize { + let minimum_fees: Vec = crawler + .mobcoin_nodes + .iter() + .map(|node| node.minimum_fee) + .collect(); + + if minimum_fees.iter().all(|&item| item == minimum_fees[0]) && !minimum_fees.is_empty() { + minimum_fees[0] + } else { + 0 + } + } + + /// determines the block height in the network + /// + /// This function tries to determine the general block height as follows: + /// In the first step, the function counts all statements of the nodes about + /// the block height and sorts them by frequency. + /// + /// If two different block heights are propagated by the same number of nodes, + /// it is determined whether the bootstrapping nodes, which are trusted a priori, + /// collectively support one of the statements. + /// If this is the case, a decision is made in favor of this block height and we are done. + /// + /// If there is a clear majority in favor of a block height, + /// then that block height is chosen. + /// + /// If it is not possible to make a decision + /// either by means of the trusted nodes or by a majority decision, + /// an error code smaller than 0 is generated. + fn determine_network_block_height(crawler: &Crawler) -> usize { + // Map + let mut map = HashMap::::new(); + for node in &crawler.mobcoin_nodes { + *map.entry(node.latest_ledger).or_insert(0) += 1; + } + if map.is_empty() { + return 0; + } + + let mut amount: Vec = map.values().cloned().collect::>(); + amount.sort_unstable_by(|a, b| b.cmp(a)); // reverse sorting + + // 2 different block lengths have the same number of "supporter nodes" + // actually no decision possible; let's rely on our trusted bootstrap nodes + if amount.len() > 1 && amount[0] == amount[1] { + let mut trusted_block = None; + for node in &crawler.mobcoin_nodes { + for bsp in &crawler.bootstrap_peers { + let (domain, port) = CrawledNode::fragment_mc_url(bsp.clone()); + // is this node one of our trusted ones? + if (node.domain == domain) && (node.port == port) { + match trusted_block { + Some(trusted_block) => { + if trusted_block != node.latest_ledger { + return 0; // nodes did not consent to a latest block because trusted nodes are discordant. + } + } + None => { + trusted_block = Some(node.latest_ledger); + } + }; + } + } + } + match trusted_block { + Some(trusted_block) => { + return usize::from(trusted_block); + } + _ => { + return 0; // nodes did not consent to a latest block because a unexpected error occured. + } + }; + } + // find the most common latest_ledger (aka block height) + usize::from( + map.iter() + .find_map(|(key, val)| if *val == amount[0] { Some(*key) } else { None }) + .unwrap(), + ) + } pub fn create_crawl_report(fbas: MobcoinFbas, crawler: &Crawler) -> Self { Self { timestamp: crawler.crawl_time.clone(), @@ -88,6 +176,8 @@ impl CrawlReport { reachable_nodes: crawler.reachable_nodes, }, nodes: fbas, + networks_latest_ledger: CrawlReport::determine_network_block_height(crawler), + networks_minimum_fee: CrawlReport::determine_minimum_fee(crawler), } } } @@ -130,6 +220,9 @@ impl MobcoinNode { quorum_set, isp, geo_data: GeoData { country_name }, + latest_ledger: crawled_node.latest_ledger, + ledger_version: crawled_node.network_block_version, + minimum_fee: crawled_node.minimum_fee, } } } @@ -147,6 +240,7 @@ where mod tests { use super::*; use mc_consensus_scp::test_utils::test_node_id; + use std::collections::HashSet; #[test] fn mc_qset_without_inner_to_sbeat_qset() { @@ -244,6 +338,9 @@ mod tests { ], ), online: false, + latest_ledger: 4242, + network_block_version: 42, + minimum_fee: 424242, }; let quorum_set = QuorumSet::from_mc_quorum_set(crawled_node.quorum_set.clone()); let expected = MobcoinNode { @@ -256,8 +353,81 @@ mod tests { geo_data: GeoData { country_name: String::from("United States"), }, + latest_ledger: 4242, + ledger_version: 42, + minimum_fee: 424242, }; let actual = MobcoinNode::from_crawled_node(crawled_node); assert_eq!(expected, actual); } + + #[test] + fn test_determine_network_block_height_failure() { + let to_crawl: HashSet = vec![ + "mc://node1.trusted.com:123".to_string(), + "mc://node2.trusted.com:123".to_string(), + ] + .into_iter() + .collect(); + let mut cnl = HashSet::::new(); + for i in 1..3 { + let crawled_node = CrawledNode { + public_key: Ed25519Public::default(), + domain: format!("node{}.trusted.com", i), + port: 123, + quorum_set: McQuorumSet::new(0, vec![]), + online: false, + latest_ledger: i, + network_block_version: 42, + minimum_fee: 4242424242, + }; + cnl.insert(crawled_node); + } + let crawler = Crawler { + bootstrap_peers: to_crawl.clone(), + mobcoin_nodes: cnl.clone(), + to_crawl, + crawled: HashSet::new(), + reachable_nodes: 2, + crawl_duration: Duration::default(), + crawl_time: String::default(), + }; + let result = CrawlReport::determine_network_block_height(&crawler); + assert_eq!(result, -1); + } + #[test] + fn determine_network_block_height() { + let to_crawl = HashSet::from(["mc://node1.coins.com:123".to_string()]); + let mut cnl = HashSet::::new(); + for i in 1..4 { + let crawled_node = CrawledNode { + public_key: Ed25519Public::default(), + domain: format!("node{}.coins.com", i), + port: 123, + quorum_set: McQuorumSet::new(0, vec![]), + online: false, + latest_ledger: i, + network_block_version: 42, + minimum_fee: 424242, + }; + cnl.insert(crawled_node); + } + let crawler = Crawler { + bootstrap_peers: to_crawl.clone(), + mobcoin_nodes: cnl.clone(), + to_crawl, + crawled: HashSet::new(), + reachable_nodes: 2, + crawl_duration: Duration::default(), + crawl_time: String::default(), + }; + let result = CrawlReport::determine_network_block_height(&crawler); + assert_eq!(result, 1); + assert!( + result > 0, + "result is type of {:#?} because of {:#?}.", + result, + cnl + ); + } }