Skip to content
This repository has been archived by the owner on Dec 16, 2021. It is now read-only.

fix: waitForTransactionToBeProvable not waiting for blocks #338

Merged
merged 27 commits into from
Feb 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2bcc1c9
fix: blockchainListener.waitForBlocks not waiting for blocks properly
antouhou Feb 8, 2021
7cb82d2
fix handler instantiation
antouhou Feb 8, 2021
314232f
fix: tests
Feb 9, 2021
6ceca4b
fix waiting for transaction to be provable
antouhou Feb 9, 2021
ea8abba
Merge remote-tracking branch 'origin/fix-block-wait' into fix-block-wait
antouhou Feb 9, 2021
d09d3be
fix tests
antouhou Feb 9, 2021
1a9e04a
simplified? promise a bit
antouhou Feb 9, 2021
fbb53fb
fix tests
antouhou Feb 9, 2021
af0a7a6
increased test coverage threshold
antouhou Feb 9, 2021
55001b2
kek
antouhou Feb 16, 2021
53f5dc2
remove promise handler factory, as there's no more generic handlers left
antouhou Feb 16, 2021
8408b38
fix race promise
antouhou Feb 16, 2021
3ce86cd
refactor: BlockchainListener
shumkov Feb 16, 2021
e22be10
Remove console.logs
antouhou Feb 16, 2021
8ff0aa8
refactor: wait for state transition result
shumkov Feb 16, 2021
4be94d1
Merge remote-tracking branch 'origin/fix-block-wait' into fix-block-wait
shumkov Feb 16, 2021
1a59f38
remove old tests
antouhou Feb 16, 2021
7bf04fe
remove unused variables
antouhou Feb 16, 2021
6113024
add new tests for BlockchainListener.js
antouhou Feb 16, 2021
73ee3db
add test for empty block
antouhou Feb 16, 2021
b22c897
test: implement tests
shumkov Feb 16, 2021
68d082b
Merge remote-tracking branch 'origin/fix-block-wait' into fix-block-wait
shumkov Feb 16, 2021
6110724
style: fix linter
shumkov Feb 16, 2021
f1b4078
useless commit
antouhou Feb 17, 2021
f6e0fdc
Merge remote-tracking branch 'origin/fix-block-wait' into fix-block-wait
antouhou Feb 17, 2021
d92b71a
revert useless commit
antouhou Feb 17, 2021
cd6dcdd
fix waitForStateTransitionResultHandlerFactory.js integration test
antouhou Feb 17, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions lib/externalApis/drive/fetchProofForStateTransitionFactory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @param {DriveClient} driveClient
* @return {fetchProofForStateTransition}
*/
function fetchProofForStateTransitionFactory(driveClient) {
/**
* @typedef {fetchProofForStateTransition}
* @param {AbstractStateTransition} stateTransition
* @return {Promise<Object>}
*/
async function fetchProofForStateTransition(stateTransition) {
const modifiedIds = stateTransition.getModifiedDataIds();

let proof;
if (stateTransition.isDocumentStateTransition()) {
({ documentsProof: proof } = await driveClient.fetchProofs(
{ documentIds: modifiedIds },
));
} else if (stateTransition.isIdentityStateTransition()) {
({ identitiesProof: proof } = await driveClient.fetchProofs(
{ identityIds: modifiedIds },
));
} else if (stateTransition.isDataContractStateTransition()) {
({ dataContractsProof: proof } = await driveClient.fetchProofs(
{ dataContractIds: modifiedIds },
));
}

return proof;
}

return fetchProofForStateTransition;
}

module.exports = fetchProofForStateTransitionFactory;
116 changes: 0 additions & 116 deletions lib/externalApis/tenderdash/BlockchainListener.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const crypto = require('crypto');

const EventEmitter = require('events');

const TX_QUERY = 'tm.event = \'Tx\'';
const NEW_BLOCK_QUERY = 'tm.event = \'NewBlock\'';
const EVENTS = {
NEW_BLOCK: 'block',
};

class BlockchainListener extends EventEmitter {
/**
* @param {WsClient} tenderdashWsClient
*/
constructor(tenderdashWsClient) {
super();
this.wsClient = tenderdashWsClient;
}

/**
* Returns an event name for a specific hash
*
* @param {string} transactionHashString
* @return {string}
*/
static getTransactionEventName(transactionHashString) {
return `transaction:${transactionHashString}`;
}

/**
*
* @param transactionHashString
* @return {string}
*/
static getTransactionAddedToTheBlockEventName(transactionHashString) {
return `blockTransactionAdded:${transactionHashString}`;
}

/**
* Subscribe to blocks and transaction results
*/
start() {
// Emit transaction results
this.wsClient.subscribe(TX_QUERY);
this.wsClient.on(TX_QUERY, (message) => {
const hashArray = message && message.events ? message.events['tx.hash'] : null;
const hashString = Array.isArray(hashArray) && hashArray[0];
if (!hashString) {
return;
}

this.emit(BlockchainListener.getTransactionEventName(hashString), message);
});

// Emit blocks and contained transactions
this.wsClient.subscribe(NEW_BLOCK_QUERY);
this.wsClient.on(NEW_BLOCK_QUERY, (message) => {
this.emit(EVENTS.NEW_BLOCK, message);

// Emit transaction hashes from block
message.data.value.block.data.txs.forEach((base64tx) => {
const transaction = Buffer.from(base64tx, 'base64');
const hashString = crypto.createHash('sha256')
.update(transaction)
.digest()
.toString('hex');

this.emit(
BlockchainListener.getTransactionAddedToTheBlockEventName(hashString),
transaction,
);
});
});
}
}

BlockchainListener.TX_QUERY = TX_QUERY;
BlockchainListener.NEW_BLOCK_QUERY = NEW_BLOCK_QUERY;
BlockchainListener.EVENTS = EVENTS;

module.exports = BlockchainListener;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class AbstractTransactionResult {
/**
* @param {Object} deliverResult
* @param {Buffer} transaction
*/
constructor(deliverResult, transaction) {
this.deliverResult = deliverResult;
this.transaction = transaction;
}

/**
* Get TX result
*
* @return {Object}
*/
getDeliverResult() {
return this.deliverResult;
}

/**
* Get transaction
*
* @return {Buffer}
*/
getTransaction() {
return this.transaction;
}
}

module.exports = AbstractTransactionResult;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const AbstractTransactionResult = require('./AbstractTransactionResult');

class TransactionErrorResult extends AbstractTransactionResult {

}

module.exports = TransactionErrorResult;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const AbstractTransactionResult = require('./AbstractTransactionResult');

class TransactionOkResult extends AbstractTransactionResult {

}

module.exports = TransactionOkResult;
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const BlockchainListener = require('../BlockchainListener');

/**
* @typedef {waitForTransactionCommitment}
* @param {BlockchainListener} blockchainListener
* @param {string} hashString
* @return {{
* promise: Promise<void>,
* detach: Function
* }}
*/
function waitForTransactionCommitment(blockchainListener, hashString) {
const txInBlockTopic = BlockchainListener
.getTransactionAddedToTheBlockEventName(hashString.toLowerCase());

let txInBlockHandler;
let newBlockHandler;

// Note that this will resolve only after two blocks. That is because the first block will
// flip the 'seenTransaction' toggle to true, and transaction will become provable
// only on the next block after the block it was included into
const promise = new Promise(((resolve) => {
let seenTransaction = false;

txInBlockHandler = () => {
seenTransaction = true;
};

newBlockHandler = () => {
if (!seenTransaction) {
return;
}

blockchainListener.off(BlockchainListener.EVENTS.NEW_BLOCK, newBlockHandler);

resolve();
};

blockchainListener.once(txInBlockTopic, txInBlockHandler);
blockchainListener.on(BlockchainListener.EVENTS.NEW_BLOCK, newBlockHandler);
}));

const detach = () => {
blockchainListener.off(txInBlockTopic, txInBlockHandler);
blockchainListener.off(BlockchainListener.EVENTS.NEW_BLOCK, newBlockHandler);
};

return {
promise,
detach,
};
}

module.exports = waitForTransactionCommitment;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const BlockchainListener = require('../BlockchainListener');
const TransactionErrorResult = require('./transactionResult/TransactionErrorResult');
const TransactionOkResult = require('./transactionResult/TransactionOkResult');

/**
* @typedef {waitForTransactionResult}
* @param {BlockchainListener} blockchainListener
* @param {string} hashString - Transaction hash string
* @return {{
* promise: Promise<TransactionOkResult|TransactionErrorResult>,
* detach: Function
* }}
*/
function waitForTransactionResult(blockchainListener, hashString) {
const topic = BlockchainListener.getTransactionEventName(hashString);

let handler;

const promise = new Promise((resolve, reject) => {
handler = ({ data: { value: { TxResult: txResult } } }) => {
blockchainListener.off(topic, handler);

const { result: deliverResult, tx } = txResult;

const txBuffer = Buffer.from(tx, 'base64');

if (deliverResult && deliverResult.code !== undefined && deliverResult.code !== 0) {
// If a transaction result is error we don't need to wait for next block
return reject(
new TransactionErrorResult(deliverResult, txBuffer),
);
}

return resolve(
new TransactionOkResult(deliverResult, txBuffer),
);
};

blockchainListener.on(topic, handler);
});

const detach = () => {
blockchainListener.off(topic, handler);
};

return {
promise,
detach,
};
}

module.exports = waitForTransactionResult;
Loading