Merge branch 'master' into ui-2
# Conflicts: # js/src/shell/Signer/components/TransactionPendingFormConfirm/transaction PendingFormConfirm.js # js/src/ui/Container/Title/title.js # js/src/views/Application/Snackbar/snackbar.js # js/src/views/Status/Peers/peers.js
This commit is contained in:
commit
31be9d25f3
@ -25,7 +25,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"validateScoreTransition": 1000000,
|
"validateScoreTransition": 1000000,
|
||||||
"eip155Transition": 1000000
|
"eip155Transition": 1000000,
|
||||||
|
"validateStepTransition": 1500000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -57,6 +57,8 @@ pub struct AuthorityRoundParams {
|
|||||||
pub validate_score_transition: u64,
|
pub validate_score_transition: u64,
|
||||||
/// Number of first block where EIP-155 rules are validated.
|
/// Number of first block where EIP-155 rules are validated.
|
||||||
pub eip155_transition: u64,
|
pub eip155_transition: u64,
|
||||||
|
/// Monotonic step validation transition block.
|
||||||
|
pub validate_step_transition: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
||||||
@ -70,6 +72,7 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
|||||||
start_step: p.start_step.map(Into::into),
|
start_step: p.start_step.map(Into::into),
|
||||||
validate_score_transition: p.validate_score_transition.map_or(0, Into::into),
|
validate_score_transition: p.validate_score_transition.map_or(0, Into::into),
|
||||||
eip155_transition: p.eip155_transition.map_or(0, Into::into),
|
eip155_transition: p.eip155_transition.map_or(0, Into::into),
|
||||||
|
validate_step_transition: p.validate_step_transition.map_or(0, Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,6 +131,7 @@ pub struct AuthorityRound {
|
|||||||
validators: Box<ValidatorSet>,
|
validators: Box<ValidatorSet>,
|
||||||
validate_score_transition: u64,
|
validate_score_transition: u64,
|
||||||
eip155_transition: u64,
|
eip155_transition: u64,
|
||||||
|
validate_step_transition: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
// header-chain validator.
|
// header-chain validator.
|
||||||
@ -208,6 +212,7 @@ impl AuthorityRound {
|
|||||||
validators: new_validator_set(our_params.validators),
|
validators: new_validator_set(our_params.validators),
|
||||||
validate_score_transition: our_params.validate_score_transition,
|
validate_score_transition: our_params.validate_score_transition,
|
||||||
eip155_transition: our_params.eip155_transition,
|
eip155_transition: our_params.eip155_transition,
|
||||||
|
validate_step_transition: our_params.validate_step_transition,
|
||||||
});
|
});
|
||||||
// Do not initialize timeouts for tests.
|
// Do not initialize timeouts for tests.
|
||||||
if should_timeout {
|
if should_timeout {
|
||||||
@ -379,7 +384,8 @@ impl Engine for AuthorityRound {
|
|||||||
|
|
||||||
// Ensure header is from the step after parent.
|
// Ensure header is from the step after parent.
|
||||||
let parent_step = header_step(parent)?;
|
let parent_step = header_step(parent)?;
|
||||||
if step <= parent_step {
|
if step == parent_step
|
||||||
|
|| (header.number() >= self.validate_step_transition && step <= parent_step) {
|
||||||
trace!(target: "engine", "Multiple blocks proposed for step {}.", parent_step);
|
trace!(target: "engine", "Multiple blocks proposed for step {}.", parent_step);
|
||||||
self.validators.report_malicious(header.author(), header.number(), Default::default());
|
self.validators.report_malicious(header.author(), header.number(), Default::default());
|
||||||
Err(EngineError::DoubleVote(header.author().clone()))?;
|
Err(EngineError::DoubleVote(header.author().clone()))?;
|
||||||
|
@ -39,9 +39,9 @@ export default class Parity {
|
|||||||
.then(outAccountInfo);
|
.then(outAccountInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
addReservedPeer (encode) {
|
addReservedPeer (enode) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_addReservedPeer', encode);
|
.execute('parity_addReservedPeer', enode);
|
||||||
}
|
}
|
||||||
|
|
||||||
chainStatus () {
|
chainStatus () {
|
||||||
@ -429,9 +429,9 @@ export default class Parity {
|
|||||||
.execute('parity_releasesInfo');
|
.execute('parity_releasesInfo');
|
||||||
}
|
}
|
||||||
|
|
||||||
removeReservedPeer (encode) {
|
removeReservedPeer (enode) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_removeReservedPeer', encode);
|
.execute('parity_removeReservedPeer', enode);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTransaction (hash) {
|
removeTransaction (hash) {
|
||||||
|
@ -104,6 +104,12 @@ export default class SignerMiddleware {
|
|||||||
return this.confirmRawRequest(store, id, signature);
|
return this.confirmRawRequest(store, id, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
confirmDecryptedMsg (store, id, decrypted) {
|
||||||
|
const { msg } = decrypted;
|
||||||
|
|
||||||
|
return this.confirmRawRequest(store, id, msg);
|
||||||
|
}
|
||||||
|
|
||||||
confirmSignedTransaction (store, id, txSigned) {
|
confirmSignedTransaction (store, id, txSigned) {
|
||||||
const { netVersion } = store.getState().nodeStatus;
|
const { netVersion } = store.getState().nodeStatus;
|
||||||
const { signature, tx } = txSigned;
|
const { signature, tx } = txSigned;
|
||||||
@ -154,7 +160,7 @@ export default class SignerMiddleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onConfirmStart = (store, action) => {
|
onConfirmStart = (store, action) => {
|
||||||
const { condition, gas = 0, gasPrice = 0, id, password, payload, txSigned, dataSigned, wallet } = action.payload;
|
const { condition, gas = 0, gasPrice = 0, id, password, payload, txSigned, dataSigned, decrypted, wallet } = action.payload;
|
||||||
const handlePromise = this._createConfirmPromiseHandler(store, id);
|
const handlePromise = this._createConfirmPromiseHandler(store, id);
|
||||||
const transaction = payload.sendTransaction || payload.signTransaction;
|
const transaction = payload.sendTransaction || payload.signTransaction;
|
||||||
|
|
||||||
@ -177,10 +183,14 @@ export default class SignerMiddleware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO [ToDr] Support eth_sign for external wallet (wallet && !transction)
|
// TODO [ToDr] Support eth_sign for external wallet (wallet && dataSigned)
|
||||||
if (dataSigned) {
|
if (dataSigned) {
|
||||||
return this.confirmSignedData(store, id, dataSigned);
|
return this.confirmSignedData(store, id, dataSigned);
|
||||||
}
|
}
|
||||||
|
// TODO [ToDr] Support parity_decrypt for external wallet (wallet && decrypted)
|
||||||
|
if (decrypted) {
|
||||||
|
return this.confirmDecryptedMsg(store, id, decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
return handlePromise(this._api.signer.confirmRequest(id, { gas, gasPrice, condition }, password));
|
return handlePromise(this._api.signer.confirmRequest(id, { gas, gasPrice, condition }, password));
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ class DecryptRequest extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderActions () {
|
renderActions () {
|
||||||
const { accounts, address, focus, isFinished, status } = this.props;
|
const { accounts, address, focus, isFinished, status, data } = this.props;
|
||||||
const account = accounts[address];
|
const account = accounts[address];
|
||||||
|
|
||||||
if (isFinished) {
|
if (isFinished) {
|
||||||
@ -153,15 +153,16 @@ class DecryptRequest extends Component {
|
|||||||
onConfirm={ this.onConfirm }
|
onConfirm={ this.onConfirm }
|
||||||
onReject={ this.onReject }
|
onReject={ this.onReject }
|
||||||
className={ styles.actions }
|
className={ styles.actions }
|
||||||
|
dataToSign={ { decrypt: data } }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onConfirm = (data) => {
|
onConfirm = (data) => {
|
||||||
const { id } = this.props;
|
const { id } = this.props;
|
||||||
const { password } = data;
|
const { password, decrypted, wallet } = data;
|
||||||
|
|
||||||
this.props.onConfirm({ id, password });
|
this.props.onConfirm({ id, password, decrypted, wallet });
|
||||||
}
|
}
|
||||||
|
|
||||||
onReject = () => {
|
onReject = () => {
|
||||||
|
@ -40,6 +40,12 @@ const PAYLOAD_SIGN = {
|
|||||||
const PAYLOAD_SIGNTX = {
|
const PAYLOAD_SIGNTX = {
|
||||||
signTransaction: TRANSACTION
|
signTransaction: TRANSACTION
|
||||||
};
|
};
|
||||||
|
const PAYLOAD_DECRYPT = {
|
||||||
|
decrypt: {
|
||||||
|
address: ADDRESS,
|
||||||
|
msg: 'testing'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let component;
|
let component;
|
||||||
let onConfirm;
|
let onConfirm;
|
||||||
@ -109,4 +115,18 @@ describe('views/Signer/RequestPending', () => {
|
|||||||
expect(component.find('Connect(TransactionPending)')).to.have.length(1);
|
expect(component.find('Connect(TransactionPending)')).to.have.length(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('decrypt', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
render(PAYLOAD_DECRYPT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(component).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders DecryptRequest component', () => {
|
||||||
|
expect(component.find('Connect(DecryptRequest)')).to.have.length(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -41,6 +41,9 @@ export default class TransactionPendingForm extends Component {
|
|||||||
}),
|
}),
|
||||||
PropTypes.shape({
|
PropTypes.shape({
|
||||||
data: PropTypes.string.isRequired
|
data: PropTypes.string.isRequired
|
||||||
|
}),
|
||||||
|
PropTypes.shape({
|
||||||
|
decrypt: PropTypes.string.isRequired
|
||||||
})
|
})
|
||||||
]).isRequired
|
]).isRequired
|
||||||
};
|
};
|
||||||
|
@ -22,7 +22,7 @@ import ReactTooltip from 'react-tooltip';
|
|||||||
|
|
||||||
import { Button, Form, Input, IdentityIcon, QrCode, QrScan } from '@parity/ui';
|
import { Button, Form, Input, IdentityIcon, QrCode, QrScan } from '@parity/ui';
|
||||||
|
|
||||||
import { generateTxQr, generateDataQr } from '~/shell/Signer/utils/qrscan';
|
import { generateTxQr, generateDecryptQr, generateDataQr } from '~/shell/Signer/utils/qrscan';
|
||||||
|
|
||||||
import styles from './transactionPendingFormConfirm.css';
|
import styles from './transactionPendingFormConfirm.css';
|
||||||
|
|
||||||
@ -344,7 +344,7 @@ export default class TransactionPendingFormConfirm extends Component {
|
|||||||
return (
|
return (
|
||||||
<QrScan
|
<QrScan
|
||||||
className={ styles.camera }
|
className={ styles.camera }
|
||||||
onScan={ this.onScanTx }
|
onScan={ this.onScan }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -396,8 +396,8 @@ export default class TransactionPendingFormConfirm extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onScanTx = (signature) => {
|
onScan = (signature) => {
|
||||||
const { chainId, rlp, tx, data } = this.state.qr;
|
const { chainId, rlp, tx, data, decrypt } = this.state.qr;
|
||||||
|
|
||||||
if (signature && signature.substr(0, 2) !== '0x') {
|
if (signature && signature.substr(0, 2) !== '0x') {
|
||||||
signature = `0x${signature}`;
|
signature = `0x${signature}`;
|
||||||
@ -417,6 +417,16 @@ export default class TransactionPendingFormConfirm extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (decrypt) {
|
||||||
|
this.props.onConfirm({
|
||||||
|
decrypted: {
|
||||||
|
decrypt,
|
||||||
|
msg: signature
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.props.onConfirm({
|
this.props.onConfirm({
|
||||||
dataSigned: {
|
dataSigned: {
|
||||||
data,
|
data,
|
||||||
@ -491,7 +501,7 @@ export default class TransactionPendingFormConfirm extends Component {
|
|||||||
generateQr = () => {
|
generateQr = () => {
|
||||||
const { api } = this.context;
|
const { api } = this.context;
|
||||||
const { netVersion, dataToSign } = this.props;
|
const { netVersion, dataToSign } = this.props;
|
||||||
const { transaction, data } = dataToSign;
|
const { transaction, data, decrypt } = dataToSign;
|
||||||
const setState = qr => {
|
const setState = qr => {
|
||||||
this.setState({ qr });
|
this.setState({ qr });
|
||||||
};
|
};
|
||||||
@ -501,6 +511,11 @@ export default class TransactionPendingFormConfirm extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (decrypt) {
|
||||||
|
generateDecryptQr(decrypt).then(setState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
generateDataQr(data).then(setState);
|
generateDataQr(data).then(setState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,7 +554,7 @@ export default class TransactionPendingFormConfirm extends Component {
|
|||||||
const { account, dataToSign } = this.props;
|
const { account, dataToSign } = this.props;
|
||||||
const { qr } = this.state;
|
const { qr } = this.state;
|
||||||
|
|
||||||
if (dataToSign.data && qr && !qr.value) {
|
if ((dataToSign.data || dataToSign.decrypt) && qr && !qr.value) {
|
||||||
this.generateQr();
|
this.generateQr();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,16 @@ export function generateDataQr (data) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateDecryptQr (data) {
|
||||||
|
return Promise.resolve({
|
||||||
|
decrypt: data,
|
||||||
|
value: JSON.stringify({
|
||||||
|
action: 'decrypt',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function generateTxQr (api, netVersion, transaction) {
|
export function generateTxQr (api, netVersion, transaction) {
|
||||||
return createUnsignedTx(api, netVersion, transaction)
|
return createUnsignedTx(api, netVersion, transaction)
|
||||||
.then((qr) => {
|
.then((qr) => {
|
||||||
|
35
js/src/ui/Container/Title/Actions/actions.js
Normal file
35
js/src/ui/Container/Title/Actions/actions.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
|
import styles from '../title.css';
|
||||||
|
|
||||||
|
export default function Actions ({ actions }) {
|
||||||
|
if (!actions || !actions.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.actions }>
|
||||||
|
{ actions }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Actions.propTypes = {
|
||||||
|
actions: PropTypes.array
|
||||||
|
};
|
17
js/src/ui/Container/Title/Actions/index.js
Normal file
17
js/src/ui/Container/Title/Actions/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './actions';
|
@ -21,6 +21,15 @@ $bylineMaxHeight: 2.4rem;
|
|||||||
$titleLineHeight: 2rem;
|
$titleLineHeight: 2rem;
|
||||||
$smallFontSize: 0.75rem;
|
$smallFontSize: 0.75rem;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
}
|
||||||
|
|
||||||
.byline,
|
.byline,
|
||||||
.description {
|
.description {
|
||||||
color: $bylineColor;
|
color: $bylineColor;
|
||||||
|
@ -18,24 +18,29 @@ import React, { PropTypes } from 'react';
|
|||||||
|
|
||||||
import { nodeOrStringProptype } from '@parity/shared/util/proptypes';
|
import { nodeOrStringProptype } from '@parity/shared/util/proptypes';
|
||||||
|
|
||||||
|
import Actions from './Actions';
|
||||||
import Byline from './Byline';
|
import Byline from './Byline';
|
||||||
import Description from './Description';
|
import Description from './Description';
|
||||||
|
|
||||||
import styles from './title.css';
|
import styles from './title.css';
|
||||||
|
|
||||||
export default function Title ({ byline, className, description, title }) {
|
export default function Title ({ actions, byline, className, description, title }) {
|
||||||
return (
|
return (
|
||||||
<div className={ className }>
|
<div className={ className }>
|
||||||
|
<div>
|
||||||
<h3 className={ styles.title }>
|
<h3 className={ styles.title }>
|
||||||
{ title }
|
{ title }
|
||||||
</h3>
|
</h3>
|
||||||
<Byline byline={ byline } />
|
<Byline byline={ byline } />
|
||||||
<Description description={ description } />
|
<Description description={ description } />
|
||||||
</div>
|
</div>
|
||||||
|
<Actions actions={ actions } />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Title.propTypes = {
|
Title.propTypes = {
|
||||||
|
actions: PropTypes.array,
|
||||||
byline: nodeOrStringProptype(),
|
byline: nodeOrStringProptype(),
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
description: nodeOrStringProptype(),
|
description: nodeOrStringProptype(),
|
||||||
|
@ -45,3 +45,16 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
float: right;
|
||||||
|
width: 40em;
|
||||||
|
|
||||||
|
.input {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,26 +14,94 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { Container } from '@parity/ui';
|
import { showSnackbar } from '@parity/shared/redux/providers/snackbarActions';
|
||||||
|
import { newError } from '@parity/shared/redux/actions';
|
||||||
import Peer from './Peer';
|
import { Button, Container, ContainerTitle, Input, ScrollableText, ShortenedHash } from '@parity/ui';
|
||||||
|
|
||||||
import styles from './peers.css';
|
import styles from './peers.css';
|
||||||
|
|
||||||
function Peers ({ peers }) {
|
class Peers extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
api: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
peers: PropTypes.array.isRequired,
|
||||||
|
newError: PropTypes.func,
|
||||||
|
showSnackbar: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
action: '',
|
||||||
|
formInput: '',
|
||||||
|
showForm: false
|
||||||
|
};
|
||||||
|
|
||||||
|
getActions () {
|
||||||
|
return [
|
||||||
|
<Button
|
||||||
|
key='btn_acceptNonReserved'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.acceptNonReserved.label'
|
||||||
|
defaultMessage='Accept non-reserved'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleAcceptNonReserved }
|
||||||
|
/>,
|
||||||
|
<Button
|
||||||
|
key='btn_dropNonReserved'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.dropNonReserved.label'
|
||||||
|
defaultMessage='Drop non-reserved'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleDropNonReserved }
|
||||||
|
/>,
|
||||||
|
<Button
|
||||||
|
key='btn_addReserved'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.addReserved.label'
|
||||||
|
defaultMessage='Add reserved'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleAddReserved }
|
||||||
|
/>,
|
||||||
|
<Button
|
||||||
|
key='btn_removeReserved'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.removeReserved.label'
|
||||||
|
defaultMessage='Remove reserved'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleRemoveReserved }
|
||||||
|
/>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { peers } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container>
|
||||||
|
<ContainerTitle
|
||||||
|
actions={ this.getActions() }
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='status.peers.title'
|
id='status.peers.title'
|
||||||
defaultMessage='network peers'
|
defaultMessage='network peers'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
/>
|
||||||
|
{ this.renderForm() }
|
||||||
<div className={ styles.peers }>
|
<div className={ styles.peers }>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@ -78,27 +146,195 @@ function Peers ({ peers }) {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{
|
{ this.renderPeers(peers) }
|
||||||
peers.map((peer, index) => {
|
|
||||||
return (
|
|
||||||
<Peer
|
|
||||||
index={ index }
|
|
||||||
key={ index }
|
|
||||||
peer={ peer }
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Peers.propTypes = {
|
renderForm () {
|
||||||
peers: PropTypes.array.isRequired
|
const { action, showForm } = this.state;
|
||||||
};
|
|
||||||
|
if (!showForm) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.form }>
|
||||||
|
<div className={ styles.input }>
|
||||||
|
<Input
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.form.label'
|
||||||
|
defaultMessage='Peer enode URL'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onChange={ this.handleInputChange }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.form.action.label'
|
||||||
|
defaultMessage='{add, select, true {Add} false {}}{remove, select, true {Remove} false {}}'
|
||||||
|
values={ {
|
||||||
|
add: action === 'add',
|
||||||
|
remove: action === 'remove'
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleConfirmForm }
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.form.cancel.label'
|
||||||
|
defaultMessage='Cancel'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleCancelForm }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPeers (peers) {
|
||||||
|
return peers.map((peer, index) => this.renderPeer(peer, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPeer (peer, index) {
|
||||||
|
const { caps, id, name, network, protocols } = peer;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
className={ styles.peer }
|
||||||
|
key={ id }
|
||||||
|
>
|
||||||
|
<td>
|
||||||
|
{ index + 1 }
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ScrollableText small text={ id } />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{ network.remoteAddress }
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{ name }
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{
|
||||||
|
protocols.eth
|
||||||
|
? <ShortenedHash data={ protocols.eth.head } />
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{
|
||||||
|
protocols.eth && protocols.eth.difficulty.gt(0)
|
||||||
|
? protocols.eth.difficulty.toExponential(16)
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{
|
||||||
|
caps && caps.length > 0
|
||||||
|
? caps.join(' - ')
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAcceptNonReserved = () => {
|
||||||
|
return this.context.api.parity.acceptNonReservedPeers()
|
||||||
|
.then(() => {
|
||||||
|
const message = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.acceptNonReservedPeers.success'
|
||||||
|
defaultMessage='Accepting non-reserved peers'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
this.props.showSnackbar(message, 3000);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.props.newError(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleDropNonReserved = () => {
|
||||||
|
return this.context.api.parity.dropNonReservedPeers()
|
||||||
|
.then(() => {
|
||||||
|
const message = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.dropNonReservedPeers.success'
|
||||||
|
defaultMessage='Dropping non-reserved peers'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
this.props.showSnackbar(message, 3000);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.props.newError(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleAddReserved = () => {
|
||||||
|
this.setState({ showForm: true, action: 'add' });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleRemoveReserved = () => {
|
||||||
|
this.setState({ showForm: true, action: 'remove' });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleInputChange = (event, value) => {
|
||||||
|
this.setState({ formInput: value });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCancelForm = () => {
|
||||||
|
this.setState({ showForm: false, action: '', formInput: '' });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleConfirmForm = () => {
|
||||||
|
const { action, formInput } = this.state;
|
||||||
|
let method;
|
||||||
|
|
||||||
|
if (action === 'add') {
|
||||||
|
method = 'addReservedPeer';
|
||||||
|
} else if (action === 'remove') {
|
||||||
|
method = 'removeReservedPeer';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ showForm: false, action: '', formInput: '' });
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.context.api.parity[method](formInput)
|
||||||
|
.then(() => {
|
||||||
|
const message = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.form.action.success'
|
||||||
|
defaultMessage='Successfully {add, select, true {added} false {}}{remove, select, true {removed} false {}} a reserved peer'
|
||||||
|
values={ {
|
||||||
|
add: action === 'add',
|
||||||
|
remove: action === 'remove'
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
this.props.showSnackbar(message, 3000);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.props.newError(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const handshakeRegex = /handshake/i;
|
const handshakeRegex = /handshake/i;
|
||||||
@ -118,7 +354,11 @@ function mapStateToProps (state) {
|
|||||||
return { peers: realPeers };
|
return { peers: realPeers };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
function mapDispatchToProps (dispatch) {
|
||||||
mapStateToProps,
|
return bindActionCreators({
|
||||||
null
|
newError,
|
||||||
)(Peers);
|
showSnackbar
|
||||||
|
}, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(Peers);
|
||||||
|
@ -46,6 +46,9 @@ pub struct AuthorityRoundParams {
|
|||||||
/// See main AuthorityRoundParams docs.
|
/// See main AuthorityRoundParams docs.
|
||||||
#[serde(rename="eip155Transition")]
|
#[serde(rename="eip155Transition")]
|
||||||
pub eip155_transition: Option<Uint>,
|
pub eip155_transition: Option<Uint>,
|
||||||
|
/// Block from which monotonic steps start.
|
||||||
|
#[serde(rename="validateStepTransition")]
|
||||||
|
pub validate_step_transition: Option<Uint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authority engine deserialization.
|
/// Authority engine deserialization.
|
||||||
@ -71,7 +74,8 @@ mod tests {
|
|||||||
},
|
},
|
||||||
"blockReward": "0x50",
|
"blockReward": "0x50",
|
||||||
"startStep" : 24,
|
"startStep" : 24,
|
||||||
"eip155Transition": "0x42"
|
"eip155Transition": "0x42",
|
||||||
|
"validateStepTransition": 150
|
||||||
}
|
}
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
|
@ -201,8 +201,10 @@ impl<D: Dispatcher + 'static> Signer for SignerClient<D> {
|
|||||||
Err(err) => Err(errors::invalid_params("Invalid signature received.", err)),
|
Err(err) => Err(errors::invalid_params("Invalid signature received.", err)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO [ToDr]: Decrypt - pass through?
|
ConfirmationPayload::Decrypt(_address, _data) => {
|
||||||
_ => Err(errors::unimplemented(Some("Non-transaction requests does not support RAW signing yet.".into()))),
|
// TODO [ToDr]: Decrypt can we verify if the answer is correct?
|
||||||
|
Ok(ConfirmationResponse::Decrypt(bytes))
|
||||||
|
},
|
||||||
};
|
};
|
||||||
if let Ok(ref response) = result {
|
if let Ok(ref response) = result {
|
||||||
signer.request_confirmed(id, Ok(response.clone()));
|
signer.request_confirmed(id, Ok(response.clone()));
|
||||||
|
@ -28,7 +28,7 @@ use jsonrpc_core::IoHandler;
|
|||||||
use v1::{SignerClient, Signer, Origin};
|
use v1::{SignerClient, Signer, Origin};
|
||||||
use v1::metadata::Metadata;
|
use v1::metadata::Metadata;
|
||||||
use v1::tests::helpers::TestMinerService;
|
use v1::tests::helpers::TestMinerService;
|
||||||
use v1::types::H520;
|
use v1::types::{Bytes as RpcBytes, H520};
|
||||||
use v1::helpers::{SigningQueue, SignerService, FilledTransactionRequest, ConfirmationPayload};
|
use v1::helpers::{SigningQueue, SignerService, FilledTransactionRequest, ConfirmationPayload};
|
||||||
use v1::helpers::dispatch::{FullDispatcher, eth_data_hash};
|
use v1::helpers::dispatch::{FullDispatcher, eth_data_hash};
|
||||||
|
|
||||||
@ -479,7 +479,6 @@ fn should_confirm_sign_transaction_with_rlp() {
|
|||||||
assert_eq!(tester.miner.imported_transactions.lock().len(), 0);
|
assert_eq!(tester.miner.imported_transactions.lock().len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_confirm_data_sign_with_signature() {
|
fn should_confirm_data_sign_with_signature() {
|
||||||
// given
|
// given
|
||||||
@ -510,6 +509,34 @@ fn should_confirm_data_sign_with_signature() {
|
|||||||
assert_eq!(tester.miner.imported_transactions.lock().len(), 0);
|
assert_eq!(tester.miner.imported_transactions.lock().len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_confirm_decrypt_with_phrase() {
|
||||||
|
// given
|
||||||
|
let tester = signer_tester();
|
||||||
|
let address = tester.accounts.new_account("test").unwrap();
|
||||||
|
tester.signer.add_request(ConfirmationPayload::Decrypt(
|
||||||
|
address,
|
||||||
|
vec![1, 2, 3, 4].into(),
|
||||||
|
), Origin::Unknown).unwrap();
|
||||||
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
|
|
||||||
|
let decrypted = serde_json::to_string(&RpcBytes::new(b"phrase".to_vec())).unwrap();
|
||||||
|
|
||||||
|
// when
|
||||||
|
let request = r#"{
|
||||||
|
"jsonrpc":"2.0",
|
||||||
|
"method":"signer_confirmRequestRaw",
|
||||||
|
"params":["0x1", "#.to_owned() + &decrypted + r#"],
|
||||||
|
"id":1
|
||||||
|
}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":"#.to_owned() + &decrypted + r#","id":1}"#;
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned()));
|
||||||
|
assert_eq!(tester.signer.requests().len(), 0);
|
||||||
|
assert_eq!(tester.miner.imported_transactions.lock().len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_generate_new_token() {
|
fn should_generate_new_token() {
|
||||||
// given
|
// given
|
||||||
|
Loading…
Reference in New Issue
Block a user