Skip to content

Commit

Permalink
Witness Update 0.3.0
Browse files Browse the repository at this point in the history
Add WitnessModel to aggregate the util functions and involved data set.
Add alarms for version, feed.
  • Loading branch information
ianpark committed May 30, 2018
1 parent 4f8006e commit 12d0602
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 108 deletions.
15 changes: 11 additions & 4 deletions src/components/witness/DataFetcher.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import witnessSample from 'resources/witness_sample.json';
import witnessIndex from 'resources/witness_index_sample.json';
import React, {Component} from 'react';
var steem = require('steem');
let steem = require('steem');
let witnessModel = require('./WitnessModel');


const convertToPrice = (price) => {
return price.base.split(' ')[0] / price.quote.split(' ')[0];
Expand Down Expand Up @@ -88,17 +90,22 @@ class DataFetcher extends Component {
})
.then((priceFeed) => {
const avgFeed = convertToPrice(priceFeed);
console.log(avgFeed);
this.witness.forEach(witness => {
witness.feedBias = (convertToPrice(witness.sbd_exchange_rate) - avgFeed) / avgFeed;
witness.priceFeed = convertToPrice(witness.sbd_exchange_rate);
let delta = witness.priceFeed - avgFeed;
if (delta < 0) delta = delta * 2;

witness.feedBias = (delta / avgFeed) * 100;
})
})
.catch((err) => {
console.log("Failed to fetch witness data");
console.log(err);
})
.done(() => {
console.log(this.witness);
this.props.onData({witnesses: this.witness, witnessIndex: this.witnessIndex});
witnessModel.buildInitialData(this.witness, this.witnessIndex);
this.props.onData(witnessModel);
});
}

Expand Down
46 changes: 14 additions & 32 deletions src/components/witness/WitnessDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,28 @@ const Colors = {
class WitnessDetail extends Component {
constructor(props) {
super(props);
let data = this.props.witness.manipulateData(this.props.account);
this.state = {
data: {
...this.props.data,
voteToTop20: this.getTopXCount(this.props.data.voteTo, 20),
voteFromTop20: this.getTopXCount(this.props.data.voteFrom, 20),
voteToTop30: this.getTopXCount(this.props.data.voteTo, 30),
voteFromTop30: this.getTopXCount(this.props.data.voteFrom, 30)
...data,
voteToTop20: this.getTopXCount(data.voteTo, 20),
voteFromTop20: this.getTopXCount(data.voteFrom, 20),
voteToTop30: this.getTopXCount(data.voteTo, 30),
voteFromTop30: this.getTopXCount(data.voteFrom, 30)
}
};
}

isDisabled = (account) => {
try {
return this.isDisabledByIndex(this.props.witnessIndex[account])
} catch (error) {
return false;
}
}

isDisabledByIndex = (index) => {
return this.props.witnesses[index].disabled;
}

getTopXCount = (items, x) => {
let voteCount = items.filter(item => item.rank <= x).length;
return {count: voteCount, ratio: voteCount ? (voteCount / items.length * 100) : 0}
}


witnessVoteWeight = () => {
let total = 0;
this.state.data.voteFrom.forEach(voter => {
total += this.props.witnesses[voter.rank-1].proxiedVests + this.props.witnesses[voter.rank-1].vestingShares;
});
return total;
}

renderVoteList = (vostList) => {
return vostList.map(x => {
let isDisabled = this.isDisabled(x.account);
let isDisabled = this.props.witness.isDisabled(x.account);
return <Label style={{
marginBottom: '2px',
color: 'white',
Expand All @@ -61,7 +43,7 @@ class WitnessDetail extends Component {
}

renderVoteChart = (vostList) => {
let count = this.props.witnesses.length;
let count = this.props.witness.getCount();
let inputData = new Array(count).fill(0);
vostList.forEach(vote => inputData[vote.rank-1] = 1)
const data = {
Expand All @@ -70,7 +52,7 @@ class WitnessDetail extends Component {
{
label: 'Votes to witness',
backgroundColor: inputData.map((value, key) =>
this.isDisabledByIndex(key) ? Colors.disabled : (key < 20) ? Colors.top20 : Colors.rest),
this.props.witness.isDisabledByIndex(key) ? Colors.disabled : (key < 20) ? Colors.top20 : Colors.rest),
borderWidth: 0,
data: inputData
}
Expand All @@ -94,8 +76,8 @@ class WitnessDetail extends Component {
return "";
},
label: (i, data) => {
let witness = this.props.witnesses[i.index];
return `${witness.owner} (rank:${i.index+1})`;
let owner = this.props.witness.getAccountByIndex(i.index);
return `${owner} (rank:${i.index+1})`;
}
}
},
Expand Down Expand Up @@ -132,7 +114,7 @@ class WitnessDetail extends Component {
renderProfile = () => {
const data = this.state.data;
const account = data.account;
const accountData = this.props.witnesses[this.props.witnessIndex[account]];
const accountData = this.props.witness.getByAccount(account);
const accountInfo = accountData.accountInfo
const profile = accountInfo.json_metadata ? JSON.parse(accountInfo.json_metadata).profile : null;

Expand All @@ -156,7 +138,7 @@ class WitnessDetail extends Component {
renderWitnessStatus = () => {
const data = this.state.data;
const account = data.account;
const accountData = this.props.witnesses[this.props.witnessIndex[account]];
const accountData = this.props.witness.getByAccount(account);
const witnessStatus = [
{name: 'Last Block', content: accountData.last_confirmed_block_num},
{name: 'Running Version', content: accountData.running_version},
Expand Down Expand Up @@ -185,7 +167,7 @@ class WitnessDetail extends Component {

render() {
const data = this.state.data;
const voteFromWitnesses = this.witnessVoteWeight();
const voteFromWitnesses = data.totalVoteFromWitnesses;
return (
<div>
{this.renderProfile()}
Expand Down
109 changes: 38 additions & 71 deletions src/components/witness/WitnessList.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,104 +13,71 @@ class WitnessList extends Component {
constructor(props) {
super(props);
this.state = {
witnessIndex: null,
witnesses: null,
ready: false,
showDetail: false,
selectedWitness: null
selectedWitness: null,
witness: null
}
}

onData = ({witnesses, witnessIndex}) => {
this.setState({witnesses: witnesses, witnessIndex: witnessIndex},
onData = (model) => {
this.setState({witness: model},
() => {
let selectedWitness = witnesses[witnessIndex[this.props.account]]
let selectedWitness = model.getByAccount(this.props.account);
this.setState({showDetail: this.props.account ? true : false,
selectedWitness: selectedWitness});
});
}

getRank(account) {
try {
return this.state.witnessIndex[account] + 1;
} catch (error) {
return null;
}
}

filterVote(voteList) {
let output = [];
voteList.map((user) => {
let rank = this.getRank(user);
if (rank) {
output.push({account: user, rank: rank})
}
});
return output.sort(function(a,b){return a.rank - b.rank;});
}

isDisabledForLong = (account) => {
try {
const witness = this.state.witnesses[this.state.witnessIndex[account]];
return witness.disabled && witness.sleepingMins > 1440;
} catch (error) {
return false;
}
}



manipulateData = (witness) => {
return {
rank: this.getRank(witness.owner),
account: witness.owner,
totalMissed: witness.total_missed,
receivingMVests: witness.votes / 1000000000000,
feedPrice: witness.sbd_exchange_rate.base.split(' ')[0],
proxy: witness.proxy || '-',
castedVote: witness.witness_votes.length,
receivedVote: witness.receiving_votes.length,
vestingShares: witness.vestingShares,
proxiedVests: witness.proxiedVests,
disabled: witness.disabled,
voteFrom: this.filterVote(witness.receiving_votes),
voteTo: this.filterVote(witness.witness_votes)
};
}

onModalClose = () => {
this.setState({account: null, showDetail: false});
this.props.history.push('/witness');
}

detailView = (account) => {
let selectedWitness = this.state.witnesses[this.state.witnessIndex[account]]
let selectedWitness = this.state.witness.getByAccount(account);
this.setState({showDetail: true, selectedWitness: selectedWitness});
this.props.history.push(`/witness/${account}`);

}

renderRow = (witness, key) => {
let data = this.manipulateData(witness);
let voteToWarn = false;
data.voteTo.forEach(x => {
if (this.isDisabledForLong(x.account)) voteToWarn = true;
});

let data = this.state.witness.manipulateData(witness.owner);
let state = data.disabled ? (data.disabledForLong ? 'negative' : 'warning') : '';
return (
<Table.Row key={key} style={data.disabled ? {background: '#ee6070', color: '#ffffff'} :{}}>
<Table.Row key={key} className={state}>
<Table.Cell>{data.rank}</Table.Cell>
<Table.Cell>{data.account} <Icon name="search" link color="blue" onClick={() => this.detailView(data.account)} style={{cursor: 'pointer'}}/></Table.Cell>
<Table.Cell>{data.account}
<Icon name="search" link color="blue" onClick={() => this.detailView(data.account)} style={{cursor: 'pointer'}}/>
{data.disabled &&
<Popup wide trigger={<Icon name="warning sign" color={state == 'warning' ? 'orange' : 'red'}/>}
content={`Inactive for ${(data.sleepingMins / 60).toFixed(1)} hours`}/>}
</Table.Cell>
<Table.Cell>{data.version}
{data.version < this.state.witness.secureVersion &&
<Popup wide trigger={<Icon name="warning sign" color="yellow"/>}
content={`A version lower than ${this.state.witness.secureVersion} might has a security hole. Note that 0.19.2 with full security patch is equivalant to 0.19.3, but there is no way to tell from the public if patches are applied or not.`}/>}
</Table.Cell>
<Table.Cell>{data.totalMissed}</Table.Cell>
<Table.Cell>{data.receivingMVests.toFixed(0)}</Table.Cell>
<Table.Cell>{(data.proxiedVests + data.vestingShares).toFixed(2)}</Table.Cell>
<Table.Cell>${data.feedPrice}</Table.Cell>
<Table.Cell>${data.feedPrice}
{Math.abs(data.feedBias) > 100 &&
<Popup wide trigger={<Icon name="warning sign" color="yellow"/>}
content={`Feed is biased ${data.feedBias.toFixed(0)}%`}/>}
</Table.Cell>
<Table.Cell>{data.proxy}</Table.Cell>
<Table.Cell>
{data.castedVote}
{voteToWarn &&
<Popup wide trigger={<Icon name="warning sign" color="orange"/>}
content="Voting to one or more disabled witnesses"/>}
{data.votingToInactive.length > 0 &&
<Popup wide trigger={<Icon name="heartbeat" color="orange"/>}
content={`Voting to witnesses who are inactive for more than ${this.state.witness.maxInactiveDay} days: ${data.votingToInactive.join(', ')} `}/>}
{data.votingToBiasedFeed.length > 0 &&
<Popup wide trigger={<Icon name="low vision" color="yellow"/>}
content={`Voting to witnesses whose feed is biased over 100%: ${data.votingToBiasedFeed.join(', ')} `}/>}
{data.votingToInsecureVer.length > 0 &&
<Popup wide trigger={<Icon name="warning sign" color="red"/>}
content={`Voting to witnesses whose version is lower than ${this.state.witness.semiSecureVersion} : ${data.votingToInsecureVer.join(', ')} `}/>}
</Table.Cell>
<Table.Cell>{data.receivedVote}</Table.Cell>
</Table.Row>
Expand All @@ -126,6 +93,7 @@ class WitnessList extends Component {
<Table.Row>
<Table.HeaderCell>#</Table.HeaderCell>
<Table.HeaderCell>Witness</Table.HeaderCell>
<Table.HeaderCell>Version</Table.HeaderCell>
<Table.HeaderCell>Missed<br/>Blocks</Table.HeaderCell>
<Table.HeaderCell>Receiving<br/>Votes<br/><sup>(MVests)</sup>
<Popup trigger={<Icon name='info circle'/>}
Expand All @@ -149,7 +117,7 @@ class WitnessList extends Component {
</Table.Row>
</Table.Header>

{this.state.witnesses ? <Table.Body>{this.state.witnesses.map((witness, key) => this.renderRow(witness, key))}</Table.Body>
{this.state.witness ? <Table.Body>{this.state.witness.witness.map((witness, key) => this.renderRow(witness, key))}</Table.Body>
: <Dimmer active><Loader>Loading</Loader></Dimmer>}

</Table>
Expand All @@ -158,9 +126,8 @@ class WitnessList extends Component {
<Modal.Header>Witness Report</Modal.Header>
<Modal.Content>
{this.state.selectedWitness ?
<WitnessDetail data={this.manipulateData(this.state.selectedWitness)}
witnessIndex={this.state.witnessIndex}
witnesses={this.state.witnesses} />
<WitnessDetail account={this.state.selectedWitness.owner}
witness={this.state.witness} />
:
"@" + this.props.account + " is not in the top 100 witnesses."
}
Expand Down
Loading

0 comments on commit 12d0602

Please sign in to comment.