From f86c3a5459d9a79077bd02091bdeee4c379b04c3 Mon Sep 17 00:00:00 2001 From: Benjamin Smith Date: Tue, 9 May 2023 07:22:18 -0400 Subject: [PATCH] Simulate Both (#270) It is well known that the WinningSettlement results returned from the orderbook API have an unreliable `simulationBlock`. IN order to improve our accuracy, we attempt to simulate the full and reduced settlement call data on `simulationBlock + i` for `i = {0, 1, 2}`. This PR introduces the necessary data structures, retry functionality and an "e2e" test demonstrating the need for it. --------- Co-authored-by: Gent Rexha --- internal_transfers/actions/src/accounting.ts | 72 +++++++++++++++---- .../tests/e2e/simulateSolverSolution.spec.ts | 13 ++++ 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/internal_transfers/actions/src/accounting.ts b/internal_transfers/actions/src/accounting.ts index c13f5bcc..4a938d2f 100644 --- a/internal_transfers/actions/src/accounting.ts +++ b/internal_transfers/actions/src/accounting.ts @@ -64,28 +64,70 @@ export async function simulateSolverSolution( return null; } - const commonSimulationParams = { - contractAddress: SETTLEMENT_CONTRACT_ADDRESS, - sender: solverAddress, - value: "0", - blockNumber: competition.simulationBlock, - }; - const simFull = await simulator.simulate({ - ...commonSimulationParams, - callData: competition.fullCallData, - }); - const simReduced = await simulator.simulate({ - ...commonSimulationParams, - callData: competition.reducedCallData, + const { full, reduced } = await simulateBoth(simulator, { + full: competition.fullCallData, + reduced: competition.reducedCallData, + common: { + contractAddress: SETTLEMENT_CONTRACT_ADDRESS, + sender: solverAddress, + value: "0", + blockNumber: competition.simulationBlock, + }, }); + return { txHash: transaction.hash, winningSettlement: competition, - full: simFull, - reduced: simReduced, + full, + reduced, }; } +interface commonSimulationParams { + contractAddress: string; + sender: string; + value: string; + blockNumber: number; +} + +interface SettlementSimulationParams { + full: string; + reduced: string; + common: commonSimulationParams; +} + +interface SimulationPair { + full: SimulationData; + reduced: SimulationData; +} + +async function simulateBoth( + simulator: TransactionSimulator, + params: SettlementSimulationParams, + numAttempts: number = 2 +): Promise { + let attempts = 0; + while (attempts < numAttempts) { + try { + return { + full: await simulator.simulate({ + ...params.common, + callData: params.full, + }), + reduced: await simulator.simulate({ + ...params.common, + callData: params.reduced, + }), + }; + } catch (error) { + attempts += 1; + // Increment blockNumber on Failed Simulation! + params.common.blockNumber += 1; + } + } + throw new Error(`failed simulations on ${numAttempts} blocks from `); +} + export function getInternalizedImbalance( simulationData: SettlementSimulationData ): TokenImbalance[] { diff --git a/internal_transfers/actions/tests/e2e/simulateSolverSolution.spec.ts b/internal_transfers/actions/tests/e2e/simulateSolverSolution.spec.ts index 51418cbf..2241fbff 100644 --- a/internal_transfers/actions/tests/e2e/simulateSolverSolution.spec.ts +++ b/internal_transfers/actions/tests/e2e/simulateSolverSolution.spec.ts @@ -33,6 +33,19 @@ describe.skip("simulateSolverSolution(transaction, simulator)", () => { const imbalance = await simulateSolverSolution(transaction, simulator); expect(imbalance).toMatchSnapshot(); }); + + test("run pipeline on transaction known to fail first simulation", async () => { + const simFailer = await getTxData( + "0x82c20f4583fb2a49a1db506ef2a1777a3efc99d90d100f7d2da9ca718de395f2" + ); + const simulation = (await simulateSolverSolution(simFailer, simulator))!; + expect(simulation.winningSettlement.simulationBlock + 1).toEqual( + simulation.reduced.blockNumber + ); + expect(simulation.winningSettlement.simulationBlock + 1).toEqual( + simulation.full.blockNumber + ); + }, 300000); }); describe.skip("completeComposition(transaction, simulator)", () => { test("runs as expected on txHash = 0xca0bbc", async () => {