From ba5fa0cddedc1862f4ae18e5334336718ed699cf Mon Sep 17 00:00:00 2001 From: Bartosz Zabuski Date: Thu, 26 Jul 2018 00:19:23 +0100 Subject: [PATCH 1/5] adding validators page --- components/nav.js | 3 ++ components/upvotevalidator.js | 48 +++++++++++++++++ pages/validators.js | 99 +++++++++++++++++++++++++++++++++++ routes.js | 3 +- utils/ajaxUtils.js | 45 +++++++++++++--- utils/rpcUtils.js | 3 +- 6 files changed, 191 insertions(+), 10 deletions(-) create mode 100644 components/upvotevalidator.js create mode 100644 pages/validators.js diff --git a/components/nav.js b/components/nav.js index 34a712a..f37a24f 100644 --- a/components/nav.js +++ b/components/nav.js @@ -46,6 +46,9 @@ class Nav extends React.Component {
  • Submit
  • +
  • + Validators +
  • diff --git a/components/upvotevalidator.js b/components/upvotevalidator.js new file mode 100644 index 0000000..65e29b3 --- /dev/null +++ b/components/upvotevalidator.js @@ -0,0 +1,48 @@ +import React from 'react' +import makeRPC from '../utils/rpcUtils' +import encoding from '../utils/encoding' + +class UpvoteValidator extends React.Component { + constructor(props, context) { + super(props, context); + this.state = {}; + } + + upvote = (validatorId) => { + if (!this.props.user) { + window.location.href = '/signup'; + return; + } + + const secret = encoding.hex2ab(localStorage.getItem('mintPK')); + const publicKey = nacl.util.encodeBase64(nacl.sign.keyPair.fromSecretKey(secret).publicKey); + + let txBody = { + type: "upvoteValidator", + entity: { + stamp: new Date().getTime(), + // validator: validatorId, + user: this.props.user._id, + } + } + + console.log("validator "+ validatorId) + console.log("txBody "+ txBody) + console.log("txBody "+ JSON.stringify(txBody)) + console.log("publicKey "+ publicKey) + console.log("secret "+ secret) + makeRPC(txBody, publicKey, secret); + + // this.props.upvoteCallback(this.props.validator._id, !this.props.validator.upvotedByCurrentUser); + this.props.upvoteCallback(validatorId); + } + + render() { + return ( + // + + ) + } +} + +export default UpvoteValidator diff --git a/pages/validators.js b/pages/validators.js new file mode 100644 index 0000000..035831f --- /dev/null +++ b/pages/validators.js @@ -0,0 +1,99 @@ +import Link from 'next/link' +import React from 'react' +import Nav from '../components/nav' +import encoding from '../utils/encoding' +import makeRPC from '../utils/rpcUtils' +import ajaxUtils from '../utils/ajaxUtils' +import UpvoteValidator from '../components/upvotevalidator' +import bson from 'bson' +import Helmet from 'react-helmet' + +class Validators extends React.Component { + + static async getInitialProps({ req }) { + const id = req.query.id; + const validators = await ajaxUtils.getValidators(); + return { validators }; + } + + constructor(props, context) { + super(props, context); + this.state = { validators: props.validators }; + } + + async componentDidMount() { + const key = localStorage.getItem('mintPK'); + + if (!key) { + return; + } + + const keyPair = nacl.sign.keyPair.fromSecretKey(encoding.hex2ab(key)); + const publicKey = encoding.toHexString(keyPair.publicKey).toUpperCase(); + + const user = await ajaxUtils.loadUser(publicKey); + this.setState({ user }); + } + + upvoteCallback = (validatorId) => { + // const post = Object.assign({}, this.state.post); + // post.upvotedByCurrentUser = status; + // post.upvotes += (status ? 1 : -1); + // this.setState({ post: post }); + } + + showLoginPrompt = e => { + e.preventDefault(); + const pk = prompt("Please enter your private key"); + if (!pk) { + return; + } + window.localStorage.setItem("mintPK", pk); + window.location.href = "/"; + } + + render() { + const validators = this.state.validators.map((validator) => { + return ( + // + + +
    + +
    + + {validator._id} + {validator.address} + {validator.votes} + + ) + }); + return ( + +
    +
    + ) + } +} + +export default Validators; diff --git a/routes.js b/routes.js index fef8d97..a5e330d 100644 --- a/routes.js +++ b/routes.js @@ -7,7 +7,8 @@ module.exports = () => { '/ask': { page: '/index' }, '/signup': { page: '/signup' }, '/submit': { page: '/submit' }, + '/validators': { page: '/validators' }, '/post': { page: '/post' }, '/comment-reply': { page: '/commentreply' } } -} \ No newline at end of file +} diff --git a/utils/ajaxUtils.js b/utils/ajaxUtils.js index 3f8f974..d28549e 100644 --- a/utils/ajaxUtils.js +++ b/utils/ajaxUtils.js @@ -19,7 +19,7 @@ export default { else if (path === '/ask') { url += '?type=askUH'; } - + const response = await fetch(url, { method: 'GET', headers: { @@ -27,7 +27,7 @@ export default { }, credentials: 'same-origin' }); - + const data = await response.json(); return data.posts; }, @@ -39,7 +39,7 @@ export default { }, credentials: 'same-origin' }); - + const data = await response.json(); return data.user; }, @@ -51,7 +51,7 @@ export default { }, credentials: 'same-origin' }); - + const data = await response.json(); return data.status; }, @@ -63,7 +63,7 @@ export default { }, credentials: 'same-origin' }); - + const data = await response.json(); return data.status; }, @@ -75,10 +75,39 @@ export default { }, credentials: 'same-origin' }); - + const data = await response.json(); return data.post; }, + getValidators: async () => { + // const response = await fetch(publicRuntimeConfig.baseUrl + '/ajax/post?id=' + id, { + // method: 'GET', + // headers: { + // 'Content-Type': 'application/json' + // }, + // credentials: 'same-origin' + // }); + // + // const data = await response.json(); + const validators = [ + { + "_id":123, + "address":"addressssssss111", + "votes":1111 + }, + { + "_id":234, + "address":"addressssssss2222", + "votes":222 + }, + { + "_id":345, + "address":"addressssssss333", + "votes":333 + } +] + return validators; + }, getComment: async (id) => { const response = await fetch(publicRuntimeConfig.baseUrl + '/ajax/comment?id=' + id, { method: 'GET', @@ -87,8 +116,8 @@ export default { }, credentials: 'same-origin' }); - + const data = await response.json(); return data.comment; } -} \ No newline at end of file +} diff --git a/utils/rpcUtils.js b/utils/rpcUtils.js index bd2e196..bf2c954 100644 --- a/utils/rpcUtils.js +++ b/utils/rpcUtils.js @@ -1,6 +1,7 @@ import encoding from './encoding'; export default async function makeRPC(txBody, publicKey, secret, cb) { + console.log("makeRPC txBody "+ txBody) let signature = nacl.sign.detached(nacl.util.decodeUTF8(JSON.stringify(txBody)), secret); let tx = { @@ -21,4 +22,4 @@ export default async function makeRPC(txBody, publicKey, secret, cb) { const json = await response.json(); cb && cb(json); -} \ No newline at end of file +} From 745af762a379c29c173d8f5df76baf4196587577 Mon Sep 17 00:00:00 2001 From: Bartosz Zabuski Date: Sun, 29 Jul 2018 00:39:13 +0100 Subject: [PATCH 2/5] adding call to fetch validators, minor refactoring --- components/upvotevalidator.js | 9 +++++---- mongo-test.js | 32 ++++++++++++++++++++++++++++++ pages/validators.js | 4 ++-- routes/rpc.routes.js | 5 ++++- routes/site.routes.js | 33 +++++++++++++++++++++++++------ utils/ajaxUtils.js | 37 ++++++++++------------------------- 6 files changed, 80 insertions(+), 40 deletions(-) create mode 100644 mongo-test.js diff --git a/components/upvotevalidator.js b/components/upvotevalidator.js index 65e29b3..edefd8f 100644 --- a/components/upvotevalidator.js +++ b/components/upvotevalidator.js @@ -8,7 +8,8 @@ class UpvoteValidator extends React.Component { this.state = {}; } - upvote = (validatorId) => { + upvote = () => { + console.log("validator: " + this.props.validator) if (!this.props.user) { window.location.href = '/signup'; return; @@ -21,12 +22,12 @@ class UpvoteValidator extends React.Component { type: "upvoteValidator", entity: { stamp: new Date().getTime(), - // validator: validatorId, + validator: this.props.validator._id, + // TODO actually user not needed. We can fetch user from DB by quering pubKey. To be Removed! user: this.props.user._id, } } - console.log("validator "+ validatorId) console.log("txBody "+ txBody) console.log("txBody "+ JSON.stringify(txBody)) console.log("publicKey "+ publicKey) @@ -34,7 +35,7 @@ class UpvoteValidator extends React.Component { makeRPC(txBody, publicKey, secret); // this.props.upvoteCallback(this.props.validator._id, !this.props.validator.upvotedByCurrentUser); - this.props.upvoteCallback(validatorId); + this.props.upvoteCallback(this.props.validator._id); } render() { diff --git a/mongo-test.js b/mongo-test.js new file mode 100644 index 0000000..7232904 --- /dev/null +++ b/mongo-test.js @@ -0,0 +1,32 @@ +var MongoClient = require('mongodb').MongoClient; + +var url = "mongodb://localhost:27017/"; + +MongoClient.connect(url, function(err, db) { + if (err) throw err; + var dbo = db.db("tendermintdb"); + //Find the first document in the customers collection: + dbo.collection("validators").aggregate([ + { + $project: { + name: 1, + votes: { $size: "$votes" } + } + }, + { + $sort: + {votes : -1} + } + ]).toArray(function(err, result) { + if (err) throw err; + console.log(result.name); + console.log(result); + db.close(); + }); + // dbo.collection("validators").find({}).toArray(function(err, result) { + // if (err) throw err; + // console.log(result.name); + // console.log(result); + // db.close(); + // }); +}); diff --git a/pages/validators.js b/pages/validators.js index 035831f..36180b3 100644 --- a/pages/validators.js +++ b/pages/validators.js @@ -59,11 +59,11 @@ class Validators extends React.Component {
    - +
    {validator._id} - {validator.address} + {validator.name} {validator.votes} ) diff --git a/routes/rpc.routes.js b/routes/rpc.routes.js index 06aede3..00cec93 100644 --- a/routes/rpc.routes.js +++ b/routes/rpc.routes.js @@ -20,8 +20,11 @@ router.route('/rpc').post((req, res) => { } request(options, function (error, response, body) { + console.log(error) + console.log(response) + console.log(body) res.json({ body: response.body }); }); }); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/routes/site.routes.js b/routes/site.routes.js index cafa729..a38743e 100644 --- a/routes/site.routes.js +++ b/routes/site.routes.js @@ -1,6 +1,6 @@ const express = require('express'); const router = express.Router(); -const dbUtil = require('../db'); +const dbUtil = require('../db'); const async = require('async'); const ObjectId = require('mongodb').ObjectId; const _ = require('lodash'); @@ -19,11 +19,11 @@ function unflatten( array, parent, tree ){ if( !_.isEmpty( children ) ){ if(!parent._id){ - tree = children; + tree = children; }else{ parent['comments'] = children; } - _.each( children, function( child ){ unflatten( array, child ) } ); + _.each( children, function( child ){ unflatten( array, child ) } ); } return tree; @@ -33,7 +33,28 @@ router.route('/ajax/fetch-user').get((req, res) => { const db = dbUtil.getDB(); db.collection('users').findOne({publicKey: req.query.pk}, function(err, user){ - res.json({ user: user}); + res.json({ user: user }); + }); +}); + +router.route('/ajax/validators').get((req, res) => { + const db = dbUtil.getDB(); + db.collection("validators").aggregate( + [ + { + $project: { + name: 1, + votes: { $size: "$votes" } + } + }, + { + $sort: + {votes : -1} + } + ] + ).toArray(function(err, result) { + if (err) throw err; + res.json({ validators : result }) }); }); @@ -56,7 +77,7 @@ router.route('/ajax/get-posts').get((req, res) => { db.collection('users').findOne({ _id: post.author }, function(err, user){ post.author = user; cb(null, post); - }); + }); }, (err, result) => { res.json({ posts: result }); }); @@ -170,4 +191,4 @@ router.route('/ajax/get-comment-upvote-status').get((req, res) => { }); }); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/utils/ajaxUtils.js b/utils/ajaxUtils.js index d28549e..a24baed 100644 --- a/utils/ajaxUtils.js +++ b/utils/ajaxUtils.js @@ -80,33 +80,16 @@ export default { return data.post; }, getValidators: async () => { - // const response = await fetch(publicRuntimeConfig.baseUrl + '/ajax/post?id=' + id, { - // method: 'GET', - // headers: { - // 'Content-Type': 'application/json' - // }, - // credentials: 'same-origin' - // }); - // - // const data = await response.json(); - const validators = [ - { - "_id":123, - "address":"addressssssss111", - "votes":1111 - }, - { - "_id":234, - "address":"addressssssss2222", - "votes":222 - }, - { - "_id":345, - "address":"addressssssss333", - "votes":333 - } -] - return validators; + const response = await fetch(publicRuntimeConfig.baseUrl + '/ajax/validators', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + }, + credentials: 'same-origin' + }); + + const data = await response.json(); + return data.validators; }, getComment: async (id) => { const response = await fetch(publicRuntimeConfig.baseUrl + '/ajax/comment?id=' + id, { From 5a36c2aa7514cc680e636ddd57f5cdf68f4cca2a Mon Sep 17 00:00:00 2001 From: Bartosz Zabuski Date: Mon, 30 Jul 2018 00:39:08 +0100 Subject: [PATCH 3/5] decresing amount of active validators --- pages/validators.js | 68 ++++++++++++++++++++++++++++++++++++++----- routes/site.routes.js | 16 +++++++++- utils/ajaxUtils.js | 2 +- 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/pages/validators.js b/pages/validators.js index 36180b3..5fe0f16 100644 --- a/pages/validators.js +++ b/pages/validators.js @@ -12,13 +12,19 @@ class Validators extends React.Component { static async getInitialProps({ req }) { const id = req.query.id; - const validators = await ajaxUtils.getValidators(); - return { validators }; + const data = await ajaxUtils.getValidators(); + return { + active: data.active, + standby: data.standby + }; } constructor(props, context) { super(props, context); - this.state = { validators: props.validators }; + this.state = { + active: props.active, + standby: props.standby + }; } async componentDidMount() { @@ -53,7 +59,11 @@ class Validators extends React.Component { } render() { - const validators = this.state.validators.map((validator) => { + // var createSquareFuncWithAdjustment = function(adjustment) { + // return function(x) { return (x * x) + adjustment; }; + // }; + + const active = this.state.active.map((validator, index) => { return ( // @@ -62,6 +72,25 @@ class Validators extends React.Component {
    + {validator.rank} + {validator._id} + {validator.name} + {validator.votes} + + ) + }); + // const rank = active.length + const standby = this.state.standby.map((validator, index) => { + return ( + // rank += 1 + // + + +
    + +
    + + {validator.rank} {validator._id} {validator.name} {validator.votes} @@ -69,29 +98,54 @@ class Validators extends React.Component { ) }); return ( -
    + +
    +
    +

    Standby validators:

    +
    + + + + + + + + + + + + {standby} + +
    RankAddressWitnessVotes
    +
    +
    +
    + + ) } } diff --git a/routes/site.routes.js b/routes/site.routes.js index a38743e..a452a1c 100644 --- a/routes/site.routes.js +++ b/routes/site.routes.js @@ -38,6 +38,7 @@ router.route('/ajax/fetch-user').get((req, res) => { }); router.route('/ajax/validators').get((req, res) => { + const numActiveValidators = 3 const db = dbUtil.getDB(); db.collection("validators").aggregate( [ @@ -54,7 +55,20 @@ router.route('/ajax/validators').get((req, res) => { ] ).toArray(function(err, result) { if (err) throw err; - res.json({ validators : result }) + + result.forEach((element, index) => { + element.rank = index + 1 + }) + console.log("here: ") + console.log(result) + // TODO looking at the fact that I'm starting to add knowledge about 'numActiveValidators' here + // and that knowledge is duplicted in ABCI backend app, I'm thinking we could consider + // moving this as a proper backend service exposing API to the fronted. Effectively, + // building single point of access for frontend (but I may be biased since I'm mainly a backend dev :P) + res.json({ + active : result.slice(0, numActiveValidators), + standby: result.slice(numActiveValidators) + }) }); }); diff --git a/utils/ajaxUtils.js b/utils/ajaxUtils.js index a24baed..0392b26 100644 --- a/utils/ajaxUtils.js +++ b/utils/ajaxUtils.js @@ -89,7 +89,7 @@ export default { }); const data = await response.json(); - return data.validators; + return data; }, getComment: async (id) => { const response = await fetch(publicRuntimeConfig.baseUrl + '/ajax/comment?id=' + id, { From ae18918e8dd88311192c9dd6c65f49954a50d39b Mon Sep 17 00:00:00 2001 From: Bartosz Zabuski Date: Mon, 30 Jul 2018 01:01:53 +0100 Subject: [PATCH 4/5] minor cleanup --- components/upvotevalidator.js | 2 -- mongo-test.js | 32 -------------------------------- pages/validators.js | 14 ++------------ routes/rpc.routes.js | 3 --- 4 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 mongo-test.js diff --git a/components/upvotevalidator.js b/components/upvotevalidator.js index edefd8f..9f47b1f 100644 --- a/components/upvotevalidator.js +++ b/components/upvotevalidator.js @@ -34,13 +34,11 @@ class UpvoteValidator extends React.Component { console.log("secret "+ secret) makeRPC(txBody, publicKey, secret); - // this.props.upvoteCallback(this.props.validator._id, !this.props.validator.upvotedByCurrentUser); this.props.upvoteCallback(this.props.validator._id); } render() { return ( - // ) } diff --git a/mongo-test.js b/mongo-test.js deleted file mode 100644 index 7232904..0000000 --- a/mongo-test.js +++ /dev/null @@ -1,32 +0,0 @@ -var MongoClient = require('mongodb').MongoClient; - -var url = "mongodb://localhost:27017/"; - -MongoClient.connect(url, function(err, db) { - if (err) throw err; - var dbo = db.db("tendermintdb"); - //Find the first document in the customers collection: - dbo.collection("validators").aggregate([ - { - $project: { - name: 1, - votes: { $size: "$votes" } - } - }, - { - $sort: - {votes : -1} - } - ]).toArray(function(err, result) { - if (err) throw err; - console.log(result.name); - console.log(result); - db.close(); - }); - // dbo.collection("validators").find({}).toArray(function(err, result) { - // if (err) throw err; - // console.log(result.name); - // console.log(result); - // db.close(); - // }); -}); diff --git a/pages/validators.js b/pages/validators.js index 5fe0f16..47ab2ff 100644 --- a/pages/validators.js +++ b/pages/validators.js @@ -42,10 +42,8 @@ class Validators extends React.Component { } upvoteCallback = (validatorId) => { - // const post = Object.assign({}, this.state.post); - // post.upvotedByCurrentUser = status; - // post.upvotes += (status ? 1 : -1); - // this.setState({ post: post }); + // TODO should be refactored to update the state. + // ATM page needs to be refreshed to see updated results } showLoginPrompt = e => { @@ -59,13 +57,8 @@ class Validators extends React.Component { } render() { - // var createSquareFuncWithAdjustment = function(adjustment) { - // return function(x) { return (x * x) + adjustment; }; - // }; - const active = this.state.active.map((validator, index) => { return ( - //
    @@ -79,11 +72,8 @@ class Validators extends React.Component { ) }); - // const rank = active.length const standby = this.state.standby.map((validator, index) => { return ( - // rank += 1 - //
    diff --git a/routes/rpc.routes.js b/routes/rpc.routes.js index 00cec93..b734155 100644 --- a/routes/rpc.routes.js +++ b/routes/rpc.routes.js @@ -20,9 +20,6 @@ router.route('/rpc').post((req, res) => { } request(options, function (error, response, body) { - console.log(error) - console.log(response) - console.log(body) res.json({ body: response.body }); }); }); From bd862159e2daff38cefa942a539e49df82c26504 Mon Sep 17 00:00:00 2001 From: Bartosz Zabuski Date: Wed, 1 Aug 2018 23:29:22 +0100 Subject: [PATCH 5/5] refactoring query to fetch validators after backend changes --- pages/validators.js | 4 ++-- routes/site.routes.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pages/validators.js b/pages/validators.js index 47ab2ff..d5a0773 100644 --- a/pages/validators.js +++ b/pages/validators.js @@ -68,7 +68,7 @@ class Validators extends React.Component { {validator.rank} {validator._id} {validator.name} - {validator.votes} + {validator.upvotes} ) }); @@ -83,7 +83,7 @@ class Validators extends React.Component { {validator.rank} {validator._id} {validator.name} - {validator.votes} + {validator.upvotes} ) }); diff --git a/routes/site.routes.js b/routes/site.routes.js index a452a1c..9e6cf85 100644 --- a/routes/site.routes.js +++ b/routes/site.routes.js @@ -45,12 +45,12 @@ router.route('/ajax/validators').get((req, res) => { { $project: { name: 1, - votes: { $size: "$votes" } + upvotes: 1 } }, { $sort: - {votes : -1} + {upvotes : -1} } ] ).toArray(function(err, result) {