Skip to content

Commit

Permalink
mempool#144 - Extract NostrEventId instead Npub (#16)
Browse files Browse the repository at this point in the history
* fix: updates signet challenge

* feat(eventId): initial commit

* feat(event-id): removes npub from query

* feat(eventId): updates unit tests
  • Loading branch information
nostrdev-com authored Dec 18, 2024
1 parent ffce32d commit f5fb3a7
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 53 deletions.
38 changes: 21 additions & 17 deletions backend/src/angor/AngorTransactionDecoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,19 @@ export class AngorTransactionDecoder {
const founderKeyHashInt = this.hashToInt(founderKeyHash);
const projectIdDerivation = this.getProjectIdDerivation(founderKeyHashInt);
const projectId = this.getProjectId(projectIdDerivation);
const nostrPubKey = this.getNostrPubKey();
const nostrEventId = this.getNostrEventId();
const addressOnFeeOutput = this.getAddressOnFeeOutput();
const txid = this.transaction.getId();

// Store Angor project in the DB.
await this.storeProjectInfo(
projectId,
nostrPubKey,
addressOnFeeOutput,
transactionStatus,
founderKeyHex,
txid,
createdOnBlock
createdOnBlock,
nostrEventId
);

// If transaction is confirmed (in the block), update statuses
Expand Down Expand Up @@ -224,23 +224,27 @@ export class AngorTransactionDecoder {
const chunks = bitcoinJS.script.toASM(decompiled).split(' ');

// Throw an error if the chunks amount is incorrect.
if (chunks.length !== 3) {
if (chunks.length !== 4) {
throw new Error(`${errorBase} Wrong chunk amount.`);
}

// Throw an error if the first chunk is not OP_RETURN.
if (chunks[0] !== 'OP_RETURN') {
throw new Error(`${errorBase} Wrong first chunk.`);
throw new Error(`${errorBase} Wrong OP_RETURN chunk.`);
}

// Throw an error if the byte length of the second chunk is not 33.
if (Buffer.from(chunks[1], 'hex').byteLength !== 33) {
throw new Error(`${errorBase} Wrong second chunk.`);
throw new Error(`${errorBase} Wrong founder pubkey chunk.`);
}

// Throw an error if the byte length of the third chunk is not 32.
if (Buffer.from(chunks[2], 'hex').byteLength !== 32) {
throw new Error(`${errorBase} Wrong third chunk.`);
if (Buffer.from(chunks[2], 'hex').byteLength !== 2) {
throw new Error(`${errorBase} Wrong key type chunk.`);
}

if (Buffer.from(chunks[3], 'hex').byteLength !== 32) {
throw new Error(`${errorBase} Wrong nostr event ID chunk.`);
}

// Remove the first chunk (OP_RETURN) as it is not useful anymore.
Expand Down Expand Up @@ -405,13 +409,13 @@ export class AngorTransactionDecoder {
}

/**
* Sets Nostr public key.
* @returns - string representing Nostr public key of Angor project.
* Sets Nostr event id.
* @return - string representing the Nostr event ID associated with the current Angor project.
* @private
*/
private getNostrPubKey(): string {
private getNostrEventId(): string {
const chunks = this.decompileProjectCreationOpReturnScript();

return chunks[1];
return chunks[2];
}

/**
Expand All @@ -434,21 +438,21 @@ export class AngorTransactionDecoder {
*/
private async storeProjectInfo(
projectId: string,
nostrPubKey: string,
addressOnFeeOutput: string,
transactionStatus: AngorTransactionStatus,
founderKey: string,
txid: string,
createdOnBlock?: number
createdOnBlock?: number,
nostrEventId?: string
): Promise<void> {
await AngorProjectRepository.$setProject(
projectId,
nostrPubKey,
addressOnFeeOutput,
transactionStatus,
founderKey,
txid,
createdOnBlock
createdOnBlock,
nostrEventId
);
}

Expand Down
37 changes: 18 additions & 19 deletions backend/src/angor/tests/AngorTransactionDecoder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,22 @@ import {
import * as bitcoinJS from 'bitcoinjs-lib';
import AngorProjectRepository from '../../repositories/AngorProjectRepository';
import AngorInvestmentRepository from '../../repositories/AngorInvestmentRepository';
import DB from '../../database';

describe('AngorTransactionDecoder', () => {
describe('Decoding transaction for Angor project creation', () => {
const data = {
transactionHex:
'0100000000010138de40ff6a3d27c33d5b84edf8f35911d819c9c547689cc4da6c5603bc3b26990000000000ffffffff0310270000000000001600144282ccfe323dbba535ccdfc8b66aeeb0bd7dd95b0000000000000000446a210352eb18befb145fef4b5c24513608183d7c3d8004d5fcad9e0e6dc2e89a0af6ae20c749d81fc42037e5b9f7b32ae266cbce75019ce6771be6877d3c509e97e39c14669b052a0100000016001431e5c2bdb361b68eb243ec7dbd46bd7cf71a1d86024730440220075dd33e3809a58423257bf23f5632e305387c283f48dfdce7f355787be33d8002201072fa636fb6bad35ac9d7f8e35fb41eea47de8b38346dc4f123260e9c74c3b401210385143acd30d6d05a5bf35ef1028ce4c50eadffa14670716976007fec5ed3e58500000000',
'01000000000101899c7a384fe0e17dfd3d56fcf6bfff796b5d0f40ecb5bc513a92e891bb2018af0200000000ffffffff031127000000000000160014e6285b56cb7cd9a51af2f28cb02762b5298c98db0000000000000000476a2102070d174561688500aac733116dbe70c5ab7480559d25e1c040f480491870c8ba020100200f2d8db8568bd3e12bdab1faa217fffc80459053967eff8bde0a65f14e2b7079d542052a01000000160014ae63769a0b0a5f69b3be5d1e6bb4b00d15eff7d0024830450221008e797faa2ef8c3e91ff03f4a47e76740cbadf4b5061d0508ffd89ab869891cb2022050c624530f5c6afbe6ec0dcba4c81287431595f89370225f7d12d3866cc0499f01210396d79f9c4a836defed971668ea51ed50495d5e2d205da2590e7f6600af03f8c800000000',
founderKeyHex:
'0352eb18befb145fef4b5c24513608183d7c3d8004d5fcad9e0e6dc2e89a0af6ae',
'02070d174561688500aac733116dbe70c5ab7480559d25e1c040f480491870c8ba',
founderKeyHashHex:
'cacedcee9bc28a37b36718ea210fcf7caac182cdb66cc17fafb6027478a221c8',
founderKeyHashInt: 2023891400,
projectIdDeriviation: 1011945700,
projectId: 'angor1qg2pvel3j8ka62dwvmlytv6hwkz7hmk2mms7qll',
nPub: 'c749d81fc42037e5b9f7b32ae266cbce75019ce6771be6877d3c509e97e39c14',
addressOnFeeOutput: 'tb1qg2pvel3j8ka62dwvmlytv6hwkz7hmk2m0ncfee',
txid: '00b78119bb6eff9f64b2d29948ddd830f405b18dfdb802a3ec2df4eacfcd1f40',
'68828edc1c6312c915c8967475be57f42d45764105af8216f2da7170d033240a',
founderKeyHashInt: 3493012490,
projectIdDeriviation: 1746506245,
projectId: 'angor1qzkfpckm2vnhdvfcwr7vdhwt7ns3rd95gr0age0',
nostrEventId: '0f2d8db8568bd3e12bdab1faa217fffc80459053967eff8bde0a65f14e2b7079',
addressOnFeeOutput: 'tb1quc59k4kt0nv62xhj72xtqfmzk55cexxmae8lyc',
txid: '0d28976a42bf7618ad9470cf0202e2eb06d6072e75e139eab012a160b7b480aa',
blockHeight: 40000,
};

Expand Down Expand Up @@ -154,11 +153,11 @@ describe('AngorTransactionDecoder', () => {

const {
projectId,
nPub,
addressOnFeeOutput,
founderKeyHex,
txid,
blockHeight,
nostrEventId
} = data;

await angorDecoder.decodeAndStoreProjectCreationTransaction(
Expand All @@ -168,12 +167,12 @@ describe('AngorTransactionDecoder', () => {

expect(setProjectSpy).toHaveBeenCalledWith(
projectId,
nPub,
addressOnFeeOutput,
transactionStatus,
founderKeyHex,
txid,
blockHeight
blockHeight,
nostrEventId
);

expect(updateInvestmentStatusSpy).toHaveBeenCalledWith(
Expand All @@ -188,10 +187,10 @@ describe('AngorTransactionDecoder', () => {
jest.restoreAllMocks();
});

it('should return 2 chunks', () => {
it('should return 3 chunks', () => {
const chunks = angorDecoder['decompileProjectCreationOpReturnScript']();

expect(chunks.length).toEqual(2);
expect(chunks.length).toEqual(3);

chunks.forEach((chunk) => expect(typeof chunk).toEqual('string'));
});
Expand Down Expand Up @@ -290,9 +289,9 @@ describe('AngorTransactionDecoder', () => {
});
});

describe('getNostrPubKey', () => {
it('should return Nostr public key', () => {
expect(angorDecoder['getNostrPubKey']()).toEqual(data.nPub);
describe('getNostrEventId', () => {
it('should return nostrEventId', () => {
expect(angorDecoder['getNostrEventId']()).toEqual(data.nostrEventId);
});
});
});
Expand Down Expand Up @@ -339,10 +338,10 @@ describe('AngorTransactionDecoder', () => {
.mockImplementation(() =>
Promise.resolve({
founder_key: '',
npub: '',
id: '',
created_on_block: 1,
txid: '',
nostr_event_id: ''
})
);

Expand Down
8 changes: 4 additions & 4 deletions backend/src/api/angor/angor.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import { fetchAngorVouts, computeAdvancedStats, computeStatsTally } from './ango

interface ProjectsPayloadItem {
founderKey: string;
nostrPubKey: string;
projectIdentifier: string;
createdOnBlock: number;
trxId: string;
nostrEventId: string;
}
interface ProjectPayloadItem {
founderKey: string;
nostrPubKey: string;
projectIdentifier: string;
createdOnBlock: number;
trxId: string;
nostrEventId: string;
totalInvestmentsCount: number;
}

Expand Down Expand Up @@ -150,10 +150,10 @@ class AngorRoutes {
const payload: ProjectsPayloadItem[] = projects
.map((project) => ({
founderKey: project.founder_key,
nostrPubKey: project.npub,
projectIdentifier: project.id,
createdOnBlock: project.created_on_block,
trxId: project.txid,
nostrEventId: project.nostr_event_id
}))
.sort(
(p1: ProjectsPayloadItem, p2: ProjectsPayloadItem) =>
Expand Down Expand Up @@ -197,10 +197,10 @@ class AngorRoutes {
// Adjust DB data to confirm ProjectsPayloadItem interface.
const payload: ProjectPayloadItem = {
founderKey: project.founder_key,
nostrPubKey: project.npub,
projectIdentifier: project.id,
createdOnBlock: project.created_on_block,
trxId: project.txid,
nostrEventId: project.nostr_event_id,
totalInvestmentsCount: project.investments_count,
};

Expand Down
3 changes: 1 addition & 2 deletions backend/src/api/database-migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ class DatabaseMigration {
*/
public async $initializeOrMigrateDatabase(): Promise<void> {
logger.debug('MIGRATIONS: Running migrations');

await this.$printDatabaseVersion();

// First of all, if the `state` database does not exist, create it so we can track migration version
Expand Down Expand Up @@ -1285,11 +1284,11 @@ class DatabaseMigration {
private getCreateAngorProjectsTableQuery(): string {
return `CREATE TABLE IF NOT EXISTS angor_projects (
id CHAR(45) NOT NULL,
npub CHAR(64) NOT NULL,
address_on_fee_output CHAR(51) NOT NULL,
creation_transaction_status VARCHAR(10) NOT NULL,
created_on_block INT(10),
txid VARCHAR(64) NOT NULL,
nostr_event_id VARCHAR(64),
founder_key VARCHAR(66) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`;
Expand Down
19 changes: 10 additions & 9 deletions backend/src/repositories/AngorProjectRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { AngorTransactionStatus } from '../angor/AngorTransactionDecoder';

export interface Project {
founder_key: string;
npub: string;
id: string;
created_on_block: number;
txid: string;
nostr_event_id: string;
}

interface ProjectWithInvestmentsCount extends Project {
Expand Down Expand Up @@ -36,34 +36,35 @@ class AngorProjectRepository {
/**
* Stores Angor project into the DB.
* @param id - project Id.
* @param npub - project Nostr public key.
* @param addressOnFeeOutput - address on fee output.
* @param transactionStatus - transaction status.
* @param founderKey - founder nostr pubkey.
* @param txid - transaction ID.
* @param createdOnBlock - block height (optional).
* @param nostrEventId - nostr event ID associated with the project
*/
public async $setProject(
id: string,
npub: string,
addressOnFeeOutput: string,
transactionStatus: AngorTransactionStatus,
founderKey: string,
txid: string,
createdOnBlock?: number
createdOnBlock?: number,
nostrEventId?: string
): Promise<void> {
try {
logger.debug(`nostrEventId=${nostrEventId}`);
const query = `INSERT INTO angor_projects
(
id,
npub,
address_on_fee_output,
creation_transaction_status,
created_on_block,
txid,
founder_key
founder_key,
nostr_event_id
)
VALUES ('${id}', '${npub}', '${addressOnFeeOutput}', '${transactionStatus}', ${createdOnBlock}, '${txid}', '${founderKey}')
VALUES ('${id}', '${addressOnFeeOutput}', '${transactionStatus}', '${createdOnBlock}', '${txid}', '${founderKey}', '${nostrEventId}')
ON DUPLICATE KEY UPDATE
creation_transaction_status = '${transactionStatus}'
`;
Expand Down Expand Up @@ -117,9 +118,9 @@ class AngorProjectRepository {
const query = `SELECT
angor_projects.id,
angor_projects.founder_key,
angor_projects.npub,
angor_projects.created_on_block,
angor_projects.txid,
angor_projects.nostr_event_id,
COUNT(angor_investments.txid) AS investments_count
FROM angor_projects
LEFT JOIN angor_investments
Expand Down Expand Up @@ -267,7 +268,7 @@ class AngorProjectRepository {
const order = 'DESC';

try {
const query = `SELECT id, founder_key, npub, created_on_block, txid
const query = `SELECT id, founder_key, created_on_block, txid, nostr_event_id
FROM angor_projects
WHERE creation_transaction_status = '${
AngorTransactionStatus.Confirmed
Expand Down
4 changes: 2 additions & 2 deletions docker-angor-api/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ services:
MINERENABLED: ${MINERENABLED:-0} # change this to 1 if this node needs to mine (however for simplicity there should only be one mining node per challenge)
NBITS: $NBITS
MINETO: ${MINETO:-tb1qk4pq0rh75qtph47wlufhyss43flhvhvwe4zt8a}
PRIVKEY: ${PRIVKEY:-cRz3Ci2aUNmdP4pViSM8LafwKHZmvn4X6gjeCXzVkBYBLhzA3uFC} # private key path is m/84'/1'/0'/0/0 of test wallet mnemonic "margin radio diamond leg loud street announce guitar video shiver speed eyebrow"
SIGNETCHALLENGE: ${SIGNETCHALLENGE:-512102b57c4413a0354bcc360a37e035f26670deda14bab613c28fbd30fe52b2deccc151ae}
PRIVKEY: ${PRIVKEY:-cNDhpWanXGyCed6U7eBNqRN3EyB7mEUbqm19tA7z5ho6BiNaPfmy} # private key path is m/84'/1'/0'/0/0 of test wallet mnemonic "margin radio diamond leg loud street announce guitar video shiver speed eyebrow"
SIGNETCHALLENGE: ${SIGNETCHALLENGE:-512102a3f8184701a033e5f8faa295647374b0bbc868082240d6e7ad8e9ecb0d86e6d451ae}
EXTERNAL_IP: $EXTERNAL_IP
ADDNODE: ${ADDNODE:-207.180.254.78}
RPCUSER: ${RPCUSER:-rpcuser}
Expand Down

0 comments on commit f5fb3a7

Please sign in to comment.