Skip to content

Commit

Permalink
Merge pull request #6 from phahulin/eventsStats-endpoint
Browse files Browse the repository at this point in the history
Some optimizations
  • Loading branch information
rstormsf authored Jun 21, 2018
2 parents fc196ff + 8c2a4a0 commit 1ed35da
Show file tree
Hide file tree
Showing 16 changed files with 244 additions and 115 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ FOREIGN_RPC_URL=https://kovan.infura.io/mew
HOME_BRIDGE_ADDRESS=0xABb4C1399DcC28FBa3Beb76CAE2b50Be3e087353
FOREIGN_BRIDGE_ADDRESS=0xE405F6872cE38a7a4Ff63DcF946236D458c2ca3a
POA20_ADDRESS=0x6F794fb14d01f7551C1fe5614FDDf5895A2e82d3
HOME_DEPLOYMENT_BLOCK=0
FOREIGN_DEPLOYMENT_BLOCK=0
GAS_PRICE_SPEED_TYPE=standard
GAS_LIMIT=300000
GAS_PRICE_FALLBACK=21
LEFT_TX_THRESHOLD=100
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.env
node_modules
responses
responses/*
!responses/.gitkeep
*.err
*.out
130 changes: 86 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,59 +7,91 @@ Home and Foreign Eth networks to check for balance difference.
On Home network it checks for `HOME_BRIDGE_ADDRESS` balance
On Foreign network it checks for `POA20_ADDRESS` total supply.

Example of an API `/`:
Example of an API

* `GET /` - check contract balances & tx numbers

```json

{
"home": {
"balance": "145.589637026290448384",
"deposits": 7641,
"withdrawals": 128
},
"foreign": {
"totalSupply": "164.0563811",
"deposits": 7642,
"withdrawals": 125
},
"balanceDiff": -18.466744073709553,
"lastChecked": 1524872762,
"depositsDiff": -1,
"withdrawalDiff": 3,
"timeDiff": 20
"home": {
"balance": "3710077.6896438415780044",
"deposits": 481,
"withdrawals": 221,
"requiredSignatures": 2
},
"foreign": {
"totalSupply": "3710077.6896438415780044",
"deposits": 481,
"withdrawals": 221,
"requiredSignatures": 2
},
"balanceDiff": 0,
"lastChecked": 1529511982,
"depositsDiff": 0,
"withdrawalDiff": 0,
"requiredSignaturesMatch": true
}
```
/validators

* `GET /validators` - check validators balances
```json
{
"home": {
"validators": {
"0xb8988B690910913c97A090c3a6f80FAD8b3A4683": {
"balance": "123.835674629",
"leftTx": 412785582096666,
"gasPrice": 1
}
}
},
"foreign": {
"validators": {
"0xb8988B690910913c97A090c3a6f80FAD8b3A4683": {
"balance": "10.523898627992509332",
"leftTx": 17539,
"gasPrice": 2
}
}
},
"lastChecked": 1524872829,
"timeDiff": 17,
"homeOk": true,
"foreignOk": true,
"ok": true
"home": {
"validators": {
"0x35DC13c72A9C09C8AEEBD0490C7228C43Ccc38Cd": {
"balance": "19.994900374",
"leftTx": 66649667913333,
"gasPrice": 1
},
"0x5D44BC8642947685F45004c936245B969F9709a6": {
"balance": "19.993736069",
"leftTx": 66645786896666,
"gasPrice": 1
},
"0x284877074B986A78F01D7Eb1f34B6043b1719002": {
"balance": "19.995139875",
"leftTx": 66650466250000,
"gasPrice": 1
}
}
},
"foreign": {
"validators": {
"0x35DC13c72A9C09C8AEEBD0490C7228C43Ccc38Cd": {
"balance": "19.084023268196",
"leftTx": 28915,
"gasPrice": 2.2
},
"0x5D44BC8642947685F45004c936245B969F9709a6": {
"balance": "19.086724777075",
"leftTx": 28919,
"gasPrice": 2.2
},
"0x284877074B986A78F01D7Eb1f34B6043b1719002": {
"balance": "19.050074813935",
"leftTx": 28863,
"gasPrice": 2.2
}
}
},
"lastChecked": 1529512164
}
```

* `GET /eventsStats` - check unprocessed events
```json
{
"onlyInHomeDeposits": [],
"onlyInForeignDeposits": [],
"onlyInHomeWithdrawals": [],
"onlyInForeignWithdrawals": [],
"lastChecked": 1529512436
}
```

# How to run
Create .env file
Create .env file (see `.env.example` for parameters reference)
```bash
HOME_RPC_URL=https://sokol.poa.network
FOREIGN_RPC_URL=https://kovan.infura.io/mew
Expand All @@ -68,17 +100,27 @@ FOREIGN_BRIDGE_ADDRESS=0xE405F6872cE38a7a4Ff63DcF946236D458c2ca3a
POA20_ADDRESS=0x6F794fb14d01f7551C1fe5614FDDf5895A2e82d3
GAS_PRICE_SPEED_TYPE=standard
GAS_LIMIT=300000
GAS_PRICE_FALLBACK=21
LEFT_TX_THRESHOLD=100
```

```bash
npm i
# check balances of contracts and validators
node checkWorker.js
# check unprocessed events
node checkWorker2.js
# run web interface
node index.js
```

You can create cron job to run worker:
To enabled debug logging, set `DEBUG=1` env variable.

You can create cron job to run workers (see `crontab.example` for reference):
```bash
crontab -e
* * * * * cd /bridge-monitor; node /bridge-monitor/checkWorker.js
#crontab -e
*/4 * * * * cd $HOME/bridge-monitor; node checkWorker.js >>cronWorker.out 2>>cronWorker.err
*/5 * * * * cd $HOME/bridge-monitor; node checkWorker2.js >>cronWorker2.out 2>>cronWorker2.err
```

You can run web interface via [pm2](https://www.npmjs.com/package/pm2) or similar supervisor program.
12 changes: 10 additions & 2 deletions checkWorker.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
const fs = require('fs')
const logger = require('./logger')('checkWorker');
const getBalances = require('./getBalances')
const getShortEventStats = require('./getShortEventStats');
const validators = require('./validators');

async function checkWorker() {
try {
logger.debug('calling getBalances()');
const balances = await getBalances();
logger.debug('calling getShortEventStats()');
const events = await getShortEventStats();
const home = Object.assign({}, balances.home, events.home)
const foreign = Object.assign({}, balances.foreign, events.foreign)
const status = Object.assign({}, balances, events, {home}, {foreign})
if (!status) throw new Error('status is empty: ' + JSON.stringify(status));
fs.writeFileSync(__dirname + '/responses/getBalances.json', JSON.stringify(status,null,4));

logger.debug('calling validators()');
const vBalances = await validators();
if (!vBalances) throw new Error('vBalances is empty: ' + JSON.stringify(vBalances));
fs.writeFileSync(__dirname + '/responses/validators.json', JSON.stringify(vBalances,null,4));
logger.debug("Done");
return status;
} catch(e) {
console.error(e)
logger.error(e);
throw e;
}
}
checkWorker();
module.exports = checkWorker;
18 changes: 18 additions & 0 deletions checkWorker2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const fs = require('fs')
const logger = require('./logger')('checkWorker2');
const eventsStats = require('./eventsStats')

async function checkWorker2() {
try {
logger.debug('calling eventsStats()');
const evStats = await eventsStats();
if (!evStats) throw new Error('evStats is empty: ' + JSON.stringify(evStats));
fs.writeFileSync(__dirname + '/responses/eventsStats.json', JSON.stringify(evStats,null,4));
logger.debug("Done");
return evStats;
} catch(e) {
logger.error('checkWorker2.js', e);
throw e;
}
}
checkWorker2();
2 changes: 2 additions & 0 deletions crontab.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*/4 * * * * cd $HOME/bridge-monitor; node checkWorker.js >>cronWorker.out 2>>cronWorker.err
*/5 * * * * cd $HOME/bridge-monitor; node checkWorker2.js >>cronWorker2.out 2>>cronWorker2.err
27 changes: 17 additions & 10 deletions eventsStats.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
require('dotenv').config();
const logger = require('./logger')('eventsStats');
const Web3 = require('web3');
const HOME_RPC_URL = process.env.HOME_RPC_URL;
const FOREIGN_RPC_URL = process.env.FOREIGN_RPC_URL;
const HOME_BRIDGE_ADDRESS = process.env.HOME_BRIDGE_ADDRESS;
const FOREIGN_BRIDGE_ADDRESS = process.env.FOREIGN_BRIDGE_ADDRESS;
const HOME_DEPLOYMENT_BLOCK = Number(process.env.HOME_DEPLOYMENT_BLOCK) || 0;
const FOREIGN_DEPLOYMENT_BLOCK = Number(process.env.FOREIGN_DEPLOYMENT_BLOCK) || 0;

const homeProvider = new Web3.providers.HttpProvider(HOME_RPC_URL);
const web3Home = new Web3(homeProvider);
Expand Down Expand Up @@ -35,32 +38,36 @@ function compareDepositsForeign(home){

async function main(){
try {

const FROM_BLOCK = 0;

const homeBridge = new web3Home.eth.Contract(HOME_ABI, HOME_BRIDGE_ADDRESS);
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ABI, FOREIGN_BRIDGE_ADDRESS);
let homeDeposits = await homeBridge.getPastEvents('Deposit', {fromBlock: FROM_BLOCK});
let foreignDeposits = await foreignBridge.getPastEvents('Deposit', {fromBlock: FROM_BLOCK});
let homeWithdrawals = await homeBridge.getPastEvents('Withdraw', {fromBlock: FROM_BLOCK});
let foreignWithdrawals = await foreignBridge.getPastEvents('Withdraw', {fromBlock: FROM_BLOCK});
logger.debug("calling homeBridge.getPastEvents('Deposit')");
let homeDeposits = await homeBridge.getPastEvents('Deposit', {fromBlock: HOME_DEPLOYMENT_BLOCK});
logger.debug("calling foreignBridge.getPastEvents('Deposit')");
let foreignDeposits = await foreignBridge.getPastEvents('Deposit', {fromBlock: FOREIGN_DEPLOYMENT_BLOCK});
logger.debug("calling homeBridge.getPastEvents('Withdraw')");
let homeWithdrawals = await homeBridge.getPastEvents('Withdraw', {fromBlock: HOME_DEPLOYMENT_BLOCK});
logger.debug("calling foreignBridge.getPastEvents('Withdraw')");
let foreignWithdrawals = await foreignBridge.getPastEvents('Withdraw', {fromBlock: FOREIGN_DEPLOYMENT_BLOCK});

const onlyInHomeDeposits = homeDeposits.filter(compareDepositsHome(foreignDeposits))
const onlyInForeignDeposits = foreignDeposits.concat([]).filter(compareDepositsForeign(homeDeposits))

const onlyInHomeWithdrawals = homeWithdrawals.filter(compareDepositsForeign(foreignWithdrawals))
const onlyInForeignWithdrawals = foreignWithdrawals.filter(compareDepositsHome(homeWithdrawals))

logger.debug("Done");
return {
onlyInHomeDeposits,
onlyInForeignDeposits,
onlyInHomeWithdrawals,
onlyInForeignWithdrawals
onlyInForeignWithdrawals,
lastChecked: Math.floor(Date.now() / 1000),
}
} catch(e) {
console.error(e);
logger.error(e);
throw e;
}

}
main()

module.exports = main;
7 changes: 6 additions & 1 deletion getBalances.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require('dotenv').config();
const logger = require('./logger')('getBalances');
const fs = require('fs')
const Web3 = require('web3');
const Web3Utils = require('web3-utils')
Expand All @@ -20,12 +21,15 @@ const ERC677_ABI = require('./abis/ERC677.abi');

async function main(){
try {
logger.debug('calling web3Home.eth.getBalance');
const homeBalance = await web3Home.eth.getBalance(HOME_BRIDGE_ADDRESS)
const tokenContract = new web3Foreign.eth.Contract(ERC677_ABI, POA20_ADDRESS);
logger.debug('calling tokenContract.methods.totalSupply()');
const totalSupply = await tokenContract.methods.totalSupply().call()
const homeBalanceBN = new BN(homeBalance)
const foreignTotalSupplyBN = new BN(totalSupply)
const diff = homeBalanceBN.minus(foreignTotalSupplyBN).toString(10)
logger.debug("Done");
return {
home: {
balance: Web3Utils.fromWei(homeBalance)
Expand All @@ -37,7 +41,8 @@ async function main(){
lastChecked: Math.floor(Date.now() / 1000)
}
} catch(e) {
console.error(e);
logger.error(e);
throw e;
}

}
Expand Down
29 changes: 20 additions & 9 deletions getShortEventStats.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require('dotenv').config();
const logger = require('./logger')('getShortEventStats.js');
const fs = require('fs')
const Web3 = require('web3');
const Web3Utils = require('web3-utils')
Expand All @@ -7,6 +8,8 @@ const FOREIGN_RPC_URL = process.env.FOREIGN_RPC_URL;
const HOME_BRIDGE_ADDRESS = process.env.HOME_BRIDGE_ADDRESS;
const FOREIGN_BRIDGE_ADDRESS = process.env.FOREIGN_BRIDGE_ADDRESS;
const POA20_ADDRESS = process.env.POA20_ADDRESS;
const HOME_DEPLOYMENT_BLOCK = Number(process.env.HOME_DEPLOYMENT_BLOCK) || 0;
const FOREIGN_DEPLOYMENT_BLOCK = Number(process.env.FOREIGN_DEPLOYMENT_BLOCK) || 0;

const homeProvider = new Web3.providers.HttpProvider(HOME_RPC_URL);
const web3Home = new Web3(homeProvider);
Expand All @@ -21,20 +24,27 @@ const BRIDGE_VALIDATORS_ABI = require('./abis/BridgeValidators.abi');

async function main(){
try {

const homeBridge = new web3Home.eth.Contract(HOME_ABI, HOME_BRIDGE_ADDRESS);
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ABI, FOREIGN_BRIDGE_ADDRESS);
logger.debug("calling homeBridge.methods.validatorContract().call()");
const validatorHomeAddress = await homeBridge.methods.validatorContract().call()
logger.debug("calling foreignBridge.methods.validatorContract().call()");
const validatorForeignAddress = await foreignBridge.methods.validatorContract().call()
const homeValidators = new web3Home.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorHomeAddress);
const foreignValidators = new web3Foreign.eth.Contract(BRIDGE_VALIDATORS_ABI, FOREIGN_BRIDGE_ADDRESS);
const foreignValidators = new web3Foreign.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorForeignAddress);
logger.debug("calling homeValidators.methods.requiredSignatures().call()");
const reqSigHome = await homeValidators.methods.requiredSignatures().call()
const reqSigForeign = await homeValidators.methods.requiredSignatures().call()
let homeDeposits = await homeBridge.getPastEvents('Deposit', {fromBlock: 0});
let foreignDeposits = await foreignBridge.getPastEvents('Deposit', {fromBlock: 0});
let homeWithdrawals = await homeBridge.getPastEvents('Withdraw', {fromBlock: 0});
let foreignWithdrawals = await foreignBridge.getPastEvents('Withdraw', {fromBlock: 0});

logger.debug("calling foreignValidators.methods.requiredSignatures().call()");
const reqSigForeign = await foreignValidators.methods.requiredSignatures().call()
logger.debug("calling homeBridge.getPastEvents('Deposit')");
let homeDeposits = await homeBridge.getPastEvents('Deposit', {fromBlock: HOME_DEPLOYMENT_BLOCK});
logger.debug("calling foreignBridge.getPastEvents('Deposit')");
let foreignDeposits = await foreignBridge.getPastEvents('Deposit', {fromBlock: FOREIGN_DEPLOYMENT_BLOCK});
logger.debug("calling homeBridge.getPastEvents('Withdraw')");
let homeWithdrawals = await homeBridge.getPastEvents('Withdraw', {fromBlock: HOME_DEPLOYMENT_BLOCK});
logger.debug("calling foreignBridge.getPastEvents('Withdraw')");
let foreignWithdrawals = await foreignBridge.getPastEvents('Withdraw', {fromBlock: FOREIGN_DEPLOYMENT_BLOCK});
logger.debug("Done");
return {
depositsDiff: homeDeposits.length - foreignDeposits.length,
withdrawalDiff: homeWithdrawals.length - foreignWithdrawals.length,
Expand All @@ -51,7 +61,8 @@ async function main(){
requiredSignaturesMatch: reqSigHome === reqSigForeign
}
} catch(e) {
console.error(e);
logger.error(e);
throw e;
}

}
Expand Down
Loading

0 comments on commit 1ed35da

Please sign in to comment.