Account for provider config weight when kicking off a request in FallbackProvider (#4298).
This commit is contained in:
parent
e2485b8ef9
commit
da34e3569e
@ -4,6 +4,7 @@ import {
|
||||
isError, makeError,
|
||||
|
||||
AbstractProvider, FallbackProvider, Network,
|
||||
ZeroAddress
|
||||
} from "../index.js";
|
||||
|
||||
import type {
|
||||
@ -93,3 +94,68 @@ describe("Test Fallback broadcast", function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test Inflight Quorum", function() {
|
||||
// Fires the %%actions%% as providers which will delay before returning,
|
||||
// and returns an array of arrays, where each sub-array indicates which
|
||||
// providers were inflight at once.
|
||||
async function test(actions: Array<{ delay: number, stallTimeout: number, priority: number, weight: number }>, quorum: number): Promise<Array<Array<number>>> {
|
||||
const inflights: Array<Array<number>> = [ [ ] ];
|
||||
|
||||
const configs = actions.map(({ delay, stallTimeout, priority, weight }, index) => ({
|
||||
provider: new MockProvider(async (r) => {
|
||||
if (r.method === "getBlockNumber") { return 1; }
|
||||
if (r.method === "getBalance") {
|
||||
// Add this as inflight
|
||||
let last = inflights.pop();
|
||||
if (last == null) { throw new Error("no elements"); }
|
||||
inflights.push(last);
|
||||
last = last.slice();
|
||||
last.push(index);
|
||||
inflights.push(last);
|
||||
|
||||
// Do the thing
|
||||
await stall(delay);
|
||||
|
||||
// Remove as inflight
|
||||
last = inflights.pop();
|
||||
if (last == null) { throw new Error("no elements"); }
|
||||
inflights.push(last);
|
||||
last = last.filter((v) => (v !== index));
|
||||
inflights.push(last);
|
||||
|
||||
return 0;
|
||||
}
|
||||
console.log(r);
|
||||
throw new Error(`unhandled method: ${ r.method }`);
|
||||
}),
|
||||
stallTimeout, priority, weight
|
||||
}));
|
||||
|
||||
const provider = new FallbackProvider(configs, network, {
|
||||
cacheTimeout: -1, pollingInterval: 100,
|
||||
quorum
|
||||
});
|
||||
await provider.getBalance(ZeroAddress);
|
||||
|
||||
return inflights;
|
||||
}
|
||||
|
||||
// See: #4298
|
||||
it("applies weights against inflight requests", async function() {
|
||||
this.timeout(2000);
|
||||
|
||||
const inflights = await test([
|
||||
{ delay: 50, stallTimeout: 1000, priority: 1, weight: 2 },
|
||||
{ delay: 50, stallTimeout: 1000, priority: 1, weight: 2 },
|
||||
], 2);
|
||||
|
||||
// Make sure there is never more than 1 inflight provider at once
|
||||
for (const running of inflights) {
|
||||
assert.ok(running.length <= 1, `too many inflight requests: ${ JSON.stringify(inflights) }`);
|
||||
}
|
||||
});
|
||||
|
||||
// @TODO: add lots more tests, checking on priority, weight and stall
|
||||
// configurations
|
||||
});
|
||||
|
@ -684,7 +684,7 @@ export class FallbackProvider extends AbstractProvider {
|
||||
// Add any new runners, because a staller timed out or a result
|
||||
// or error response came in.
|
||||
for (let i = 0; i < newRunners; i++) {
|
||||
this.#addRunner(running, req)
|
||||
this.#addRunner(running, req);
|
||||
}
|
||||
|
||||
// All providers have returned, and we have no result
|
||||
@ -759,8 +759,12 @@ export class FallbackProvider extends AbstractProvider {
|
||||
|
||||
// Bootstrap enough runners to meet quorum
|
||||
const running: Set<RunnerState> = new Set();
|
||||
for (let i = 0; i < this.quorum; i++) {
|
||||
this.#addRunner(running, req);
|
||||
let inflightQuorum = 0;
|
||||
while (true) {
|
||||
const runner = this.#addRunner(running, req);
|
||||
if (runner == null) { break; }
|
||||
inflightQuorum += runner.config.weight;
|
||||
if (inflightQuorum >= this.quorum) { break; }
|
||||
}
|
||||
|
||||
const result = await this.#waitForQuorum(running, req);
|
||||
|
Loading…
Reference in New Issue
Block a user