export async function updateActiveFeeWindows(db: Knex, blockNumber: number, timestamp: number): Promise<FeeWindowModifications> { const expiredFeeWindowRows: Array<{ feeWindow: Address; universe: Address }> = await db("fee_windows").select("feeWindow", "universe") .whereNot("state", FeeWindowState.PAST) .where("endTime", "<", timestamp); await db("fee_windows").update("state", FeeWindowState.PAST).whereIn("feeWindow", _.map(expiredFeeWindowRows, (result) => result.feeWindow)); const newActiveFeeWindowRows: Array<{ feeWindow: Address; universe: Address }> = await db("fee_windows").select("feeWindow", "universe") .whereNot("state", FeeWindowState.CURRENT) .where("endTime", ">", timestamp) .where("startTime", "<", timestamp); await db("fee_windows").update("state", FeeWindowState.CURRENT).whereIn("feeWindow", _.map(newActiveFeeWindowRows, (row) => row.feeWindow)); if (expiredFeeWindowRows != null) { expiredFeeWindowRows.forEach((expiredFeeWindowRow) => { augurEmitter.emit(SubscriptionEventNames.FeeWindowClosed, Object.assign({ blockNumber, timestamp, }, expiredFeeWindowRow)); }); } if (newActiveFeeWindowRows != null) { newActiveFeeWindowRows.forEach((newActiveFeeWindowRow) => { augurEmitter.emit(SubscriptionEventNames.FeeWindowOpened, Object.assign({ blockNumber, timestamp, }, newActiveFeeWindowRow)); }); } return { newActiveFeeWindows: _.map(newActiveFeeWindowRows, (row) => row.feeWindow), expiredFeeWindows: _.map(expiredFeeWindowRows, (row) => row.feeWindow), }; }
// set all crowdsourcers completed to 0, and markets.disputeRounds = null if no initial report, 0 if there is async function uncompleteNonforkingCrowdsourcers(db: Knex, universe: Address, forkingMarket: Address) { await db("crowdsourcers").update("completed", 0) .whereIn("marketId", (queryBuilder) => queryBuilder.from("markets").select("marketId").where({ universe }).whereNot("marketId", forkingMarket)); await db("markets").update({ disputeRounds: null }).where({ universe }).whereNot("marketId", forkingMarket); await db("markets").update({ disputeRounds: 0 }).where({ universe }).whereNot("marketId", forkingMarket) .whereIn("marketId", (queryBuilder) => queryBuilder.from("initial_reports").select("marketId")); }
return async (db: Knex) => { if (forkingMarket == null) throw new Error(`Could not retrieve forking market for universe ${log.universe}`); await db("markets").update("forking", 1).where("marketId", forkingMarket); await updateMarketState(db, forkingMarket, log.blockNumber, ReportingState.FORKING); augurEmitter.emit(SubscriptionEventNames.MarketState, { universe: log.universe, marketId: forkingMarket, reportingState: ReportingState.FORKING, }); await db("markets").increment("needsDisavowal", 1).where({ universe: log.universe }).whereNot("marketId", forkingMarket); await db("universes").update("forked", true).where({ universe: log.universe }); const marketsToRevert: Array<MarketsContractAddressRow> = await getMarketsWithReportingState(db).from("markets").select("markets.marketId") .where({ universe: log.universe }) .whereIn("reportingState", [ReportingState.AWAITING_FINALIZATION, ReportingState.CROWDSOURCING_DISPUTE, ReportingState.AWAITING_NEXT_WINDOW]); await each(marketsToRevert, async (marketIdRow: MarketsContractAddressRow) => { await updateMarketState(db, marketIdRow.marketId, log.blockNumber, ReportingState.AWAITING_FORK_MIGRATION); augurEmitter.emit(SubscriptionEventNames.MarketState, { universe: log.universe, marketId: marketIdRow.marketId, reportingState: ReportingState.AWAITING_FORK_MIGRATION, }); await db("payouts").where({ marketId: marketIdRow.marketId }).update({ winning: db.raw("null"), tentativeWinning: 0 }); return db("payouts").update("tentativeWinning", 1) .join("initial_reports", "payouts.payoutId", "initial_reports.payoutId") .where({ marketId: marketIdRow.marketId }); }); return uncompleteNonforkingCrowdsourcers(db, log.universe, forkingMarket); };
exports.up = async (knex: Knex): Promise<any> => { const marketShareVolumeCreated = await knex.schema.hasColumn("markets", "shareVolume").then(async(exists) => { if (exists) return false; await knex.schema.table("markets", (t) => t.string("shareVolume").defaultTo("0")); return true; }); const outcomeShareVolumeCreated = await knex.schema.hasColumn("outcomes", "shareVolume").then(async(exists) => { if (exists) return false; await knex.schema.table("outcomes", (t) => t.string("shareVolume").defaultTo("0")); return true; }); if (marketShareVolumeCreated || outcomeShareVolumeCreated) { const tradeRows: Array<MinimalTradeRow> = await knex("trades").select(["price", "amount", "marketId", "outcome"]); const tradeRowsByMarket = _.groupBy(tradeRows, "marketId" ); for (const marketId in tradeRowsByMarket) { if (!tradeRowsByMarket.hasOwnProperty(marketId)) continue; const marketTrades = tradeRowsByMarket[marketId]; const marketRow: MarketRow = await knex("markets").first("minPrice", "maxPrice", "numTicks").where({ marketId }); const minPrice = new BigNumber(marketRow.minPrice); const marketVolumes = getVolumesFromTrades(marketTrades, minPrice); await knex("markets").update(marketVolumes).where({marketId}); const outcomeTradesByOutcome = _.groupBy(marketTrades, "outcome"); for (const outcome in outcomeTradesByOutcome) { if (!outcomeTradesByOutcome.hasOwnProperty(outcome)) continue; const outcomeTrades = outcomeTradesByOutcome[outcome]; const tradeVolumes = getVolumesFromTrades(outcomeTrades, minPrice); await knex("outcomes").update(tradeVolumes).where({marketId, outcome}); } } } };
return async (db: Knex) => { await rollbackMarketState(db, log.market, augur.constants.REPORTING_STATE.AWAITING_NEXT_WINDOW); await db("initial_reports").delete().where({ marketId: log.market }); await db("markets").update({ initialReportSize: null }).where({ marketId: log.market }); await updateMarketFeeWindow(db, augur, log.universe, log.market, false); await refreshMarketMailboxEthBalance(db, augur, log.market); augurEmitter.emit(SubscriptionEventNames.InitialReportSubmitted, log); };
return async (db: Knex) => { await rollbackMarketState(db, log.market, augur.constants.REPORTING_STATE.FINALIZED); await db("markets").where({ marketId: log.market }).update({ finalizationBlockNumber: null }); await db("markets").where({ universe: log.universe }).update({ needsMigration: 0 }); await refreshMarketMailboxEthBalance(db, augur, log.market); await removeOutcomeValue(db, log.transactionHash); await updateCategoryAggregationsOnMarketFinalizedRollback({ db, marketId: log.market }); };
async function isDatabaseDamaged(db: Knex): Promise<boolean> { try { const migrationsLock = await db("knex_migrations_lock").first(["is_locked"]); if (migrationsLock.is_locked === 1) return true; const errorRow: { error: undefined|null|string } = await db("network_id").first(["error"]).whereNotNull("error"); return errorRow.error != null; } catch { // Database does not exist return false; } }
return async (db: Knex) => { const initialReporter = await db("initial_reports").update("disavowed", 1).where({ initialReporter: log.reportingParticipant }); const crowdsourcer = await db("crowdsourcers").update("disavowed", 1).where({ crowdsourcerId: log.reportingParticipant }); if (initialReporter === 1) { augurEmitter.emit(SubscriptionEventNames.ReportingParticipantDisavowed, Object.assign({ type: "initialReporter" }, log)); } else if (crowdsourcer === 1) { augurEmitter.emit(SubscriptionEventNames.ReportingParticipantDisavowed, Object.assign({ type: "crowdsourcer" }, log)); } else { throw new Error(`No reporting participant ${log.reportingParticpant}`); } };
async function insertBlockRow(db: Knex, blockNumber: number, blockHash: string, bulkSync: boolean, timestamp: number) { const blocksRows: Array<BlocksRow> = await db("blocks").where({ blockNumber }); let query: Knex.QueryBuilder; if (!blocksRows || !blocksRows.length) { query = db.insert({ blockNumber, blockHash, timestamp, bulkSync }).into("blocks"); } else { query = db("blocks") .where({ blockNumber }) .update({ blockHash, timestamp, bulkSync }); } return query; }
return async (db: Knex) => { await db.from("disputes").where({ transactionHash: log.transactionHash, logIndex: log.logIndex, }).del(); const result: { amountStaked: BigNumber } = await db("crowdsourcers").first("amountStaked").where("crowdsourcerId", log.disputeCrowdsourcer); const amountStaked = result.amountStaked.minus(new BigNumber(log.amountStaked, 10)).toString(); await db("crowdsourcers").update({ amountStaked }).where("crowdsourcerId", log.disputeCrowdsourcer); augurEmitter.emit(SubscriptionEventNames.DisputeCrowdsourcerContribution, Object.assign({}, log, { marketId: log.market })); };