pull/1624/head
Audric Ackermann 4 years ago
parent c2298c4c30
commit 4514714d60
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -25,6 +25,8 @@ const pathFailureThreshold = 3;
// some naming issue here it seems)
let guardNodes: Array<SnodePool.Snode> = [];
export const ed25519Str = (ed25519Key: string) => `(...${ed25519Key.substr(58)})`;
export async function buildNewOnionPathsOneAtATime() {
// this function may be called concurrently make sure we only have one inflight
return allowOnlyOneAtATime('buildNewOnionPaths', async () => {
@ -50,9 +52,15 @@ export async function dropSnodeFromPath(snodeEd25519: string) {
);
if (pathWithSnodeIndex === -1) {
window.log.warn(
`Could not drop ${ed25519Str(snodeEd25519)} from path index: ${pathWithSnodeIndex}`
);
return;
}
window.log.info(`dropping snode ${snodeEd25519} from path index: ${pathWithSnodeIndex}`);
window.log.info(
`dropping snode ${ed25519Str(snodeEd25519)} from path index: ${pathWithSnodeIndex}`
);
// make a copy now so we don't alter the real one while doing stuff here
const oldPaths = _.cloneDeep(onionPaths);
@ -116,7 +124,9 @@ export async function getOnionPath(toExclude?: SnodePool.Snode): Promise<Array<S
*/
export async function incrementBadPathCountOrDrop(guardNodeEd25519: string) {
const pathIndex = onionPaths.findIndex(p => p[0].pubkey_ed25519 === guardNodeEd25519);
window.log.info('\t\tincrementBadPathCountOrDrop starting with guard', guardNodeEd25519);
window.log.info(
`\t\tincrementBadPathCountOrDrop starting with guard ${ed25519Str(guardNodeEd25519)}`
);
if (pathIndex === -1) {
window.log.info('Did not find path with this guard node');
@ -158,6 +168,11 @@ async function dropPathStartingWithGuardNode(guardNodeEd25519: string) {
window.log.warn('No such path starts with this guard node ');
return;
}
window.log.info(
`Dropping path starting with guard node ${ed25519Str(
guardNodeEd25519
)}; index:${failingPathIndex}`
);
onionPaths = onionPaths.filter(p => p[0].pubkey_ed25519 !== guardNodeEd25519);
const edKeys = guardNodes
@ -175,7 +190,7 @@ async function dropPathStartingWithGuardNode(guardNodeEd25519: string) {
async function testGuardNode(snode: SnodePool.Snode) {
const { log } = window;
log.info('Testing a candidate guard node ', snode);
log.info(`Testing a candidate guard node ${ed25519Str(snode.pubkey_ed25519)}`);
// Send a post request and make sure it is OK
const endpoint = '/storage_rpc/v1';
@ -242,7 +257,7 @@ async function selectGuardNodes(): Promise<Array<SnodePool.Snode>> {
// The use of await inside while is intentional:
// we only want to repeat if the await fails
// eslint-disable-next-line-no-await-in-loop
while (selectedGuardNodes.length < 3) {
while (selectedGuardNodes.length < desiredGuardCount) {
if (shuffled.length < desiredGuardCount) {
log.error('Not enought nodes in the pool');
break;
@ -261,11 +276,10 @@ async function selectGuardNodes(): Promise<Array<SnodePool.Snode>> {
selectedGuardNodes = _.concat(selectedGuardNodes, goodNodes);
}
if (guardNodes.length < desiredGuardCount) {
log.error(`COULD NOT get enough guard nodes, only have: ${guardNodes.length}`);
if (selectedGuardNodes.length < desiredGuardCount) {
log.error(`Cound't get enough guard nodes, only have: ${guardNodes.length}`);
}
log.info('new guard nodes: ', guardNodes);
guardNodes = selectedGuardNodes;
const edKeys = guardNodes.map(n => n.pubkey_ed25519);
@ -277,7 +291,7 @@ async function selectGuardNodes(): Promise<Array<SnodePool.Snode>> {
async function buildNewOnionPathsWorker() {
const { log } = window;
log.info('LokiSnodeAPI::buildNewOnionPaths - building new onion paths');
log.info('LokiSnodeAPI::buildNewOnionPaths - building new onion paths...');
const allNodes = await SnodePool.getRandomSnodePool();
@ -300,12 +314,11 @@ async function buildNewOnionPathsWorker() {
);
}
}
// If guard nodes is still empty (the old nodes are now invalid), select new ones:
if (guardNodes.length < minimumGuardCount) {
// TODO: don't throw away potentially good guard nodes
guardNodes = await selectGuardNodes();
}
}
// If guard nodes is still empty (the old nodes are now invalid), select new ones:
if (guardNodes.length < minimumGuardCount) {
// TODO: don't throw away potentially good guard nodes
guardNodes = await selectGuardNodes();
}
// TODO: select one guard node and 2 other nodes randomly
@ -316,7 +329,6 @@ async function buildNewOnionPathsWorker() {
'LokiSnodeAPI::buildNewOnionPaths - Too few nodes to build an onion path! Refreshing pool and retrying'
);
await SnodePool.refreshRandomPool();
debugger;
await buildNewOnionPathsOneAtATime();
return;
}
@ -345,8 +357,6 @@ async function buildNewOnionPathsWorker() {
}
onionPaths.push(path);
}
console.warn('guards', guards);
console.warn('onionPaths', onionPaths);
log.info(`Built ${onionPaths.length} onion paths`);
}

@ -3,7 +3,6 @@
import { OnionPaths } from '.';
import {
FinalRelayOptions,
RequestError,
sendOnionRequestLsrpcDest,
snodeHttpsAgent,
SnodeResponse,
@ -92,6 +91,7 @@ export const getOnionPathForSending = async () => {
const initOptionsWithDefaults = (options: OnionFetchBasicOptions) => {
const defaultFetchBasicOptions = {
retry: 0,
noJson: false,
};
return _.defaults(options, defaultFetchBasicOptions);
};
@ -177,7 +177,7 @@ export const sendViaOnion = async (
});
},
{
retries: 5,
retries: 10, // each path can fail 3 times before being dropped, we have 3 paths at most
factor: 1,
minTimeout: 1000,
onFailedAttempt: e => {

@ -268,21 +268,9 @@ export async function getSnodePoolFromSnodes() {
const nodesToRequest = _.sampleSize(existingSnodePool, 3);
const results = await Promise.all(
nodesToRequest.map(async node => {
return pRetry(
async () => {
return getSnodePoolFromSnode(node);
},
{
retries: 3,
factor: 1,
minTimeout: 1000,
onFailedAttempt: e => {
window.log.warn(
`getSnodePoolFromSnode attempt #${e.attemptNumber} failed. ${e.retriesLeft} retries left...`
);
},
}
);
// this call is already retried if the snode does not reply
// at least when onion requests enabled
return getSnodePoolFromSnode(node);
})
);

@ -13,12 +13,6 @@ import { fromBase64ToArrayBuffer, toHex } from '../utils/String';
import pRetry from 'p-retry';
import { incrementBadPathCountOrDrop } from '../onions/onionPath';
export enum RequestError {
BAD_PATH = 'BAD_PATH',
OTHER = 'OTHER',
ABORTED = 'ABORTED',
}
// hold the ed25519 key of a snode against the time it fails. Used to remove a snode only after a few failures (snodeFailureThreshold failures)
const snodeFailureCount: Record<string, number> = {};
@ -332,7 +326,6 @@ const debug = false;
// Process a response as it arrives from `fetch`, handling
// http errors and attempting to decrypt the body with `sharedKey`
// May return false BAD_PATH, indicating that we should try a new path.
// tslint:disable-next-line: cyclomatic-complexity
async function processOnionResponse(
response: Response,
@ -497,9 +490,6 @@ export async function incrementBadSnodeCountOrDrop(snodeEd25519: string, associa
const oldFailureCount = snodeFailureCount[snodeEd25519] || 0;
const newFailureCount = oldFailureCount + 1;
snodeFailureCount[snodeEd25519] = newFailureCount;
window.log.warn(
`Couldn't reach snode at: ${snodeEd25519}; setting his failure count to ${newFailureCount}`
);
if (newFailureCount >= snodeFailureThreshold) {
window.log.warn(`Failure threshold reached for: ${snodeEd25519}; dropping it.`);
@ -524,6 +514,10 @@ export async function incrementBadSnodeCountOrDrop(snodeEd25519: string, associa
// if dropSnodeFromPath throws, it means there is an issue patching up the path, increment the whole path issues count
await OnionPaths.incrementBadPathCountOrDrop(snodeEd25519);
}
} else {
window.log.warn(
`Couldn't reach snode at: ${snodeEd25519}; setting his failure count to ${newFailureCount}`
);
}
}
@ -733,7 +727,7 @@ async function onionFetchRetryable(
}
/**
* If the fetch returnes BAD_PATH we retry this call with a new path at most 3 times. If another error happens, we return it. If we have a result we just return it.
* If the fetch throws a retryable error we retry this call with a new path at most 3 times. If another error happens, we return it. If we have a result we just return it.
*/
export async function lokiOnionFetch(
targetNode: Snode,
@ -746,7 +740,7 @@ export async function lokiOnionFetch(
return onionFetchRetryable(targetNode, body, associatedWith);
},
{
retries: 5,
retries: 10,
factor: 1,
minTimeout: 1000,
onFailedAttempt: e => {

@ -7,6 +7,7 @@ import * as Data from '../../../ts/data/data';
import { allowOnlyOneAtATime } from '../utils/Promise';
import pRetry from 'p-retry';
import { ed25519Str } from '../onions/onionPath';
/**
* If we get less than this snode in a swarm, we fetch new snodes for this pubkey
@ -117,7 +118,9 @@ export function dropSnodeFromSnodePool(snodeEd25519: string) {
_.remove(randomSnodePool, x => x.pubkey_ed25519 === snodeEd25519);
window.log.warn(
`Marking ${snodeEd25519} as unreachable, ${randomSnodePool.length} snodes remaining in randomPool`
`Marking ${ed25519Str(snodeEd25519)} as unreachable, ${
randomSnodePool.length
} snodes remaining in randomPool`
);
}
}
@ -271,7 +274,7 @@ export async function refreshRandomPool(): Promise<void> {
return;
}
try {
// let this request try 3 (2+1) times. If all those requests end up without having a consensus,
// let this request try 3 (3+1) times. If all those requests end up without having a consensus,
// fetch the snode pool from one of the seed nodes (see the catch).
await pRetry(
async () => {
@ -284,7 +287,7 @@ export async function refreshRandomPool(): Promise<void> {
randomSnodePool = commonNodes;
},
{
retries: 2,
retries: 3,
factor: 1,
minTimeout: 1000,
onFailedAttempt: e => {

Loading…
Cancel
Save