Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F12944937
D13484.id38990.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
20 KB
Subscribers
None
D13484.id38990.diff
View Options
diff --git a/web/alias-server/config.js b/web/alias-server/config.js
--- a/web/alias-server/config.js
+++ b/web/alias-server/config.js
@@ -7,6 +7,9 @@
pendingAliases: 'pendingAliasTxs',
serverState: 'serverState',
},
+ startup: {
+ serverState: { processedBlockheight: 0, processedConfirmedTxs: 0 },
+ },
connectionUrl: 'mongodb://localhost:27017',
},
telegram: {
diff --git a/web/alias-server/dbMethods.js b/web/alias-server/dbMethods.js
new file mode 100644
--- /dev/null
+++ b/web/alias-server/dbMethods.js
@@ -0,0 +1,112 @@
+'use strict';
+const config = require('./config');
+const log = require('./log');
+const { sendAdminAlert } = require('./telegram');
+module.exports = {
+ getValidAliasesFromDb: async function (db) {
+ let validAliasesInDb;
+ try {
+ validAliasesInDb = await db
+ .collection(config.database.collections.validAliases)
+ .find()
+ .sort({ blockheight: 1 })
+ .project({ _id: 0 })
+ .toArray();
+ log(
+ `${validAliasesInDb.length} valid aliases fetched from the database.`,
+ );
+ return validAliasesInDb;
+ } catch (err) {
+ const errorDesc = `Error in determining validAliasesInDb in function getValidAliasesFromDb. Notifying admin.`;
+ await module.exports.handleFailedDatabaseRequest(errorDesc, err);
+ return false;
+ }
+ },
+ getServerStateFromDb: async function (db) {
+ let serverStateArray;
+ try {
+ serverStateArray = await db
+ .collection(config.database.collections.serverState)
+ .find()
+ .toArray();
+ if (serverStateArray.length === 0) {
+ // Special case where you are just starting the app
+ log(
+ `Server startup: App has no serverState; processedConfirmedTxs and processedBlockheight will default to 0`,
+ );
+ return config.database.startup.serverState;
+ } else {
+ return serverStateArray[0];
+ }
+ } catch (err) {
+ const errorDesc = `Error in determining serverState. Notifying admin.`;
+ await module.exports.handleFailedDatabaseRequest(errorDesc, err);
+ return false;
+ }
+ },
+ addAliasesToDb: async function (db, newValidAliases) {
+ let validAliasesAddedToDbSuccess;
+ try {
+ validAliasesAddedToDbSuccess = await db
+ .collection(config.database.collections.validAliases)
+ .insertMany(newValidAliases);
+ log(
+ `Inserted ${validAliasesAddedToDbSuccess.insertedCount} reserved aliases into ${config.database.collections.validAliases}`,
+ );
+ return true;
+ } catch (err) {
+ const errorDesc = `Error in function addAliasesToDb. Notifying admin.`;
+ await module.exports.handleFailedDatabaseRequest(errorDesc, err);
+ return false;
+ }
+ },
+ updateServerStateInDb: async function (db, newServerState) {
+ const { processedConfirmedTxs, processedBlockheight } = newServerState;
+ // An empty document will update the first document returned in the collection
+ // serverState only has one document
+ const serverStateQuery = {};
+ const serverStateUpdate = {
+ $set: {
+ processedConfirmedTxs,
+ processedBlockheight,
+ },
+ };
+ // If you are running the server for the first time and there is no
+ // serverState in the db, create it
+ const serverStateOptions = { upsert: true };
+ let serverStateUpdateResult;
+ try {
+ serverStateUpdateResult = await db
+ .collection(config.database.collections.serverState)
+ .updateOne(
+ serverStateQuery,
+ serverStateUpdate,
+ serverStateOptions,
+ );
+ return true;
+ } catch (err) {
+ // If this isn't updated, the server will process too many txs next time
+ // Let the admin know. This won't impact parsing but will cause processing too many txs
+ const errorDesc = `Error in function updateServerState. Notifying admin.`;
+ await module.exports.handleFailedDatabaseRequest(errorDesc, err);
+ return false;
+ }
+ },
+ handleFailedDatabaseRequest: async function (
+ adminErrorDescription,
+ thrownError,
+ ) {
+ log(adminErrorDescription, thrownError);
+ // Send prelim admin notification with text only.
+ // Notification with error msg may fail to send due to telegram markdown requirements.
+ const prelimAdminNotified = await sendAdminAlert(adminErrorDescription);
+ if (!prelimAdminNotified) {
+ log(`Prelim admin notification failed to send.`);
+ }
+ const adminNotifyMsg = `${adminErrorDescription}\n\n${thrownError}`;
+ const adminNotified = await sendAdminAlert(adminNotifyMsg);
+ if (!adminNotified) {
+ log(`Admin notification failed to send.`);
+ }
+ },
+};
diff --git a/web/alias-server/websocket.js b/web/alias-server/websocket.js
--- a/web/alias-server/websocket.js
+++ b/web/alias-server/websocket.js
@@ -1,3 +1,4 @@
+'use strict';
const config = require('./config');
const log = require('./log');
const {
@@ -13,9 +14,14 @@
} = require('./utils');
const {
returnTelegramBotSendMessagePromise,
- sendAdminAlert,
buildAliasAnnouncementMsg,
} = require('./telegram');
+const {
+ getValidAliasesFromDb,
+ getServerStateFromDb,
+ addAliasesToDb,
+ updateServerStateInDb,
+} = require('./dbMethods');
const { chronik } = require('./chronik');
const axios = require('axios');
@@ -53,92 +59,27 @@
: log(`Checking for new aliases on startup`);
// Get the valid aliases already in the db
- let validAliasesInDb;
- try {
- validAliasesInDb = await db
- .collection(config.database.collections.validAliases)
- .find()
- .sort({ blockheight: 1 })
- .project({ _id: 0 })
- .toArray();
- log(`${validAliasesInDb.length} valid aliases in database`);
- } catch (err) {
- /*
- - Notify Admin
- - Do not finish this function. Leave alias info unchanged
- (will be in error state or not displaying the most recent aliases)
- - Not displaying the most recent aliases is acceptable if the API does display
- the blockheight at which info is valid
- */
- const errMsg = `Error in determining validAliasesInDb, notifying admin and exiting parseWebsocketMessage()`;
- log(errMsg, err);
- const adminNotifyMsg = `${errMsg}\n\n${err}`;
- const adminNotified = await sendAdminAlert(adminNotifyMsg);
- if (!adminNotified) {
- log(`Admin notification failed to send`);
- }
+ let validAliasesInDb = await getValidAliasesFromDb(db);
+ if (!validAliasesInDb) {
+ log(
+ `Failed to fetch valid aliases from database at block ${wsMsg.blockHash}. Exiting loop.`,
+ );
+ // Break out of this loop
+ // API will continue to show the last alias set we know to be valid
return;
}
- // Get the valid aliases already in the db
- let serverState, serverStateArray;
- try {
- serverStateArray = await db
- .collection(config.database.collections.serverState)
- .find()
- .toArray();
- if (serverStateArray.length === 0) {
- // Special case where you are just starting the app
- log(
- `App has no serverState. processedConfirmedTxs will default to 0`,
- );
- }
- serverState = serverStateArray[0];
- } catch (err) {
- /*
- If this happens,
- - Notify Admin
- - Do not finish this function. Leave alias info unchanged
- (will be in error state or not displaying the most recent aliases)
- - Not displaying the most recent aliases is acceptable if the API does display
- the blockheight at which info is valid
- */
- const errMsg = `Error in determining serverState, notifying admin and exiting parseWebsocketMessage()`;
- log(errMsg, err);
- const adminNotifyMsg = `${errMsg}\n\n${err}`;
- const adminNotified = await sendAdminAlert(adminNotifyMsg);
- if (!adminNotified) {
- log(`Admin notification failed to send`);
- }
- return;
- }
+ let serverState;
+ let isServerStartup = false;
+ // If you have no valid aliases in the db, the server is starting up
+ if (validAliasesInDb.length === 0) {
+ log(`Server startup: No valid aliases in the database.`);
+ isServerStartup = true;
+ // No point in checking database for serverState. Assume startup.
+ // For edge case where user has serverState reflecting processed blocks,
+ // this assumption will overwrite it correctly at the end of this block found loop
+ serverState = config.database.startup.serverState;
- let processedBlockheight, processedConfirmedTxs;
- // If you have aliases in the db and processedConfirmedTxs in serverState,
- // determine the most recently processed block and processedConfirmedTxs
- if (
- validAliasesInDb &&
- validAliasesInDb.length > 0 &&
- serverStateArray.length > 0 &&
- serverStateArray[0] &&
- typeof serverStateArray[0].processedConfirmedTxs !==
- 'undefined'
- ) {
- /*
- Note processedBlockheight is not the same as the blockheight of
- the most recent alias tx
- */
- processedBlockheight = serverState.processedBlockheight;
- processedConfirmedTxs = serverState.processedConfirmedTxs;
- log(`processedBlockheight`, processedBlockheight);
- log(`processedConfirmedTxs`, processedConfirmedTxs);
- } else {
- log(
- `Server startup. There are no valid aliases in the database.`,
- );
- // If nothing is in cache, get the full tx history
- processedBlockheight = 0;
- processedConfirmedTxs = 0;
// If validAliasesInDb is empty, set it to ABC whitelist
// This will be built on with getUnprocessedValidAliasRegistrations()
validAliasesInDb = generateReservedAliasTxArray();
@@ -147,22 +88,25 @@
log(
`Initializing ${config.database.collections.validAliases} with reserved aliases`,
);
- try {
- const reservedAliasTxsCollectionInsertResult = await db
- .collection(
- config.database.collections.validAliases,
- )
- .insertMany(validAliasesInDb);
- log(
- `Inserted ${reservedAliasTxsCollectionInsertResult.insertedCount} reserved aliases into ${config.database.collections.validAliases}`,
- );
- } catch (err) {
+ let validAliasesDbInitializedWithReservedAliases =
+ await addAliasesToDb(db, validAliasesInDb);
+ if (!validAliasesDbInitializedWithReservedAliases) {
log(
- `Error in db.collection(${config.database.collections.validAliases}.insertMany on server startup)`,
- err,
+ `Failed to initialize validAliases collection with reserved aliases`,
);
+ // Don't stop processing in this case. This does not create a risk of corrupting alias info.
+ }
+ } else {
+ // Get server state
+ serverState = await getServerStateFromDb(db);
+ if (!serverState) {
+ // Break out of this loop
+ // API will continue to show the last alias set we know to be valid
+ return;
}
}
+ const { processedBlockheight, processedConfirmedTxs } =
+ serverState;
// Look for unprocessed transactions at alias registration address
const unprocessedTxs = await getUnprocessedTxHistory(
@@ -176,8 +120,12 @@
//TODO
// if unprocessedTxs is zero, should be able to just exit
// probably irrelevant for IFP address which will always have coinbase txs
- for (let i = 0; i < unprocessedTxs.length; i += 1) {
- log(`Unprocessed tx: ${unprocessedTxs[i].txid}`);
+
+ // Only log unprocessed txs if this is not server startup
+ if (!isServerStartup) {
+ for (let i = 0; i < unprocessedTxs.length; i += 1) {
+ log(`Unprocessed tx: ${unprocessedTxs[i].txid}`);
+ }
}
// Process unprocessed alias txs
@@ -204,7 +152,7 @@
);
// If you are starting up the server, and have 100s of aliases to log, don't
- if (newlyValidAliasTxs.length < 25) {
+ if (!isServerStartup) {
for (let i = 0; i < newlyValidAliasTxs.length; i += 1) {
log(
`New valid alias processed: ${newlyValidAliasTxs[i].alias}`,
@@ -245,43 +193,23 @@
`Updating ${processedConfirmedTxs} from ${processedConfirmedTxs} to ${updatedProcessedConfirmedTxs}`,
);
- // Update server state
- // An empty document will update the first document returned in the collection
- // serverState only has one document
- const serverStateQuery = {};
- const serverStateUpdate = {
- $set: {
- processedConfirmedTxs: updatedProcessedConfirmedTxs,
- processedBlockheight: updatedProcessedBlockheight,
- },
+ // Update server state in database
+ const newServerState = {
+ processedConfirmedTxs: updatedProcessedConfirmedTxs,
+ processedBlockheight: updatedProcessedBlockheight,
};
- // If you are running the server for the first time and there is no
- // serverState in the db, create it
- const serverStateOptions = { upsert: true };
- let serverStateUpdateResult;
- try {
- serverStateUpdateResult = await db
- .collection(config.database.collections.serverState)
- .updateOne(
- serverStateQuery,
- serverStateUpdate,
- serverStateOptions,
- );
+ const serverStateUpdatedInDb = await updateServerStateInDb(
+ db,
+ newServerState,
+ );
+ if (!serverStateUpdatedInDb) {
+ // If serverState isn't updated, this API endpoint could become inconsistent with
+ // valid aliases in the db
+ // Stop this loop before you update valid aliases
log(
- `Updated serverState.processedConfirmedTxs from ${processedConfirmedTxs} to ${updatedProcessedConfirmedTxs}.`,
+ `Server state failed to update for block ${wsMsg.blockHash}, exiting loop.`,
);
- } catch (err) {
- // If this isn't updated, the server will process too many txs next time
- // Let the admin know. This won't impact parsing but will cause processing too many txs
- const errMsg = `Error in db.collection(${config.database.collections.serverState}).update(${serverStateQuery}, ${serverStateUpdate})`;
- log(errMsg, err);
- const adminNotifyMsg = `${errMsg}\n\n${err}`;
- const adminNotified = await sendAdminAlert(
- adminNotifyMsg,
- );
- if (!adminNotified) {
- log(`Admin notification failed to send`);
- }
+ return;
}
} else {
log(`No new confirmed alias txs since last block`);
@@ -289,34 +217,19 @@
if (newlyValidAliasTxs.length > 0) {
// Update validAliasTxs
- try {
- const validAliasTxsCollectionInsertResult = await db
- .collection(
- config.database.collections.validAliases,
- )
- .insertMany(newlyValidAliasTxs);
- log(
- `Inserted ${validAliasTxsCollectionInsertResult.insertedCount} aliases into ${config.database.collections.validAliases}`,
- );
- } catch (err) {
- log(
- `Error in db.collection(${config.database.collections.validAliases}.insertMany)`,
- err,
- );
- /*
- let ids = err.result.result.insertedIds;
- for (let id of Object.values(ids)) {
- log(`Processed a document with id ${id._id}`);
- }
-
+ let newlyValidAliasesAddedToDb = await addAliasesToDb(
+ db,
+ newlyValidAliasTxs,
+ );
+ if (!newlyValidAliasesAddedToDb) {
log(
- `Number of documents inserted: ${err.result.result.nInserted}`,
+ `alias-server failed to add newly valid aliases to the database for block ${wsMsg.blockHash}`,
);
- */
+ // Admin is notified. No point in breaking out of the loop here.
}
// To prevent rate limiting, do not send Telegram msg on server startup
- if (processedBlockheight !== 0) {
+ if (!isServerStartup) {
// Get the XEC price to use in the Telegram msgs
let coingeckoPriceResponse;
let xecPrice;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Feb 6, 16:23 (17 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5082685
Default Alt Text
D13484.id38990.diff (20 KB)
Attached To
D13484: [alias-server] Organize db functions in separate file
Event Timeline
Log In to Comment