index.js
1 class TransactionTracker { 2 constructor(embark, _options) { 3 this.logger = embark.logger; 4 this.events = embark.events; 5 this.transactions = {}; 6 this.embark = embark; 7 this.startTimestamp = Date.now() / 1000; 8 9 embark.events.on("block:pending:transaction", this.onPendingTransaction.bind(this)); 10 embark.events.on("block:header", this.onBlockHeader.bind(this)); 11 this.registerAPICalls(); 12 } 13 14 onPendingTransaction(pendingTransactionHash) { 15 this.transactions[pendingTransactionHash] = { 16 startTimestamp: Date.now() / 1000 17 }; 18 } 19 20 onBlockHeader(blockHeader) { 21 this.events.request("blockchain:block:byNumber", blockHeader.hash, (err, block) => { 22 if (err) { 23 return this.logger.error('Error getting block header', err); 24 } 25 // Don't know why, but sometimes we receive nothing 26 if (!block || !block.transactions) { 27 return; 28 } 29 block.transactions.forEach(transaction => { 30 if (this.transactions[transaction.hash]) { 31 let wait = block.timestamp - this.transactions[transaction.hash].startTimestamp; 32 if (wait < 0.1) { 33 wait = 0.1; 34 } 35 Object.assign(this.transactions[transaction.hash], 36 {endTimestamp: block.timestamp, wait, gasPrice: transaction.gasPrice}); 37 } 38 }); 39 this.events.emit('blockchain:gas:oracle:new'); 40 this.cullOldTransactions(); 41 }); 42 } 43 44 cullOldTransactions() { 45 const timeLimit = (Date.now() / 1000) - 600; // Transactions old of 10 minutes are not to be counted anymore 46 if (this.startTimestamp > timeLimit) { 47 return; 48 } 49 Object.keys(this.transactions).forEach(transactionHash => { 50 if (this.transactions[transactionHash].startTimestamp < timeLimit) { 51 delete this.transactions[transactionHash]; 52 } 53 }); 54 } 55 56 calculateGasPriceSpeeds() { 57 return Object.keys(this.transactions).reduce((acc, transactionHash) => { 58 const transaction = this.transactions[transactionHash]; 59 if (!transaction.gasPrice) { 60 return acc; 61 } 62 if (!acc[transaction.gasPrice]) { 63 acc[transaction.gasPrice] = { 64 nbTxs: 0, 65 totalWait: 0 66 }; 67 } 68 acc[transaction.gasPrice].nbTxs++; 69 acc[transaction.gasPrice].totalWait += transaction.wait; 70 acc[transaction.gasPrice].averageWait = acc[transaction.gasPrice].totalWait / acc[transaction.gasPrice].nbTxs; 71 72 return acc; 73 }, {}); 74 } 75 76 registerAPICalls() { 77 const self = this; 78 self.embark.registerAPICall( 79 'get', 80 '/embark-api/blockchain/gas/oracle', 81 (req, res) => { 82 res.send(self.calculateGasPriceSpeeds()); 83 } 84 ); 85 self.embark.registerAPICall( 86 'ws', 87 '/embark-api/blockchain/gas/oracle', 88 (ws) => { 89 self.events.on('blockchain:gas:oracle:new', () => { 90 ws.send(JSON.stringify(self.calculateGasPriceSpeeds()), () => {}); 91 }); 92 } 93 ); 94 } 95 } 96 97 module.exports = TransactionTracker;