Skip to content

Commit

Permalink
mempool#148 - Add Angor Config (#23)
Browse files Browse the repository at this point in the history
* feat(angor-config): adds backend config

* feat(angor-config): adds frontend config

* feat(angor-config): adds frontend config

* chore: updates docker-compose

* feat(angor-config): optionally create angor tables

* refactor: moves angor db creation
  • Loading branch information
nostrdev-com authored Dec 30, 2024
1 parent 94ed390 commit 8fa9e03
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 72 deletions.
3 changes: 3 additions & 0 deletions backend/mempool-config.sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -159,5 +159,8 @@
"ENABLED": true,
"PAID": false,
"API_KEY": "your-api-key-from-freecurrencyapi.com"
},
"ANGOR": {
"ENABLED": true
}
}
4 changes: 4 additions & 0 deletions backend/src/__tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ describe('Mempool Backend Config', () => {
PAID: false,
API_KEY: '',
});

expect(config.ANGOR).toStrictEqual({
ENABLED: false
});
});
});

Expand Down
59 changes: 31 additions & 28 deletions backend/src/api/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -976,35 +976,38 @@ class Blocks {
// New block is saved to the DB.
// Decode block transaction with Angor decoder to identify transactions
// related to Angor projects.
const transactionIds = await bitcoinApi.$getTxIdsForBlock(blockHash);

for (const transactionId of transactionIds) {
const transactionHex = await bitcoinApi.$getTransactionHex(
transactionId
);

const angorDecoder = new AngorTransactionDecoder(
transactionHex,
AngorSupportedNetworks.Testnet
);

await angorDecoder
.decodeAndStoreProjectCreationTransaction(
AngorTransactionStatus.Confirmed,
blockExtended.height
)
.catch(async () => {
await angorDecoder
.decodeAndStoreInvestmentTransaction(
AngorTransactionStatus.Confirmed,
blockExtended.height
)
.catch(() => {
// Ignore error.
});
});
}

if (config.ANGOR.ENABLED) {
const transactionIds = await bitcoinApi.$getTxIdsForBlock(blockHash);

for (const transactionId of transactionIds) {
const transactionHex = await bitcoinApi.$getTransactionHex(
transactionId
);

const angorDecoder = new AngorTransactionDecoder(
transactionHex,
AngorSupportedNetworks.Testnet
);

await angorDecoder
.decodeAndStoreProjectCreationTransaction(
AngorTransactionStatus.Confirmed,
blockExtended.height
)
.catch(async () => {
await angorDecoder
.decodeAndStoreInvestmentTransaction(
AngorTransactionStatus.Confirmed,
blockExtended.height
)
.catch(() => {
// Ignore error.
});
});
}
}

if (!fastForwarded) {
let lastestPriceId;
try {
Expand Down
29 changes: 17 additions & 12 deletions backend/src/api/database-migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ class DatabaseMigration {
logger.debug('MIGRATIONS: `state` table initialized.');
}

// Create Angor tables
if (config.ANGOR.ENABLED) {
await this.$executeQuery(
this.getCreateAngorProjectsTableQuery(),
await this.$checkIfTableExists('angor_projects')
);
await this.$executeQuery(
this.getCreateAngorInvestmentsTableQuery(),
await this.$checkIfTableExists('angor_investments')
);
await this.$executeQuery(
this.getCreateAngorBlocksTableQuery(),
await this.$checkIfTableExists('angor_blocks')
);
}

let databaseSchemaVersion = 0;
try {
databaseSchemaVersion = await this.$getSchemaVersionFromDatabase();
Expand Down Expand Up @@ -101,24 +117,13 @@ class DatabaseMigration {
* Create all missing tables
*/
private async $createMissingTablesAndIndexes(databaseSchemaVersion: number) {
logger.debug('create missing tables runs');
await this.$setStatisticsAddedIndexedFlag(databaseSchemaVersion);

const isBitcoin = ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK);

await this.$executeQuery(this.getCreateElementsTableQuery(), await this.$checkIfTableExists('elements_pegs'));
await this.$executeQuery(this.getCreateStatisticsQuery(), await this.$checkIfTableExists('statistics'));
await this.$executeQuery(
this.getCreateAngorProjectsTableQuery(),
await this.$checkIfTableExists('angor_projects')
);
await this.$executeQuery(
this.getCreateAngorInvestmentsTableQuery(),
await this.$checkIfTableExists('angor_investments')
);
await this.$executeQuery(
this.getCreateAngorBlocksTableQuery(),
await this.$checkIfTableExists('angor_blocks')
);
if (databaseSchemaVersion < 2 && this.statisticsAddedIndexed === false) {
await this.$executeQuery(`CREATE INDEX added ON statistics (added);`);
await this.updateToSchemaVersion(2);
Expand Down
46 changes: 24 additions & 22 deletions backend/src/api/mempool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Mempool {
private mempoolProtection = 0;
private latestTransactions: any[] = [];

private ESPLORA_MISSING_TX_WARNING_THRESHOLD = 100;
private ESPLORA_MISSING_TX_WARNING_THRESHOLD = 100;
private SAMPLE_TIME = 10000; // In ms
private timer = new Date().getTime();
private missingTxCount = 0;
Expand Down Expand Up @@ -383,27 +383,29 @@ class Mempool {

// Use Angor decoder to identify transaction related to Angor projects that
// were added to the mempool.
for (const transaction of newTransactions) {
const { txid } = transaction;

const transactionHex = await bitcoinApi.$getTransactionHex(txid);

const angorDecoder = new AngorTransactionDecoder(
transactionHex,
AngorSupportedNetworks.Testnet
);

await angorDecoder
.decodeAndStoreProjectCreationTransaction(
AngorTransactionStatus.Pending
)
.catch(async () => {
await angorDecoder
.decodeAndStoreInvestmentTransaction(AngorTransactionStatus.Pending)
.catch(() => {
// Ignore error.
});
});
if (config.ANGOR.ENABLED) {
for (const transaction of newTransactions) {
const { txid } = transaction;

const transactionHex = await bitcoinApi.$getTransactionHex(txid);

const angorDecoder = new AngorTransactionDecoder(
transactionHex,
AngorSupportedNetworks.Testnet
);

await angorDecoder
.decodeAndStoreProjectCreationTransaction(
AngorTransactionStatus.Pending
)
.catch(async () => {
await angorDecoder
.decodeAndStoreInvestmentTransaction(AngorTransactionStatus.Pending)
.catch(() => {
// Ignore error.
});
});
}
}

if (!this.inSync && transactions.length === newMempoolSize) {
Expand Down
8 changes: 8 additions & 0 deletions backend/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ interface IConfig {
WALLETS: {
ENABLED: boolean;
WALLETS: string[];
},
ANGOR: {
ENABLED: boolean;
}
}

Expand Down Expand Up @@ -332,6 +335,9 @@ const defaults: IConfig = {
'ENABLED': false,
'WALLETS': [],
},
'ANGOR': {
'ENABLED': false
}
};

class Config implements IConfig {
Expand All @@ -354,6 +360,7 @@ class Config implements IConfig {
REDIS: IConfig['REDIS'];
FIAT_PRICE: IConfig['FIAT_PRICE'];
WALLETS: IConfig['WALLETS'];
ANGOR: IConfig['ANGOR'];

constructor() {
const configs = this.merge(configFromFile, defaults);
Expand All @@ -376,6 +383,7 @@ class Config implements IConfig {
this.REDIS = configs.REDIS;
this.FIAT_PRICE = configs.FIAT_PRICE;
this.WALLETS = configs.WALLETS;
this.ANGOR = configs.ANGOR;
}

merge = (...objects: object[]): IConfig => {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ class Server {
if (!config.MEMPOOL.OFFICIAL) {
aboutRoutes.initRoutes(this.app);
}
if (config.DATABASE.ENABLED) {
if (config.DATABASE.ENABLED && config.ANGOR.ENABLED) {
angorRoutes.initRoutes(this.app);
}

Expand Down
6 changes: 3 additions & 3 deletions backend/src/indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ class Indexer {

// Index transactions related to Angor projects.
// This operation should be done once when initial indexing is complete.
await this.indexAngorTransactions();


if (config.ANGOR.ENABLED) {
await this.indexAngorTransactions();
}
blocks.$classifyBlocks();
} catch (e) {
this.indexerRunning = false;
Expand Down
2 changes: 2 additions & 0 deletions docker-angor-api/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ services:
STATISTICS_ENABLED: "true"
MEMPOOL_STDOUT_LOG_MIN_PRIORITY: "debug"
MEMPOOL_INDEXING_BLOCKS_AMOUNT: -1
ANGOR_ENABLED: "true"
VIRTUAL_HOST: indexer.angor.io
VIRTUAL_PORT: 8999
VIRTUAL_PROTO: http
Expand Down Expand Up @@ -111,6 +112,7 @@ services:
FRONTEND_HTTP_PORT: "8080"
BACKEND_MAINNET_HTTP_HOST: "mempool_api"
LIGHTNING: "false"
ANGOR_ENABLED: "true"
VIRTUAL_HOST: explorer.angor.io
VIRTUAL_PORT: 8080
VIRTUAL_PROTO: http
Expand Down
3 changes: 3 additions & 0 deletions docker/backend/mempool-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,8 @@
"ENABLED": __FIAT_PRICE_ENABLED__,
"PAID": __FIAT_PRICE_PAID__,
"API_KEY": "__FIAT_PRICE_API_KEY__"
},
"ANGOR": {
"ENABLED": __ANGOR_ENABLED__
}
}
6 changes: 6 additions & 0 deletions docker/backend/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ __FIAT_PRICE_ENABLED__=${FIAT_PRICE_ENABLED:=true}
__FIAT_PRICE_PAID__=${FIAT_PRICE_PAID:=false}
__FIAT_PRICE_API_KEY__=${FIAT_PRICE_API_KEY:=""}

# ANGOR
__ANGOR_ENABLED__=${ANGOR_ENABLED:=false}

mkdir -p "${__MEMPOOL_CACHE_DIR__}"

sed -i "s!__MEMPOOL_NETWORK__!${__MEMPOOL_NETWORK__}!g" mempool-config.json
Expand Down Expand Up @@ -310,4 +313,7 @@ sed -i "s!__FIAT_PRICE_ENABLED__!${__FIAT_PRICE_ENABLED__}!g" mempool-config.jso
sed -i "s!__FIAT_PRICE_PAID__!${__FIAT_PRICE_PAID__}!g" mempool-config.json
sed -i "s!__FIAT_PRICE_API_KEY__!${__FIAT_PRICE_API_KEY__}!g" mempool-config.json

# ANGOR
sed -i "s! __ANGOR_ENABLED__!${__ANGOR_ENABLED__}!g" mempool-config.json

node /backend/package/index.js
2 changes: 2 additions & 0 deletions docker/frontend/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ __SERVICES_API__=${SERVICES_API:=https://mempool.space/api/v1/services}
__PUBLIC_ACCELERATIONS__=${PUBLIC_ACCELERATIONS:=false}
__HISTORICAL_PRICE__=${HISTORICAL_PRICE:=true}
__ADDITIONAL_CURRENCIES__=${ADDITIONAL_CURRENCIES:=false}
__ANGOR_ENABLED__=${ANGOR_ENABLED:=false}

# Export as environment variables to be used by envsubst
export __MAINNET_ENABLED__
Expand Down Expand Up @@ -76,6 +77,7 @@ export __SERVICES_API__
export __PUBLIC_ACCELERATIONS__
export __HISTORICAL_PRICE__
export __ADDITIONAL_CURRENCIES__
export __ANGOR_ENABLED__

folder=$(find /var/www/mempool -name "config.js" | xargs dirname)
echo ${folder}
Expand Down
3 changes: 2 additions & 1 deletion frontend/mempool-frontend-config.sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@
"ACCELERATOR": false,
"ACCELERATOR_BUTTON": true,
"PUBLIC_ACCELERATIONS": false,
"SERVICES_API": "https://mempool.space/api/v1/services"
"SERVICES_API": "https://mempool.space/api/v1/services",
"ANGOR_ENABLED": true
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
<li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}" id="btn-pools" *ngIf="stateService.env.MINING_DASHBOARD">
<a class="nav-link" [routerLink]="['/mining' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'hammer']" [fixedWidth]="true" i18n-title="mining.mining-dashboard" title="Mining Dashboard"></fa-icon></a>
</li>
<li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}" id="btn-angor">
<li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}" id="btn-angor" *ngIf="stateService.isAngorEnabled()">
<a class="nav-link" [routerLink]="['/angor' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'boxes-stacked']" [fixedWidth]="true" title="Angor Projects"></fa-icon>
</a>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export class SearchFormComponent implements OnInit {
(data) => { this.navigate('/block/', data.hash); },
(error) => { console.log(error); this.isSearching = false; }
);
} else if (this.regexAngor.test(searchText)) {
} else if (this.stateService.isAngorEnabled() && this.regexAngor.test(searchText)) {
this.navigate('/angor/projects/', searchText);
} else {
this.isSearching = false;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/master-page.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const routes: Routes = [
{
path: 'angor',
loadChildren: () => import('@app/angor/angor.module').then(m => m.AngorModule),
data: { preload: true },
data: { preload: browserWindowEnv && browserWindowEnv.ANGOR_ENABLED === true },
},
{
path: 'lightning',
Expand Down
10 changes: 8 additions & 2 deletions frontend/src/app/services/state.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export interface Env {
SERVICES_API?: string;
customize?: Customization;
PROD_DOMAINS: string[];
ANGOR_ENABLED: boolean;
}

const defaultEnv: Env = {
Expand Down Expand Up @@ -125,6 +126,7 @@ const defaultEnv: Env = {
'ADDITIONAL_CURRENCIES': false,
'SERVICES_API': 'https://mempool.space/api/v1/services',
'PROD_DOMAINS': [],
'ANGOR_ENABLED': false
};

@Injectable({
Expand Down Expand Up @@ -334,7 +336,7 @@ export class StateService {
this.hideAudit.subscribe((hide) => {
this.storageService.setValue('audit-preference', hide ? 'hide' : 'show');
});

const fiatPreference = this.storageService.getValue('fiat-preference');
this.fiatCurrency$ = new BehaviorSubject<string>(fiatPreference || 'USD');

Expand Down Expand Up @@ -418,6 +420,10 @@ export class StateService {
return this.env.LIGHTNING && this.lightningNetworks.includes(this.network);
}

isAngorEnabled() {
return this.env.ANGOR_ENABLED;
}

getHiddenProp(){
const prefixes = ['webkit', 'moz', 'ms', 'o'];
if ('hidden' in document) { return 'hidden'; }
Expand Down Expand Up @@ -477,6 +483,6 @@ export class StateService {
focusSearchInputDesktop() {
if (!hasTouchScreen()) {
this.searchFocus$.next(true);
}
}
}
}

0 comments on commit 8fa9e03

Please sign in to comment.