Skip to content

Commit

Permalink
Update production (#75)
Browse files Browse the repository at this point in the history
* added node install to docker

* run npm install correct

* don't copy modules

* use env variables for testnet

* Update pr.yml

* github workflows changes

* Update pr.yml

* Update pr.yml

* Update pr.yml

* Update pr.yml

* Update pr.yml

* Update pr.yml

* Update pr.yml

* Update pr.yml

* Update pr.yml

* Make search case-insensitive (#36)

Modify variable names for clarity.

* Query balance by denomination (#48)

* colw/subscription-fix (#47)

* Fix transaction destructure

* Lint

* Rename for consistency

* Override method for V2

* Colw/fix denom and votes (#49)

* Use larger denom for governance parameters

* Lint

* Fix: Leave in big number format for line #86

* Fabo/minor fixes (#51)

* gracefully handle no rewards

* always return balance

* prevent error when no rewards

* fix wrong delegation amount showing

* log transaction if tag is empty (#58)

* fix tally for running proposals (#54)

* Fabo/move testnet definition into network configs file (#56)

* move testnet definition into network configs file

* use configs for endpoints

* update cache key per block (#57)

* colw/minor-fixes (#59)

* Export testnet data for use in LunieDB Source

* Fix get query

* Mario/32 add proposal proposer (#52)

* Add proposal proposer

* Add proposer to proposals page

* Revert package.js mod, use Promise.all

* Call all queries at same time in getProposalById

* Api error 500 fix

* Fabo suggestions

* Add cross-env

* Resolve merge conflict

* Fix merge error

* deliver correct testnet url (#60)

* Latest proposal should be on top (#61)

* Colin's magic

* const proposals

* fix to not crash if no denom

* Fabo/wait for stargate to be up (#62)

* debug missing denom

* do not call validators

* await for the remote instance to be up before loading static data

* remove logs

* remove fallback

* comment

* Update cosmosV0-source.js

* Update cosmosV0-source.js

* Update cosmosV0-source.js

* colw/subscription-refactor (#63)

* Factor out subscription object

* WIP

* Reenable subs

* Do not pre-populate cache (temp)

This is run on every request.

* Reenable static data

* Fix

* Remove comment

* WIP

* Use API class within subscription object

* Update file and parameter naming

* Load API classes once.

* Revert "Load API classes once."

ca567095360dbd7a8d81c7a53fe4fe885f3b63d2

* Set headers in separate method

* format comment

* Rename class variable

* Split static data up

* Adjust cache timing, default 5

* Update lib/schema.js

Co-Authored-By: Fabian <[email protected]>

* Change client name to TendermintClient

* Comment and rename for clarity

* Cache specific blocks longer

* Move Tendermint client to CosmosNodeSubscription

* Comments for clarity

* Clear memory after handling each new block (#66)

* Fix typo and no return. (#68)

* Aleksei/sentry added (#67)

* only sentry init code added

* docker-compose changes

* inspect removed

* colw/Decrease validator list loading time (#69)

* Fetch validators each new block and store them

* Store block, and sync validator map with block

* Add block to store

* Remove unused parameters

* Retrieve a single validator form the map

* Review fix: remove height parameter

* Review fix: Change variable name for clarity

* Return delegations and rewards from store (#70)

* Return delegations and rewards from store

* overview values

* Remove unnecessary Promise.all
  • Loading branch information
faboweb authored Nov 6, 2019
1 parent 55f1db3 commit 5a468dc
Show file tree
Hide file tree
Showing 25 changed files with 970 additions and 514 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/development.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ jobs:
- name: Installing Docker Compose
run: ssh [email protected] "sudo curl -L \"https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose; sudo chmod +x /usr/local/bin/docker-compose"
- name: Run on Digital Ocean
run: ssh [email protected] "docker image prune -a -f; docker load < lunieapi.tgz; docker container stop lunieapi;docker container stop caddy; docker container stop node_exporter; docker container prune -f; export HASURA_URL="https://staging-db.lunie.io/v1/graphql"; export HASURA_ADMIN_KEY="${{ secrets.LUNIE_STAGING_DB_KEY }}"; docker-compose -f docker-compose.yml up --build -d"
run: ssh [email protected] "docker image prune -a -f; docker load < lunieapi.tgz; docker container stop lunieapi;docker container stop caddy; docker container stop node_exporter; docker container prune -f; export HASURA_URL="https://staging-db.lunie.io/v1/graphql"; export HASURA_ADMIN_KEY="${{ secrets.LUNIE_STAGING_DB_KEY }}"; export SENTRY_DSN="${{ secrets.SENTRY_DSN }}"; docker-compose -f docker-compose.yml up --build -d"
- name: Setting up cron job for pm2 metrics export
run: ssh [email protected] "mkdir /logs -p; touch /logs/show; line='*/1 * * * * docker exec lunieapi pm2 show 0 > /logs/show; perl /root/pm2metrics.pl'; crontab -l | grep -q 'lunieapi pm2' && true || (crontab -l; echo "$line" ) | crontab -"
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ jobs:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: 'pr_alerts'
SLACK_USERNAME: 'luniebot'
SLACK_MESSAGE: 'New pull request to lunie-api'
SLACK_MESSAGE: ${{ github.event.pull_request.title }} | ${{ github.event.pull_request.body }} | ${{ github.event.pull_request._links.html.href }}
4 changes: 2 additions & 2 deletions .github/workflows/production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
- name: prepare to push to Digital Ocean
run: mkdir -p ~/.ssh && echo "${{ secrets.DO_PRIVATE_KEY }}" | tr -d '\r' > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa && eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_rsa && ssh-keyscan -H 167.71.107.214 >> ~/.ssh/known_hosts
- name: push to Digital Ocean
run: rsync -4 lunieapi.tgz [email protected]:~/ && rsync -4 pm2metrics.pl [email protected]:~/ && rsync -4 docker-compose.prod.yml [email protected]:~/ && rsync -4 Caddyfile.prod [email protected]:~/
run: rsync -4 lunieapi.tgz [email protected]:~/ && rsync -4 pm2metrics.pl [email protected]:~/ && rsync -4 docker-compose.prod.yml [email protected]:~/docker-compose.yml && rsync -4 Caddyfile.prod [email protected]:~/Caddyfile
- name: Installing Docker Compose
run: ssh [email protected] "sudo curl -L \"https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose; sudo chmod +x /usr/local/bin/docker-compose"
- name: Run on Digital Ocean
run: ssh [email protected] "docker image prune -a -f; docker load < lunieapi.tgz; docker container stop lunieapi;docker container stop caddy; docker container stop node_exporter; docker container prune -f;export HASURA_URL="https://production-db.lunie.io/v1/graphql"; export HASURA_ADMIN_KEY="${{ secrets.LUNIE_PRODUCTION_DB_KEY }}"; docker-compose -f docker-compose.yml up --build -d"
run: ssh [email protected] "docker image prune -a -f; docker load < lunieapi.tgz; docker container stop lunieapi;docker container stop caddy; docker container stop node_exporter; docker container prune -f;export HASURA_URL="https://production-db.lunie.io/v1/graphql"; export HASURA_ADMIN_KEY="${{ secrets.LUNIE_PRODUCTION_DB_KEY }}"; export SENTRY_DSN="${{ secrets.SENTRY_DSN }}"; docker-compose -f docker-compose.yml up --build -d"
- name: Setting up cron job for pm2 metrics export
run: ssh [email protected] "mkdir /logs -p; touch /logs/show; line='*/1 * * * * docker exec lunieapi pm2 show 0 > /logs/show; perl /root/pm2metrics.pl'; crontab -l | grep -q 'lunieapi pm2' && true || (crontab -l; echo "$line" ) | crontab -"
6 changes: 5 additions & 1 deletion Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ staging-api.lunie.io {
proxy / lunieapi:4000 {
websocket
}
}
}
:9100 {
basicauth / admin lunie1234
proxy / node_exporter:9100
}
4 changes: 4 additions & 0 deletions Caddyfile.prod
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ production-api.lunie.io {
websocket
}
}
:9100 {
basicauth / admin lunie1234
proxy / node_exporter:9100
}
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ FROM keymetrics/pm2:latest-alpine

WORKDIR /var/www/server

COPY ./node_modules ./node_modules

COPY ./lib ./lib

COPY ./data ./data
Expand All @@ -16,6 +14,8 @@ COPY pm2.json .

COPY index.js .

RUN npm install

CMD [ "pm2-runtime", "start", "pm2.json", "--format"]

EXPOSE 4200
5 changes: 4 additions & 1 deletion config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ module.exports = {
redis_url: process.env.REDIS_URL || '',
hasura_admin_key: process.env.HASURA_ADMIN_KEY || '',
hasura_url: process.env.HASURA_URL || 'http://localhost:8080/v1/graphql',
enableTestnet: process.env.TESTNET === 'true'
enableTestnet: process.env.TESTNET === 'true',
testnetRPC: process.env.TESTNET_RPC_URL || 'ws://localhost:26657/websocket',
testnetAPI: process.env.TESTNET_API_URL || 'http://localhost:9071',
SENTRY_DSN: process.env.SENTRY_DSN || '',
}
35 changes: 29 additions & 6 deletions data/network-configs.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
const config = require('../config')

const testnet = {
id: 'local-cosmos-hub-testnet',
title: 'Local Cosmos Testnet',
chain_id: 'testnet',
rpc_url: config.testnetRPC,
api_url: config.testnetAPI,
bech32_prefix: 'cosmos',
testnet: true,
feature_session: true,
feature_portfolio: true,
feature_validators: true,
feature_proposals: true,
feature_activity: true,
feature_explorer: true,
action_send: true,
action_claim_rewards: true,
action_delegate: true,
action_redelegate: true,
action_undelegate: true,
action_deposit: true,
action_vote: true,
action_proposal: true,
experimental: true,
stakingDenom: 'STAKE'
}

let networks = {
'cosmos-hub-testnet': {
id: 'cosmos-hub-testnet',
Expand All @@ -14,13 +40,10 @@ let networks = {
}

if (config.enableTestnet) {
networks['local-cosmos-hub-testnet'] = {
id: 'local-cosmos-hub-testnet',
api_url: 'http://localhost:9070',
rpc_url: 'ws://localhost:26657/websocket'
}
networks['local-cosmos-hub-testnet'] = testnet
}

module.exports = {
networks
networks,
testnet
}
9 changes: 4 additions & 5 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ services:
- /logs:/var/www/server/logs
networks:
- general
ports:
- "4000:4000"
deploy:
replicas: 1
environment:
- HASURA_URL=$HASURA_URL
- HASURA_ADMIN_KEY=$HASURA_ADMIN_KEY
- SENTRY_DSN=$SENTRY_DSN
- NODE_ENV=production
node-exporter:
image: prom/node-exporter
container_name: node_exporter
Expand All @@ -29,8 +29,6 @@ services:
- --collector.textfile.directory=/var/www
- --collector.filesystem.ignored-mount-points
- ^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)
ports:
- 9100:9100
restart: always
networks:
- general
Expand All @@ -49,8 +47,9 @@ services:
ports:
- "80:80"
- "443:443"
- "9100:9100"
volumes:
- ./Caddyfile.prod:/etc/Caddyfile
- ./Caddyfile:/etc/Caddyfile
- ./caddy_certs:/root/.caddy
volumes:
caddy_certs:
Expand Down
7 changes: 3 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ services:
- /logs:/var/www/server/logs
networks:
- general
ports:
- "4000:4000"
deploy:
replicas: 1
environment:
- HASURA_URL=$HASURA_URL
- HASURA_ADMIN_KEY=$HASURA_ADMIN_KEY
- SENTRY_DSN=$SENTRY_DSN
- NODE_ENV=staging
node-exporter:
image: prom/node-exporter
container_name: node_exporter
Expand All @@ -29,8 +29,6 @@ services:
- --collector.textfile.directory=/var/www
- --collector.filesystem.ignored-mount-points
- ^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)
ports:
- 9100:9100
restart: always
networks:
- general
Expand All @@ -49,6 +47,7 @@ services:
ports:
- "80:80"
- "443:443"
- "9100:9100"
volumes:
- ./Caddyfile:/etc/Caddyfile
- ./caddy_certs:/root/.caddy
Expand Down
59 changes: 45 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,72 @@
const { ApolloServer } = require('apollo-server')
const responseCachePlugin = require('apollo-server-plugin-response-cache')
const { mapValues } = require('lodash')
const typeDefs = require('./lib/schema')
const resolvers = require('./lib/resolvers')
const CosmosNodeSubscription = require('./lib/cosmos-node-subscription')
const CosmosV0API = require('./lib/cosmosV0-source')
const CosmosV2API = require('./lib/cosmosV2-source')
const LunieDBAPI = require('./lib/luniedb-source')
const BlockStore = require('./lib/block-store')

const { networks } = require('./data/network-configs')
const config = require('./config')

const cosmosHubMainnetAPI = new CosmosV0API(networks['cosmos-hub-mainnet'])
const cosmosHubTestnetAPI = new CosmosV2API(networks['cosmos-hub-testnet'])
const lunieDBAPI = new LunieDBAPI()

const dataSources = {
CosmosHubMainnetAPI: cosmosHubMainnetAPI,
CosmosHubTestnetAPI: cosmosHubTestnetAPI,
LunieDBAPI: lunieDBAPI
if(config.SENTRY_DSN){
const Sentry = require('@sentry/node');
Sentry.init({ dsn: config.SENTRY_DSN });
}

const store = mapValues(networks, network => new BlockStore(network.id))

new CosmosNodeSubscription(
networks['cosmos-hub-mainnet'],
CosmosV0API,
store['cosmos-hub-mainnet']
)
new CosmosNodeSubscription(
networks['cosmos-hub-testnet'],
CosmosV2API,
store['cosmos-hub-testnet']
)

if (config.enableTestnet) {
const localCosmosTestnetAPI = new CosmosV0API(
networks['local-cosmos-hub-testnet']
new CosmosNodeSubscription(
networks['local-cosmos-hub-testnet'],
CosmosV0API,
store['local-cosmos-hub-testnet']
)
dataSources.TestnetAPI = localCosmosTestnetAPI
}

function createDataSources() {
const dataSources = {
CosmosHubMainnetAPI: new CosmosV0API(networks['cosmos-hub-mainnet']),
CosmosHubTestnetAPI: new CosmosV2API(networks['cosmos-hub-testnet']),
LunieDBAPI: new LunieDBAPI(),
store: store
}
if (config.enableTestnet) {
dataSources.TestnetAPI = new CosmosV0API(
networks['local-cosmos-hub-testnet']
)
}
return dataSources
}

let options = {
typeDefs,
resolvers,
dataSources: () => dataSources,
dataSources: createDataSources,
cacheControl: {
defaultMaxAge: 5000
defaultMaxAge: 10
},
introspection: true,
playground: true,
engine: {
apiKey: config.apollo_engine_api_key,
schemaTag: 'production'
}
},
plugins: [responseCachePlugin()]
}

if (config.enable_cache) {
Expand Down
29 changes: 29 additions & 0 deletions lib/block-store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class BlockStore {
constructor(networkId) {
this.networkId = networkId
this.latestHeight = 0
this.block = {}
this.stakingDenom = ''
this.annualProvision = 0
this.signedBlocksWindow = 0
this.validators = {}
}

update({
height,
block = this.block,
stakingDenom = this.stakingDenom,
annualProvision = this.annualProvision,
signedBlocksWindow = this.signedBlocksWindow,
validators = this.validators
}) {
this.latestHeight = Number(height)
this.block = block
this.stakingDenom = stakingDenom
this.annualProvision = Number(annualProvision)
this.signedBlocksWindow = Number(signedBlocksWindow)
this.validators = validators
}
}

module.exports = BlockStore
58 changes: 58 additions & 0 deletions lib/cosmos-node-subscription.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const _ = require('lodash')
const Tendermint = require('./helpers/tendermint')
const {
publishBlockAdded,
publishUserTransactionAdded
} = require('./subscriptions')

// This class establishes an rpc connection to Tendermint.
// Used for listening to events, such as new blocks.
class CosmosNodeSubscription {
constructor(network, CosmosApiClass, store) {
this.network = network
this.cosmosAPI = new CosmosApiClass(network)
this.store = store

// Create a RPC subscription for each network that will react to new block events.
Tendermint()
.connect(this.network.rpc_url)
.then(connectedClient => {
connectedClient.subscribe({ query: "tm.event='NewBlock'" }, event =>
this.newBlockHandler(event.block.header.height)
)
})
}

// For each block event, we fetch the block information and publish a message.
// A GraphQL resolver is listening for these messages and sends the block to
// each subscribed user.
async newBlockHandler(height) {
const block = await this.cosmosAPI.getBlockByHeight({
blockHeight: height
})
const validatorMap = await this.getLatestBlockData()
this.store.update({ height, block, validators: validatorMap })
publishBlockAdded(this.network.id, block)

// For each transaction listed in a block we fetch the transaction and
// extract the relevant addresses. This is published to the network.
// A GraphQL resolver is listening for these messages and sends the
// transaction to each subscribed user.
const txs = await this.cosmosAPI.getTransactionsByHeight(height)
txs.forEach(tx => {
this.cosmosAPI.extractInvolvedAddresses(tx.raw).forEach(address => {
publishUserTransactionAdded(this.network.id, address, tx)
})
})

this.cosmosAPI.clearMemory()
}

async getLatestBlockData() {
const validators = await this.cosmosAPI.getAllValidators()
const validatorMap = _.keyBy(validators, 'operatorAddress')
return validatorMap
}
}

module.exports = CosmosNodeSubscription
Loading

0 comments on commit 5a468dc

Please sign in to comment.