Skip to content

Commit

Permalink
fix: add transaction submit eventHandler for nightfall-client
Browse files Browse the repository at this point in the history
LijuJoseJJ committed Mar 28, 2023

Verified

This commit was signed with the committer’s verified signature. The key has expired.
lawliet89 Yong Wen Chua
1 parent a5c326d commit e2d769e
Showing 6 changed files with 146 additions and 3 deletions.
19 changes: 18 additions & 1 deletion nightfall-client/src/event-handlers/block-proposed.mjs
Original file line number Diff line number Diff line change
@@ -14,8 +14,9 @@ import {
setSiblingInfo,
countCircuitTransactions,
isTransactionHashBelongCircuit,
deleteNonNullifiedCommitments,
} from '../services/commitment-storage.mjs';
import getProposeBlockCalldata from '../services/process-calldata.mjs';
import { getProposeBlockCalldata } from '../services/process-calldata.mjs';
import { zkpPrivateKeys, nullifierKeys } from '../services/keys.mjs';
import {
getTreeByBlockNumberL2,
@@ -24,6 +25,8 @@ import {
saveBlock,
setTransactionHashSiblingInfo,
getNumberOfL2Blocks,
findDuplicateTransactions,
deleteTransactionsByTransactionHashes,
} from '../services/database.mjs';
import { decryptCommitment } from '../services/commitment-sync.mjs';
import { syncState } from '../services/state-sync.mjs';
@@ -79,6 +82,7 @@ async function blockProposedEventHandler(data, syncing) {

const dbUpdates = transactions.map(async transaction => {
let saveTxToDb = false;
let duplicateTransactions = []; // duplicate tx holding same commitments or nullifiers

// filter out non zero commitments and nullifiers
const nonZeroCommitments = transaction.commitments.filter(c => c !== ZERO);
@@ -126,6 +130,12 @@ async function blockProposedEventHandler(data, syncing) {
...transaction,
isDecrypted,
});

duplicateTransactions = await findDuplicateTransactions(
nonZeroCommitments,
nonZeroNullifiers,
[transaction.transactionHash],
);
}

return Promise.all([
@@ -137,6 +147,13 @@ async function blockProposedEventHandler(data, syncing) {
data.blockNumber,
data.transactionHash,
),
deleteTransactionsByTransactionHashes([...duplicateTransactions.map(t => t.transactionHash)]),
deleteNonNullifiedCommitments([
...duplicateTransactions
.map(t => t.commitments)
.flat()
.filter(c => c !== ZERO),
]),
]);
});

3 changes: 3 additions & 0 deletions nightfall-client/src/event-handlers/index.mjs
Original file line number Diff line number Diff line change
@@ -2,15 +2,18 @@ import { startEventQueue } from './subscribe.mjs';
import blockProposedEventHandler from './block-proposed.mjs';
import rollbackEventHandler from './rollback.mjs';
import removeBlockProposedEventHandler from './chain-reorg.mjs';
import transactionSubmittedEventHandler from './transaction-submitted.mjs';

const eventHandlers = {
BlockProposed: blockProposedEventHandler,
TransactionSubmitted: transactionSubmittedEventHandler,
Rollback: rollbackEventHandler,
removers: {
BlockProposed: removeBlockProposedEventHandler,
},
priority: {
BlockProposed: 0,
TransactionSubmitted: 1,
Rollback: 0,
},
};
57 changes: 57 additions & 0 deletions nightfall-client/src/event-handlers/transaction-submitted.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import logger from '@polygon-nightfall/common-files/utils/logger.mjs';
import constants from '@polygon-nightfall/common-files/constants/index.mjs';
import { getTransactionSubmittedCalldata } from '../services/process-calldata.mjs';
import { countCommitments, countNullifiers } from '../services/commitment-storage.mjs';
import { saveTransaction } from '../services/database.mjs';

const { ZERO } = constants;

async function doesAnyOfCommitmentsExistInDB(commitments) {
const count = await countCommitments(commitments);
return Boolean(count);
}

async function doesAnyOfNullifiersExistInDB(nullifiers) {
const count = await countNullifiers(nullifiers);
return Boolean(count);
}

/**
* This handler runs whenever a new transaction is submitted to the blockchain
*/
async function transactionSubmittedEventHandler(eventParams) {
const { offchain = false, ...data } = eventParams;
let saveTxInDb = false;

const transaction = await getTransactionSubmittedCalldata(data);
transaction.blockNumber = data.blockNumber;
transaction.transactionHashL1 = data.transactionHash;

// logic: if any of non zero commitment in transaction alraedy exist in db
// i.e transaction belong to user using this nightfall-client.
// for example: for deposit we store commitment while transaction submit,
// similarly for transfer we store change commitment while transaction submit

// filter out non zero commitments and nullifiers
const nonZeroCommitments = transaction.commitments.filter(c => c !== ZERO);
const nonZeroNullifiers = transaction.nullifiers.filter(n => n !== ZERO);

if (await doesAnyOfCommitmentsExistInDB(nonZeroCommitments)) {
saveTxInDb = true;
} else if (doesAnyOfNullifiersExistInDB(nonZeroNullifiers)) {
saveTxInDb = true;
}

if (saveTxInDb) {
await saveTransaction({ ...transaction });
}

logger.info({
msg: 'Client Transaction Handler - New transaction received.',
transaction,
offchain,
saveTxInDb,
});
}

export default transactionSubmittedEventHandler;
8 changes: 8 additions & 0 deletions nightfall-client/src/services/commitment-storage.mjs
Original file line number Diff line number Diff line change
@@ -1072,3 +1072,11 @@ export async function getCommitmentsDepositedRollbacked(compressedZkpPublicKey)

return db.collection(COMMITMENTS_COLLECTION).find(query).toArray();
}

// function to delete non nullified commitments
export async function deleteNonNullifiedCommitments(commitments) {
const connection = await mongo.connection(MONGO_URL);
const query = { _id: { $in: commitments }, isNullifiedOnChain: -1 };
const db = connection.db(COMMITMENTS_DB);
return db.collection(COMMITMENTS_COLLECTION).deleteMany(query);
}
15 changes: 15 additions & 0 deletions nightfall-client/src/services/database.mjs
Original file line number Diff line number Diff line change
@@ -292,3 +292,18 @@ export async function getTransactionsByTransactionHashesByL2Block(transactionHas
);
return transactions;
}

/**
* Function to find duplicate transactions for an array of commitments or nullifiers
* this function is used in blockProposedEventHandler
*/
export async function findDuplicateTransactions(commitments, nullifiers, transactionHashes = []) {
const connection = await mongo.connection(MONGO_URL);
const db = connection.db(COMMITMENTS_DB);
const query = {
$or: [{ commitments: { $in: commitments } }, { nullifiers: { $in: nullifiers } }],
transactionHash: { $nin: transactionHashes },
blockNumberL2: { $exists: false },
};
return db.collection(TRANSACTIONS_COLLECTION).find(query).toArray();
}
47 changes: 45 additions & 2 deletions nightfall-client/src/services/process-calldata.mjs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import { unpackBlockInfo } from '@polygon-nightfall/common-files/utils/block-uti

const { SIGNATURES } = config;

async function getProposeBlockCalldata(eventData) {
export async function getProposeBlockCalldata(eventData) {
const web3 = Web3.connection();
const { transactionHash } = eventData;
const tx = await web3.eth.getTransaction(transactionHash);
@@ -76,4 +76,47 @@ async function getProposeBlockCalldata(eventData) {
return { transactions, block };
}

export default getProposeBlockCalldata;
export async function getTransactionSubmittedCalldata(eventData) {
const web3 = Web3.connection();
const { transactionHash } = eventData;
const tx = await web3.eth.getTransaction(transactionHash);
// Remove the '0x' and function signature to recove rhte abi bytecode
const abiBytecode = `0x${tx.input.slice(10)}`;
const transactionData = web3.eth.abi.decodeParameter(SIGNATURES.SUBMIT_TRANSACTION, abiBytecode);
const [
packedTransactionInfo,
historicRootBlockNumberL2Packed,
tokenId,
ercAddress,
recipientAddress,
commitments,
nullifiers,
compressedSecrets,
proof,
] = transactionData;

const { value, fee, circuitHash, tokenType } =
Transaction.unpackTransactionInfo(packedTransactionInfo);

const historicRootBlockNumberL2 = Transaction.unpackHistoricRoot(
nullifiers.length,
historicRootBlockNumberL2Packed,
);

const transaction = {
value,
fee,
circuitHash,
tokenType,
historicRootBlockNumberL2,
tokenId,
ercAddress,
recipientAddress,
commitments,
nullifiers,
compressedSecrets,
proof,
};
transaction.transactionHash = Transaction.calcHash(transaction);
return transaction;
}

0 comments on commit e2d769e

Please sign in to comment.