diff --git a/src/GetActionsHandler.js b/src/GetActionsHandler.js index d0e550d..db0891a 100644 --- a/src/GetActionsHandler.js +++ b/src/GetActionsHandler.js @@ -40,18 +40,20 @@ class GetActionsHandler extends MassiveActionHandler { return [false, 0] } - // Override to use ON CONFLICT DO NOTHING for _block_number_txid. - // Re-processed blocks (e.g. after switching from NodeosActionReader) would otherwise - // crash with a duplicate key violation since that table has no upsert support. + // Overridden for two reasons: + // - demux reads the resume point from _index_state row id=1 only (loadIndexState). + // A save() without an id inserted a fresh serial row per block, so id=1 never + // existed and every restart replayed from block 1. Upsert row 1 explicitly. + // - Re-processed blocks (e.g. after switching from NodeosActionReader) would crash + // on _block_number_txid's duplicate key, since that table has no upsert support. async updateIndexState (state, block, isReplay, context) { const { blockInfo } = block - const fromDb = (await state._index_state.findOne({ id: 1 })) || {} - const toSave = Object.assign({}, fromDb, { - block_number: blockInfo.blockNumber, - block_hash: blockInfo.blockHash, - is_replay: isReplay - }) - await state._index_state.save(toSave) + await state.instance.none( + `INSERT INTO _index_state (id, block_number, block_hash, is_replay) VALUES (1, $1, $2, $3) + ON CONFLICT (id) DO UPDATE SET block_number = EXCLUDED.block_number, + block_hash = EXCLUDED.block_hash, is_replay = EXCLUDED.is_replay`, + [blockInfo.blockNumber, blockInfo.blockHash, isReplay] + ) await state.instance.none( 'INSERT INTO _block_number_txid (block_number, txid) VALUES ($1, $2) ON CONFLICT DO NOTHING', [blockInfo.blockNumber, context.txid]