Skip to content

Commit

Permalink
Merge pull request #27 from rsksmart/add-live-monitor-tool
Browse files Browse the repository at this point in the history
Adds live monitoring tool
  • Loading branch information
marcos-iov committed Mar 2, 2023
2 parents ce8bac2 + 3ec320d commit 13f77b6
Show file tree
Hide file tree
Showing 2 changed files with 270 additions and 0 deletions.
108 changes: 108 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,111 @@ This is a beta version until audited by the security team. Any comments or sugge
- `blocks to search`: amount of blocks to search, from the starting block forward. Max 100 blocks.
- bridgeTx: A bridgeTx: web3TransactionObject. E.g.: {\"hash\":\"0xc2dee2f542cee022196948b1da5d8d44331e3f8de964ee6fb025e06bb077c880\",\"nonce\":241,\"blockHash\":\"0x3cd357a760e69e3942d344062f751eff7be4d07d4a01f095ebfd42c8c0d2498e\",\"blockNumber\":2867321,\"transactionIndex\":3,\"from\":\"0x92C94AE16eEfC9202bb8BCAf1F6B0c8702fb56eE\",\"to\":\"0x0000000000000000000000000000000001000006\",\"gas\":67152,\"gasPrice\":\"65164000\",\"value\":\"0\",\"input\":\"0x43dc06560000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000022280e00000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000131010000000001014e80d52d5ed9dfe3523c47e7cb095b9cffe6677f22090fd9e0bbf32813c18be00200000017160014c4cb069eec8a8b695a8c50515eaec10b4e65bb5bffffffff030000000000000000306a2e52534b54013a29282d5144cea68cb33995ce82212f4b21ccec012b6f4aecd3bad677f9056c20958b1c1ff56d25c3405489000000000017a9148f38b3d8ec8816f7f58a390f306bb90bb178d6ac87ee3a07000000000017a914f38b645178d325b086b1849bb79147518b8931698702483045022100be99ce8ce2de3147ba64e81ec5fe4bc0dea12dccf258cd4dca65c0c09108da8f022024b5c36e2184a4d2a67b5212b52e6955e4e7a9fbff896825bef7e028d34ef4c70121028d2a1b7ef1feffdfd1aa57d543bf0799107ec44469f9e3d332ffe25fec2b8e590000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470200000002000000000000000000000000000000000000000000000000000000000000000076113d8b6fc306e168ac534d80874e3ee1b9f418b8c1985ead59399d638b1ea3010500000000000000000000000000000000000000000000000000\",\"v\":\"0x62\",\"r\":\"0x802a61cfaa81791b8e5a5101887932f4e9cd0f64d3bb0d7d61ae77d190f289a2\",\"s\":\"0x5e1f5b3d2ae30474665e2485f472c81979f6b6db8c9dc2c92408b4f96d7d2baf\"}
- bridgeTxReceipt: A bridgeTxReceipt: web3TransactionObject. E.g.: {\"transactionHash\":\"0xc2dee2f542cee022196948b1da5d8d44331e3f8de964ee6fb025e06bb077c880\",\"transactionIndex\":3,\"blockHash\":\"0x3cd357a760e69e3942d344062f751eff7be4d07d4a01f095ebfd42c8c0d2498e\",\"blockNumber\":2867321,\"cumulativeGasUsed\":507369,\"gasUsed\":67152,\"contractAddress\":null,\"logs\":[],\"from\":\"0x92c94ae16eefc9202bb8bcaf1f6b0c8702fb56ee\",\"to\":\"0x0000000000000000000000000000000001000006\",\"status\":true,\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}

## Live monitoring tool

The live monitoring tool enables real-time monitoring of a given set of Bridge related events and methods.

This tool can be helpful to track peg-ins, peg-outs or any other specific bridge action in real time.

It can be executed against a node running in any network (regtest, testnet or mainnet).

To print in the console all the transactions sent to the bridge with their method and events data, the following command can be used:

> node tool/live-monitor.js
The tool will start checking block by block (starting from the latest one), transaction by transaction, filtering the transaction sent to the bridge and printing a payload like this:

```js
...

{
txHash: '0xda3db1d8b949e99a4f0fb27dc867981e79b457339b8df94a5bd27654a79bf6da',
blockHash: '0x69304c7b6d072c157245d9f93f09661fe86d30f6befc28ba7c188ca33685d6cf',
blockNumber: 3574944,
from: '0x62dB6C4b118d7259c23692B162829E6bd5e4d5B0',
to: '0x0000000000000000000000000000000001000006',
method: '',
events: [
BridgeEvent {
name: 'release_request_received',
signature: '0x8e04e2f2c246a91202761c435d6a4971bdc7af0617f0c739d900ecd12a6d7266',
arguments: {
sender: '0x62dB6C4b118d7259c23692B162829E6bd5e4d5B0',
btcDestinationAddress: '0xcab5925c59a9a413f8d443000abcc5640bdf0675',
amount: '5130000'
}
}
]
}

{
txHash: '0x77b15a4b54029cc9edec8096606a7b7eae1ad749c3a98ed4e0e393028e568d2f',
blockHash: '0x2c819a09d8e00fed67ea216c563d14e2b8286f4c0a2480b764f6dd86b3662396',
blockNumber: 3574946,
from: '0xD478f3CE39cc5957b890C09EFE709AC7d4c282F8',
to: '0x0000000000000000000000000000000001000006',
method: BridgeMethod {
name: 'receiveHeaders',
signature: '0xe5400e7b',
arguments: {
blocks: [
'0x0000a0200f0a949fe1d050024b2077c7528792edb620f89cb5db089f29000000000000005e54b6818e31f89e69f1ddd523b7a58d2d45259b77a110fd875b8328de2b5d1e0750e6639cde2c1983e2d76a'
]
}
},
events: []
}

...
```

It will continue to print as it finds new Bridge methods or events in the upcoming blocks.

Available param options:

* [--fromblock=number] defaults to `lastest`
* [--network=network] defaults to `testnet`
* [--pegin] if provided, prints peg-in related transactions. It can be used along `--pegout` to only print peg-in and peg-out related transactions
* [--pegout] if provided, prints peg-out related transactions It can be used along `--pegin` to only print peg-in and peg-out related transactions
* [--methods="['bridgeMethod1', 'bridgeMethod2']"] prints transaction data of calls made to any of the specified bridge methods. Defaults to all Bridge methods
* [--events="['bridgeEvent1', 'bridgeEvent2']"] prints transaction data of those that emitted any of these events. Defaults to all Bridge events
* [--checkeverymillis=timeInMilliseconds] time between executions to get the next block to filter and print the transactions data. Defaults to 1000 milliseconds

### Samples

Note: All the options are optional and can be provided in any order

Print all Bridge methods and events related transaction data starting at block `3,573,827` in `testnet`:

> node tool/live-monitor.js --fromblock=3574944
Print all the peg-out related transaction data from block `3,574,944 ` in a local node at `http://127.0.0.1:30007`:

> node tool/live-monitor.js --fromblock=3574944 --pegout --network=http://127.0.0.1:30007
Print all the transaction data that only has the `addSignature` method starting at the latest block in `testnet`:

> node tool/live-monitor.js --methods="['addSignature']"
Print all the transaction data only related to peg-ins and peg-outs in testnet:

> node tool/live-monitor.js --pegin --pegout
Only print peg-in related transaction data in testnet from block `3,575,114`:

> node tool/live-monitor.js --fromblock=3575114 --pegin
Only print peg-out related transaction data in testnet:

> node tool/live-monitor.js --pegout
Only print the transaction data that contains the `updateCollections` method and the `release_requested` event starting at block `3,574,944 ` in `testnet`:

> node tool/live-monitor.js --fromblock=3574944 --methods="['updateCollections']" --events="['release_requested']"
Only print the transaction data that contains the `updateCollections` method and the `release_requested` event starting at block `500` at host `http://127.0.0.1:30007` retrieving new blocks every minute:

> node tool/live-monitor.js --fromblock=500 --methods="['updateCollections']" --events="['release_requested']" --network=http://127.0.0.1:30007 --checkeverymillis=60000
If an unknown option parameter is passed, the tool will throw an exception.
162 changes: 162 additions & 0 deletions tool/live-monitor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
const Web3 = require('web3');
const { getBridgeTransactionByTxHash } = require('../index');
const networkParser = require('./network-parser');
const Bridge = require('@rsksmart/rsk-precompiled-abis').bridge;
const util = require('util');

const DEFAULT_CHECK_EVERY_MILLIS = 1_000;

const defaultParamsValues = {
fromBlock: 'latest',
methods: [],
events: [],
pegout: false,
pegin: false,
network: 'testnet',
checkEveryMillis: DEFAULT_CHECK_EVERY_MILLIS,
};

const getParsedParams = () => {
const params = process.argv.filter(param => param.startsWith('--'))
.reduce((params, param) => {
if(param.startsWith('--fromblock')) {
params.fromBlock = param.slice(param.indexOf('=') + 1);
} else if(param.startsWith('--methods') || param.startsWith('--events')) { // Parsing params that include an array
const paramName = param.slice(2, param.indexOf('='));
params[paramName] = JSON.parse(param.slice(param.indexOf('=') + 1).replaceAll("'", '"'));
} else if(param.startsWith('--network')) {
params.network = param.slice(param.indexOf('=') + 1);
} else if(param.startsWith('--pegout') || param.startsWith('--pegin')) {
const paramName = param.replace('--', '');
params[paramName] = true;
} else if(param.startsWith('--checkeverymillis')) {
params.checkEveryMillis = Number(param.slice(param.indexOf('=') + 1));
} else {
throw new Error(`Parameter '${param}' not recognized`);
}
return params;
}, defaultParamsValues);
return params;
};

const PEGOUT_METHOD_SIGNATURES = {
releaseBtc: '0x',
updateCollections: '0x0c5a9990',
addSignature: '0xf10b9c59'
};

const PEGIN_METHOD_SIGNATURES = {
registerBtcCoinbaseTransaction: '0xccf417ae',
registerBtcTransaction: '0x43dc0656',
registerFastBridgeBtcTransaction: '0x6adc0133'
};

function isAPegoutRelatedTransactionData(data) {
const methodSignature = data.slice(0, 10);
return Object.values(PEGOUT_METHOD_SIGNATURES)
.includes(methodSignature);
}

function isAPeginRelatedTransactionData(data) {
const methodSignature = data.slice(0, 10);
return Object.values(PEGIN_METHOD_SIGNATURES)
.includes(methodSignature);
}

const params = getParsedParams();

const web3Client = new Web3(networkParser(params.network));

let currentBlockNumber = params.fromBlock;

let notified = false;

async function monitor() {

try {

const latestBlockNumber = await web3Client.eth.getBlockNumber();

if(currentBlockNumber === 'latest') {
currentBlockNumber = latestBlockNumber;
}

if(latestBlockNumber < currentBlockNumber) {
if(!notified) {
console.warn("latestBlockNumber was reached!");
notified = true;
}
return;
}

notified = false;

const block = await web3Client.eth.getBlock(currentBlockNumber, true);

console.info("Checking block: ", block.number);

currentBlockNumber++;

for(const transaction of block.transactions) {

if(transaction.to === Bridge.address) {

const isPeginRelated = isAPeginRelatedTransactionData(transaction.input);
const isPegoutRelated = isAPegoutRelatedTransactionData(transaction.input);

// Requested only pegouts, if tx is not a pegout then continue
if(!params.pegin && (params.pegout && !isPegoutRelated)) {
continue;
// Requested only pegins, if tx is not a pegin then return
} else if(!params.pegout && (params.pegin && !isPeginRelated)) {
continue;
// Requested only pegins and pegouts, if tx is not a pegin or pegout then return
} else if((params.pegin && params.pegout) && (!isPeginRelated && !isPegoutRelated)) {
continue;
}

// Showing all bridge events by default if params.pegin and params.pegout where not specified

const rskTx = await getBridgeTransactionByTxHash(web3Client, transaction.hash);

if(params.methods.length > 0 && !params.methods.includes(rskTx.method.name)) {
continue;
}

const containsAtLeast1RequestedEvent = rskTx.events.some(event => params.events.includes(event.name));
if(params.events.length > 0 && containsAtLeast1RequestedEvent) {
continue;
}

const bridgeTxDetails = {
txHash: transaction.hash,
blockHash: transaction.blockHash,
blockNumber: transaction.blockNumber,
from: transaction.from,
to: transaction.to,
method: rskTx.method,
events: rskTx.events
};

console.info("Found a tx:");

console.info(util.inspect(bridgeTxDetails, {depth: null, colors: true}));

}

}

} catch(e) {
console.error(`There was an error trying to get the tx data/events in block: ${currentBlockNumber - 1}`, e);
console.info("Moving forward...");
}

}

const checkEveryMillis = params.checkEveryMillis || DEFAULT_CHECK_EVERY_MILLIS;

console.log(`Checking a block every ${checkEveryMillis} milliseconds`);

setInterval(async () => {
await monitor();
}, checkEveryMillis);

0 comments on commit 13f77b6

Please sign in to comment.