From acbaed59c0b7134b581f78ba235aab0a8091cb2b Mon Sep 17 00:00:00 2001 From: Jannis R Date: Thu, 10 Nov 2016 17:26:45 +0100 Subject: [PATCH 01/49] CopyToClipboard: clear timeout on unmount --- js/src/ui/CopyToClipboard/copyToClipboard.js | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/js/src/ui/CopyToClipboard/copyToClipboard.js b/js/src/ui/CopyToClipboard/copyToClipboard.js index 3351f2e40..a49da6adc 100644 --- a/js/src/ui/CopyToClipboard/copyToClipboard.js +++ b/js/src/ui/CopyToClipboard/copyToClipboard.js @@ -39,9 +39,17 @@ export default class CopyToClipboard extends Component { }; state = { - copied: false + copied: false, + timeout: null }; + componentWillUnmount () { + const { timeoutId } = this.state; + if (timeoutId) { + window.clearTimeout(timeoutId); + } + } + render () { const { data, label, size } = this.props; const { copied } = this.state; @@ -65,11 +73,12 @@ export default class CopyToClipboard extends Component { onCopy = () => { const { cooldown, onCopy } = this.props; - this.setState({ copied: true }); - setTimeout(() => { - this.setState({ copied: false }); - }, cooldown); - + this.setState({ + copied: true, + timeout: setTimeout(() => { + this.setState({ copied: false, timeout: null }); + }, cooldown) + }); onCopy(); } } From 87c39f066c373c747e848d1499551994eea35831 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Thu, 10 Nov 2016 17:27:04 +0100 Subject: [PATCH 02/49] Form/Input: use CopyToClipboard --- js/src/ui/Form/Input/input.css | 4 --- js/src/ui/Form/Input/input.js | 62 +++------------------------------- 2 files changed, 5 insertions(+), 61 deletions(-) diff --git a/js/src/ui/Form/Input/input.css b/js/src/ui/Form/Input/input.css index 62c2e39b2..bc7cfb840 100644 --- a/js/src/ui/Form/Input/input.css +++ b/js/src/ui/Form/Input/input.css @@ -24,8 +24,4 @@ .copy { margin-right: 0.5em; - - svg { - transition: all .5s ease-in-out; - } } diff --git a/js/src/ui/Form/Input/input.js b/js/src/ui/Form/Input/input.js index 24a0a8089..27c270834 100644 --- a/js/src/ui/Form/Input/input.js +++ b/js/src/ui/Form/Input/input.js @@ -15,11 +15,9 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; +import { TextField } from 'material-ui'; -import CopyToClipboard from 'react-copy-to-clipboard'; -import CopyIcon from 'material-ui/svg-icons/content/content-copy'; -import { TextField, IconButton } from 'material-ui'; -import { lightWhite, fullWhite } from 'material-ui/styles/colors'; +import CopyToClipboard from '../../CopyToClipboard'; import styles from './input.css'; @@ -77,9 +75,7 @@ export default class Input extends Component { } state = { - value: this.props.value || '', - timeoutId: null, - copied: false + value: this.props.value || '' } componentWillReceiveProps (newProps) { @@ -88,14 +84,6 @@ export default class Input extends Component { } } - componentWillUnmount () { - const { timeoutId } = this.state; - - if (timeoutId) { - window.clearTimeout(timeoutId); - } - } - render () { const { value } = this.state; const { children, className, hideUnderline, disabled, error, label, hint, multiLine, rows, type } = this.props; @@ -151,7 +139,7 @@ export default class Input extends Component { renderCopyButton () { const { allowCopy, hideUnderline, label, hint, floatCopy } = this.props; - const { copied, value } = this.state; + const { value } = this.state; if (!allowCopy) { return null; @@ -165,8 +153,6 @@ export default class Input extends Component { ? allowCopy : value; - const scale = copied ? 'scale(1.15)' : 'scale(1)'; - if (hideUnderline && !label) { style.marginBottom = 2; } else if (label && !hint) { @@ -184,49 +170,11 @@ export default class Input extends Component { return (
- - - - - +
); } - handleCopy = () => { - if (this.state.timeoutId) { - window.clearTimeout(this.state.timeoutId); - } - - this.setState({ copied: true }, () => { - const timeoutId = window.setTimeout(() => { - this.setState({ copied: false }); - }, 500); - - this.setState({ timeoutId }); - }); - } - onChange = (event, value) => { this.setValue(value); From e9b69bceab88355d459ab7d0c396ceb20848f795 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Thu, 10 Nov 2016 18:09:54 +0100 Subject: [PATCH 03/49] Account Header: use CopyToClipboard --- js/src/views/Account/Header/header.css | 4 +- js/src/views/Account/Header/header.js | 58 ++------------------------ 2 files changed, 6 insertions(+), 56 deletions(-) diff --git a/js/src/views/Account/Header/header.css b/js/src/views/Account/Header/header.css index ff3f985c3..74390face 100644 --- a/js/src/views/Account/Header/header.css +++ b/js/src/views/Account/Header/header.css @@ -43,6 +43,6 @@ } .address { - white-space: nowrap; - font-family: monospace; + display: inline-block; + margin-left: .5em; } diff --git a/js/src/views/Account/Header/header.js b/js/src/views/Account/Header/header.js index d4b01cf56..66f0a36b9 100644 --- a/js/src/views/Account/Header/header.js +++ b/js/src/views/Account/Header/header.js @@ -15,13 +15,9 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; -import CopyToClipboard from 'react-copy-to-clipboard'; -import IconButton from 'material-ui/IconButton'; -import Snackbar from 'material-ui/Snackbar'; -import CopyIcon from 'material-ui/svg-icons/content/content-copy'; -import { lightWhite, fullWhite, darkBlack } from 'material-ui/styles/colors'; import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName, Tags } from '../../../ui'; +import CopyToClipboard from '../../../ui/CopyToClipboard'; import styles from './header.css'; @@ -37,8 +33,7 @@ export default class Header extends Component { } state = { - name: null, - addressCopied: false + name: null } componentWillMount () { @@ -51,7 +46,6 @@ export default class Header extends Component { render () { const { account, balance } = this.props; - const { addressCopied } = this.state; const { address, meta, uuid } = account; if (!account) { @@ -64,50 +58,14 @@ export default class Header extends Component { return (
- - - Address - { address } - copied to clipboard - - } - autoHideDuration={ 4000 } - onRequestClose={ this.handleCopyAddressClose } - bodyStyle={ { - backgroundColor: darkBlack - } } - /> -
} />
- - - - - - { address } + +
{ address }
{ uuidText }
@@ -157,14 +115,6 @@ export default class Header extends Component { }); } - handleCopyAddress = () => { - this.setState({ addressCopied: true }); - } - - handleCopyAddressClose = () => { - this.setState({ addressCopied: false }); - } - setName () { const { account } = this.props; From 522b7108f94b44e898c3869c1d035ffc57b1b287 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Thu, 10 Nov 2016 18:47:17 +0100 Subject: [PATCH 04/49] CopyToClipboard: show SnackBar --- js/src/ui/CopyToClipboard/copyToClipboard.css | 20 +++++++++++ js/src/ui/CopyToClipboard/copyToClipboard.js | 34 +++++++++++++------ 2 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 js/src/ui/CopyToClipboard/copyToClipboard.css diff --git a/js/src/ui/CopyToClipboard/copyToClipboard.css b/js/src/ui/CopyToClipboard/copyToClipboard.css new file mode 100644 index 000000000..acf2bb204 --- /dev/null +++ b/js/src/ui/CopyToClipboard/copyToClipboard.css @@ -0,0 +1,20 @@ +/* Copyright 2015, 2016 Ethcore (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 . +*/ + +.data { + font-family: monospace; +} diff --git a/js/src/ui/CopyToClipboard/copyToClipboard.js b/js/src/ui/CopyToClipboard/copyToClipboard.js index a49da6adc..c78038617 100644 --- a/js/src/ui/CopyToClipboard/copyToClipboard.js +++ b/js/src/ui/CopyToClipboard/copyToClipboard.js @@ -16,11 +16,15 @@ import React, { Component, PropTypes } from 'react'; import { IconButton } from 'material-ui'; +import Snackbar from 'material-ui/Snackbar'; import Clipboard from 'react-copy-to-clipboard'; import CopyIcon from 'material-ui/svg-icons/content/content-copy'; import Theme from '../Theme'; +import { darkBlack } from 'material-ui/styles/colors'; const { textColor, disabledTextColor } = Theme.flatButton; +import styles from './copyToClipboard.css'; + export default class CopyToClipboard extends Component { static propTypes = { data: PropTypes.string.isRequired, @@ -56,16 +60,26 @@ export default class CopyToClipboard extends Component { return ( - - - +
+ copied { data } to clipboard
+ } + autoHideDuration={ 2000 } + bodyStyle={ { backgroundColor: darkBlack } } + /> + + + +
); } From cd143e475a615ba5591a2d35df986625976928a0 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 10 Nov 2016 20:35:47 +0100 Subject: [PATCH 05/49] WIP refacto typed input --- .../DeployContract/DetailsStep/detailsStep.js | 278 ++++++++++++++---- 1 file changed, 228 insertions(+), 50 deletions(-) diff --git a/js/src/modals/DeployContract/DetailsStep/detailsStep.js b/js/src/modals/DeployContract/DetailsStep/detailsStep.js index e0f02bc70..568d1bff1 100644 --- a/js/src/modals/DeployContract/DetailsStep/detailsStep.js +++ b/js/src/modals/DeployContract/DetailsStep/detailsStep.js @@ -16,12 +16,124 @@ import React, { Component, PropTypes } from 'react'; import { MenuItem } from 'material-ui'; +import { range } from 'lodash'; import { AddressSelect, Form, Input, InputAddressSelect, Select } from '../../../ui'; import { validateAbi } from '../../../util/validation'; import styles from '../deployContract.css'; +class TypedInput extends Component { + + static propTypes = { + onChange: PropTypes.func.isRequired, + accounts: PropTypes.object.isRequired, + type: PropTypes.string.isRequired, + + error: PropTypes.any, + value: PropTypes.any, + label: PropTypes.string + }; + + render () { + const { type } = this.props; + + const arrayRegex = /^(.+)\[(\d*)\]$/; + + if (arrayRegex.test(type)) { + const matches = arrayRegex.exec(type); + return this.renderArray(matches[1], matches[2] || Infinity); + } + + switch (type) { + case 'address': + return this.renderAddress(); + + case 'bool': + return this.renderBoolean(); + + default: + return this.renderDefault(); + } + } + + renderArray (type, max) { + const { label, value, error } = this.props; + + return ( + < + ); + } + + renderDefault () { + const { label, value, error } = this.props; + + return ( + + ); + } + + renderAddress () { + const { accounts, label, value, error } = this.props; + + return ( + + ); + } + + renderBoolean () { + const { label, value, error } = this.props; + + const boolitems = ['false', 'true'].map((bool) => { + return ( + + { bool } + + ); + }); + + return ( + + ); + } + + onChangeBool = (event, _index, value) => { + this.props.onChange(value === 'true'); + } + + onChange = (event, value) => { + this.props.onChange(value); + } + + onSubmit = (value) => { + this.props.onChange(value); + } + +} + export default class DetailsStep extends Component { static contextTypes = { api: PropTypes.object.isRequired @@ -98,59 +210,22 @@ export default class DetailsStep extends Component { } return inputs.map((input, index) => { - const onChange = (event, value) => this.onParamChange(index, value); - const onChangeBool = (event, _index, value) => this.onParamChange(index, value === 'true'); - const onSubmit = (value) => this.onParamChange(index, value); - const label = `${input.name}: ${input.type}`; - let inputBox = null; + const onChange = (value) => this.onParamChange(index, value); - switch (input.type) { - case 'address': - inputBox = ( - - ); - break; - - case 'bool': - const boolitems = ['false', 'true'].map((bool) => { - return ( - { bool } - ); - }); - inputBox = ( - - ); - break; - - default: - inputBox = ( - - ); - break; - } + const label = `${input.name ? `${input.name}: ` : ''}${input.type}`; + const value = params[index]; + const error = paramsError[index]; return (
- { inputBox } +
); }); @@ -181,7 +256,9 @@ export default class DetailsStep extends Component { const { abiError, abiParsed } = validateAbi(abi, api); if (!abiError) { - const { inputs } = abiParsed.find((method) => method.type === 'constructor') || { inputs: [] }; + const { inputs } = abiParsed + .find((method) => method.type === 'constructor') || { inputs: [] }; + const params = []; inputs.forEach((input) => { @@ -228,3 +305,104 @@ export default class DetailsStep extends Component { onCodeChange(code); } } + +const ARRAY_TYPE = 'ARRAY_TYPE'; +const ADDRESS_TYPE = 'ADDRESS_TYPE'; +const STRING_TYPE = 'STRING_TYPE'; +const BOOL_TYPE = 'BOOL_TYPE'; +const BYTES_TYPE = 'BYTES_TYPE'; +const UINT_TYPE = 'UINT_TYPE'; +const INT_TYPE = 'INT_TYPE'; + +function parseAbiType (type) { + if (type === 'string') { + return { + type: STRING_TYPE, + default: '' + }; + } + + if (type === 'bool') { + return { + type: BOOL_TYPE, + default: false + }; + } + + if (type === 'address') { + return { + type: ADDRESS_TYPE, + default: '0x' + }; + } + + const arrayRegex = /^(.+)\[(\d*)\]$/; + + if (arrayRegex.test(type)) { + const matches = arrayRegex.exec(type); + + const subtype = parseAbiType(matches[1]); + const M = parseInt(matches[2]) || Infinity; + const defaultValue = M === Infinity + ? [] + : range(M).map(() => subtype.default); + + return { + type: ARRAY_TYPE, + subtype: subtype, + length: M, + default: defaultValue + }; + } + + const lengthRegex = /^([a-z]+)(\d{1,3})$/; + + if (lengthRegex.test(type)) { + const subtype = parseAbiType(matches[1]); + const length = parseInt(matches[2]) || Infinity; + + return { + ...subtype, + length + }; + } + + if (type === 'bytes') { + return { + type: BYTES_TYPE, + default: '0x' + }; + } + + if (type === 'uint') { + return { + type: UINT_TYPE, + default: 0, + length: 256 + }; + } + + if (type === 'int') { + return { + type: INT_TYPE, + default: 0, + length: 256 + }; + } + + if (type === 'ufixed') { + return { + type: UFIXED_TYPE, + default: 0, + length: 256 + }; + } + + if (type === 'fixed') { + return { + type: FIXED_TYPE, + default: 0, + length: 256 + }; + } +} From b59df1d7b83523094c498dd09141291c942f8c4f Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Fri, 11 Nov 2016 12:37:01 +0100 Subject: [PATCH 06/49] WIP // Real ABI params in Deploy Constructor #3314 --- .../DeployContract/DetailsStep/detailsStep.js | 217 +++++++++++------- .../modals/DeployContract/deployContract.css | 14 ++ js/src/ui/Form/Input/input.js | 8 +- 3 files changed, 154 insertions(+), 85 deletions(-) diff --git a/js/src/modals/DeployContract/DetailsStep/detailsStep.js b/js/src/modals/DeployContract/DetailsStep/detailsStep.js index 568d1bff1..51d2318c8 100644 --- a/js/src/modals/DeployContract/DetailsStep/detailsStep.js +++ b/js/src/modals/DeployContract/DetailsStep/detailsStep.js @@ -28,7 +28,7 @@ class TypedInput extends Component { static propTypes = { onChange: PropTypes.func.isRequired, accounts: PropTypes.object.isRequired, - type: PropTypes.string.isRequired, + param: PropTypes.object.isRequired, error: PropTypes.any, value: PropTypes.any, @@ -36,32 +36,84 @@ class TypedInput extends Component { }; render () { - const { type } = this.props; + const { param } = this.props; + const { type } = param; - const arrayRegex = /^(.+)\[(\d*)\]$/; + if (type === ARRAY_TYPE) { + const { accounts, label, value = param.default } = this.props; + const { subtype, length } = param; - if (arrayRegex.test(type)) { - const matches = arrayRegex.exec(type); - return this.renderArray(matches[1], matches[2] || Infinity); + if (length) { + const inputs = range(length).map((_, index) => { + const onChange = (inputValue) => { + const newValues = [].concat(this.props.value); + newValues[index] = inputValue; + this.props.onChange(newValues); + }; + + return ( + + ); + }); + + return ( +
+ + { inputs } +
+ ); + } } - switch (type) { - case 'address': - return this.renderAddress(); - - case 'bool': - return this.renderBoolean(); - - default: - return this.renderDefault(); - } + return this.renderType(type); } - renderArray (type, max) { - const { label, value, error } = this.props; + renderType (type) { + if (type === ADDRESS_TYPE) { + return this.renderAddress(); + } + + if (type === BOOL_TYPE) { + return this.renderBoolean(); + } + + if (type === STRING_TYPE) { + return this.renderDefault(); + } + + if (type === BYTES_TYPE) { + return this.renderDefault(); + } + + if (type === INT_TYPE) { + return this.renderNumber(); + } + + if (type === FIXED_TYPE) { + return this.renderNumber(); + } + + return this.renderDefault(); + } + + renderNumber () { + const { label, value, error, param } = this.props; return ( - < + ); } @@ -215,6 +267,7 @@ export default class DetailsStep extends Component { const label = `${input.name ? `${input.name}: ` : ''}${input.type}`; const value = params[index]; const error = paramsError[index]; + const param = parseAbiType(input.type) return (
@@ -224,7 +277,7 @@ export default class DetailsStep extends Component { error={ error } accounts={ accounts } onChange={ onChange } - type={ input.type } + param={ param } />
); @@ -262,31 +315,8 @@ export default class DetailsStep extends Component { const params = []; inputs.forEach((input) => { - switch (input.type) { - case 'address': - params.push('0x'); - break; - - case 'bool': - params.push(false); - break; - - case 'bytes': - params.push('0x'); - break; - - case 'uint': - params.push('0'); - break; - - case 'string': - params.push(''); - break; - - default: - params.push('0'); - break; - } + const param = parseAbiType(input.type); + params.push(param.default); }); onParamsChange(params); @@ -311,10 +341,58 @@ const ADDRESS_TYPE = 'ADDRESS_TYPE'; const STRING_TYPE = 'STRING_TYPE'; const BOOL_TYPE = 'BOOL_TYPE'; const BYTES_TYPE = 'BYTES_TYPE'; -const UINT_TYPE = 'UINT_TYPE'; const INT_TYPE = 'INT_TYPE'; +const FIXED_TYPE = 'FIXED_TYPE'; function parseAbiType (type) { + const arrayRegex = /^(.+)\[(\d*)\]$/; + + if (arrayRegex.test(type)) { + const matches = arrayRegex.exec(type); + + const subtype = parseAbiType(matches[1]); + const M = parseInt(matches[2]) || null; + const defaultValue = !M + ? [] + : range(M).map(() => subtype.default); + + return { + type: ARRAY_TYPE, + subtype: subtype, + length: M, + default: defaultValue + }; + } + + const lengthRegex = /^(u?int|bytes)(\d{1,3})$/; + + if (lengthRegex.test(type)) { + const matches = lengthRegex.exec(type); + + const subtype = parseAbiType(matches[1]); + const length = parseInt(matches[2]); + + return { + ...subtype, + length + }; + } + + const fixedLengthRegex = /^(u?fixed)(\d{1,3})x(\d{1,3})$/; + + if (fixedLengthRegex.test(type)) { + const matches = fixedLengthRegex.exec(type); + + const subtype = parseAbiType(matches[1]); + const M = parseInt(matches[2]); + const N = parseInt(matches[3]); + + return { + ...subtype, + M, N + }; + } + if (type === 'string') { return { type: STRING_TYPE, @@ -336,37 +414,6 @@ function parseAbiType (type) { }; } - const arrayRegex = /^(.+)\[(\d*)\]$/; - - if (arrayRegex.test(type)) { - const matches = arrayRegex.exec(type); - - const subtype = parseAbiType(matches[1]); - const M = parseInt(matches[2]) || Infinity; - const defaultValue = M === Infinity - ? [] - : range(M).map(() => subtype.default); - - return { - type: ARRAY_TYPE, - subtype: subtype, - length: M, - default: defaultValue - }; - } - - const lengthRegex = /^([a-z]+)(\d{1,3})$/; - - if (lengthRegex.test(type)) { - const subtype = parseAbiType(matches[1]); - const length = parseInt(matches[2]) || Infinity; - - return { - ...subtype, - length - }; - } - if (type === 'bytes') { return { type: BYTES_TYPE, @@ -376,9 +423,10 @@ function parseAbiType (type) { if (type === 'uint') { return { - type: UINT_TYPE, + type: INT_TYPE, default: 0, - length: 256 + length: 256, + signed: false }; } @@ -386,15 +434,17 @@ function parseAbiType (type) { return { type: INT_TYPE, default: 0, - length: 256 + length: 256, + signed: true }; } if (type === 'ufixed') { return { - type: UFIXED_TYPE, + type: FIXED_TYPE, default: 0, - length: 256 + length: 256, + signed: false }; } @@ -402,7 +452,8 @@ function parseAbiType (type) { return { type: FIXED_TYPE, default: 0, - length: 256 + length: 256, + signed: true }; } } diff --git a/js/src/modals/DeployContract/deployContract.css b/js/src/modals/DeployContract/deployContract.css index 45fd7a852..b8ce35b8a 100644 --- a/js/src/modals/DeployContract/deployContract.css +++ b/js/src/modals/DeployContract/deployContract.css @@ -31,3 +31,17 @@ .funcparams { padding-left: 3em; } + +.inputs { + padding-top: 18px; + + label { + line-height: 22px; + pointer-events: none; + color: rgba(255, 255, 255, 0.498039); + -webkit-user-select: none; + font-size: 12px; + top: 8px; + position: relative; + } +} diff --git a/js/src/ui/Form/Input/input.js b/js/src/ui/Form/Input/input.js index 24a0a8089..bc7c60f1e 100644 --- a/js/src/ui/Form/Input/input.js +++ b/js/src/ui/Form/Input/input.js @@ -65,7 +65,9 @@ export default class Input extends Component { hideUnderline: PropTypes.bool, value: PropTypes.oneOfType([ PropTypes.number, PropTypes.string - ]) + ]), + min: PropTypes.any, + max: PropTypes.any }; static defaultProps = { @@ -98,7 +100,7 @@ export default class Input extends Component { render () { const { value } = this.state; - const { children, className, hideUnderline, disabled, error, label, hint, multiLine, rows, type } = this.props; + const { children, className, hideUnderline, disabled, error, label, hint, multiLine, rows, type, min, max } = this.props; const readOnly = this.props.readOnly || disabled; @@ -142,6 +144,8 @@ export default class Input extends Component { onChange={ this.onChange } onKeyDown={ this.onKeyDown } inputStyle={ inputStyle } + min={ min } + max={ max } > { children } From deaf863c9ef710de639c7810c8b1acb8cedffb1f Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Fri, 11 Nov 2016 12:41:44 +0100 Subject: [PATCH 07/49] Fixing linting --- js/src/modals/DeployContract/DetailsStep/detailsStep.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/modals/DeployContract/DetailsStep/detailsStep.js b/js/src/modals/DeployContract/DetailsStep/detailsStep.js index 51d2318c8..c04a505bf 100644 --- a/js/src/modals/DeployContract/DetailsStep/detailsStep.js +++ b/js/src/modals/DeployContract/DetailsStep/detailsStep.js @@ -267,7 +267,7 @@ export default class DetailsStep extends Component { const label = `${input.name ? `${input.name}: ` : ''}${input.type}`; const value = params[index]; const error = paramsError[index]; - const param = parseAbiType(input.type) + const param = parseAbiType(input.type); return (
From 046d2f23337606272b8336b570e1d06437256d67 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Fri, 11 Nov 2016 13:09:16 +0100 Subject: [PATCH 08/49] Scrollable --- js/src/modals/DeployContract/deployContract.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/modals/DeployContract/deployContract.js b/js/src/modals/DeployContract/deployContract.js index 588d16f6a..3bcea7c29 100644 --- a/js/src/modals/DeployContract/deployContract.js +++ b/js/src/modals/DeployContract/deployContract.js @@ -67,7 +67,8 @@ export default class DeployContract extends Component { steps={ deployError ? null : steps } title={ deployError ? 'deployment failed' : null } waiting={ [1] } - visible> + visible + scroll> { this.renderStep() } ); From ed135bb9dc5638a3e33ed4d1961b7cb5ce6afa51 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 11 Nov 2016 17:18:31 +0100 Subject: [PATCH 09/49] fetch known code from the database during restoration previously it kept all seen code in memory, leading to high memory usage by the end of state restoration --- ethcore/src/snapshot/account.rs | 20 +++++--------- ethcore/src/snapshot/mod.rs | 47 +++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index 38a4028e1..4db023017 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -19,11 +19,11 @@ use account_db::{AccountDB, AccountDBMut}; use snapshot::Error; -use util::{U256, FixedHash, H256, Bytes, HashDB, DBValue, SHA3_EMPTY, SHA3_NULL_RLP}; +use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY, SHA3_NULL_RLP}; use util::trie::{TrieDB, Trie}; use rlp::{Rlp, RlpStream, Stream, UntrustedRlp, View}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; // An empty account -- these are replaced with RLP null data for a space optimization. const ACC_EMPTY: Account = Account { @@ -150,7 +150,6 @@ impl Account { pub fn from_fat_rlp( acct_db: &mut AccountDBMut, rlp: UntrustedRlp, - code_map: &HashMap, ) -> Result<(Self, Option), Error> { use util::{TrieDBMut, TrieMut}; @@ -177,9 +176,6 @@ impl Account { } CodeState::Hash => { let code_hash = try!(rlp.val_at(3)); - if let Some(code) = code_map.get(&code_hash) { - acct_db.emplace(code_hash.clone(), DBValue::from_slice(code)); - } (code_hash, None) } @@ -250,7 +246,7 @@ mod tests { let fat_rlp = account.to_fat_rlp(&AccountDB::new(db.as_hashdb(), &addr), &mut Default::default()).unwrap(); let fat_rlp = UntrustedRlp::new(&fat_rlp); - assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, &Default::default()).unwrap().0, account); + assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp).unwrap().0, account); } #[test] @@ -275,7 +271,7 @@ mod tests { let fat_rlp = account.to_fat_rlp(&AccountDB::new(db.as_hashdb(), &addr), &mut Default::default()).unwrap(); let fat_rlp = UntrustedRlp::new(&fat_rlp); - assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, &Default::default()).unwrap().0, account); + assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp).unwrap().0, account); } #[test] @@ -318,12 +314,11 @@ mod tests { let fat_rlp1 = UntrustedRlp::new(&fat_rlp1); let fat_rlp2 = UntrustedRlp::new(&fat_rlp2); - let code_map = HashMap::new(); - let (acc, maybe_code) = Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2, &code_map).unwrap(); + let (acc, maybe_code) = Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2).unwrap(); assert!(maybe_code.is_none()); assert_eq!(acc, account2); - let (acc, maybe_code) = Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr1), fat_rlp1, &code_map).unwrap(); + let (acc, maybe_code) = Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr1), fat_rlp1).unwrap(); assert_eq!(maybe_code, Some(b"this is definitely code".to_vec())); assert_eq!(acc, account1); } @@ -332,9 +327,8 @@ mod tests { fn encoding_empty_acc() { let mut db = get_temp_state_db(); let mut used_code = HashSet::new(); - let code_map = HashMap::new(); assert_eq!(ACC_EMPTY.to_fat_rlp(&AccountDB::new(db.as_hashdb(), &Address::default()), &mut used_code).unwrap(), ::rlp::NULL_RLP.to_vec()); - assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP), &code_map).unwrap(), (ACC_EMPTY, None)); + assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP)).unwrap(), (ACC_EMPTY, None)); } } diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 22c44ba3b..325ce94a8 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -389,7 +389,7 @@ pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex, state_root: H256, - code_map: HashMap, // maps code hashes to code itself. + known_code: HashMap, // code hashes mapped to first account with this code. missing_code: HashMap>, // maps code hashes to lists of accounts missing that code. bloom: Bloom, } @@ -400,7 +400,7 @@ impl StateRebuilder { StateRebuilder { db: journaldb::new(db.clone(), pruning, ::db::COL_STATE), state_root: SHA3_NULL_RLP, - code_map: HashMap::new(), + known_code: HashMap::new(), missing_code: HashMap::new(), bloom: StateDB::load_bloom(&*db), } @@ -419,24 +419,26 @@ impl StateRebuilder { let chunk_size = account_fat_rlps.len() / ::num_cpus::get() + 1; // new code contained within this chunk. - let mut chunk_code = HashMap::new(); + let mut chunk_code = Vec::new(); for (account_chunk, out_pairs_chunk) in account_fat_rlps.chunks(chunk_size).zip(pairs.chunks_mut(chunk_size)) { - let code_map = &self.code_map; - let status = try!(rebuild_accounts(self.db.as_hashdb_mut(), account_chunk, out_pairs_chunk, code_map)); + let status = try!(rebuild_accounts(self.db.as_hashdb_mut(), account_chunk, out_pairs_chunk, &self.known_code)); chunk_code.extend(status.new_code); + + // update missing code. for (addr_hash, code_hash) in status.missing_code { self.missing_code.entry(code_hash).or_insert_with(Vec::new).push(addr_hash); } } + // patch up all missing code. must be done after collecting all new missing code entries. - for (code_hash, code) in chunk_code { + for (code_hash, code, first_with) in chunk_code { for addr_hash in self.missing_code.remove(&code_hash).unwrap_or_else(Vec::new) { let mut db = AccountDBMut::from_hash(self.db.as_hashdb_mut(), addr_hash); db.emplace(code_hash, DBValue::from_slice(&code)); } - self.code_map.insert(code_hash, code); + self.known_code.insert(code_hash, first_with); } let backing = self.db.backing().clone(); @@ -482,7 +484,8 @@ impl StateRebuilder { #[derive(Default)] struct RebuiltStatus { - new_code: Vec<(H256, Bytes)>, // new code that's become available. + // new code that's become available. (code_hash, code, addr_hash) + new_code: Vec<(H256, Bytes, H256)>, missing_code: Vec<(H256, H256)>, // accounts that are missing code. } @@ -492,7 +495,7 @@ fn rebuild_accounts( db: &mut HashDB, account_chunk: &[&[u8]], out_chunk: &mut [(H256, Bytes)], - code_map: &HashMap + known_code: &HashMap, ) -> Result { let mut status = RebuiltStatus::default(); @@ -503,17 +506,33 @@ fn rebuild_accounts( let fat_rlp = try!(account_rlp.at(1)); let thin_rlp = { - let mut acct_db = AccountDBMut::from_hash(db, hash); // fill out the storage trie and code while decoding. - let (acc, maybe_code) = try!(Account::from_fat_rlp(&mut acct_db, fat_rlp, code_map)); + let (acc, maybe_code) = { + let mut acct_db = AccountDBMut::from_hash(db, hash); + try!(Account::from_fat_rlp(&mut acct_db, fat_rlp)) + }; let code_hash = acc.code_hash().clone(); match maybe_code { - Some(code) => status.new_code.push((code_hash, code)), + // new inline code + Some(code) => status.new_code.push((code_hash, code, hash)), None => { - if code_hash != ::util::SHA3_EMPTY && !code_map.contains_key(&code_hash) { - status.missing_code.push((hash, code_hash)); + if code_hash != ::util::SHA3_EMPTY { + // see if this code has already been included inline + match known_code.get(&code_hash) { + Some(&first_with) => { + // if so, load it from the database. + let code = try!(AccountDB::from_hash(db, first_with) + .get(&code_hash) + .ok_or_else(|| Error::MissingCode(vec![first_with]))); + + // and write it again under a different mangled key + AccountDBMut::from_hash(db, hash).emplace(code_hash, code); + } + // if not, queue it up to be filled later + None => status.missing_code.push((hash, code_hash)), + } } } } From a7ad75d851a82e224a8050db2faa1ff0f2643837 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Nov 2016 17:32:54 +0100 Subject: [PATCH 10/49] whitespace [ci:skip] --- ethcore/src/snapshot/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 325ce94a8..9cdbff433 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -496,8 +496,7 @@ fn rebuild_accounts( account_chunk: &[&[u8]], out_chunk: &mut [(H256, Bytes)], known_code: &HashMap, -) -> Result -{ +) -> Result { let mut status = RebuiltStatus::default(); for (account_pair, out) in account_chunk.into_iter().zip(out_chunk) { let account_rlp = UntrustedRlp::new(account_pair); From a719b91b635b1a419f78352eb50b57e34d349136 Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 11 Nov 2016 16:37:44 +0000 Subject: [PATCH 11/49] move spec constructors to spec --- ethcore/res/{ethereum => }/expanse.json | 0 ethcore/src/ethereum/ethash.rs | 38 +++++++++--------- ethcore/src/ethereum/mod.rs | 47 ++--------------------- ethcore/src/miner/mod.rs | 4 +- ethcore/src/spec/spec.rs | 51 ++++++++++++++++++++----- ethcore/src/tests/client.rs | 3 +- ethcore/src/tests/helpers.rs | 3 +- 7 files changed, 69 insertions(+), 77 deletions(-) rename ethcore/res/{ethereum => }/expanse.json (100%) diff --git a/ethcore/res/ethereum/expanse.json b/ethcore/res/expanse.json similarity index 100% rename from ethcore/res/ethereum/expanse.json rename to ethcore/res/expanse.json diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 6436e3531..2c7187b09 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -423,13 +423,13 @@ mod tests { use env_info::EnvInfo; use error::{BlockError, Error}; use header::Header; - use super::super::{new_morden, new_homestead_test}; + use spec::Spec; use super::{Ethash, EthashParams}; use rlp; #[test] fn on_close_block() { - let spec = new_morden(); + let spec = Spec::new_ethereum_morden(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); @@ -443,7 +443,7 @@ mod tests { #[test] fn on_close_block_with_uncle() { - let spec = new_morden(); + let spec = Spec::new_ethereum_morden(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); @@ -463,14 +463,14 @@ mod tests { #[test] fn has_valid_metadata() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; assert!(!engine.name().is_empty()); assert!(engine.version().major >= 1); } #[test] fn can_return_schedule() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; let schedule = engine.schedule(&EnvInfo { number: 10000000, author: 0.into(), @@ -498,8 +498,8 @@ mod tests { #[test] fn can_do_seal_verification_fail() { - let engine = new_morden().engine; - //let engine = Ethash::new_test(new_morden()); + let engine = Spec::new_ethereum_morden().engine; + //let engine = Ethash::new_test(Spec::new_ethereum_morden()); let header: Header = Header::default(); let verify_result = engine.verify_block_basic(&header, None); @@ -513,7 +513,7 @@ mod tests { #[test] fn can_do_difficulty_verification_fail() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; let mut header: Header = Header::default(); header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); @@ -528,7 +528,7 @@ mod tests { #[test] fn can_do_proof_of_work_verification_fail() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; let mut header: Header = Header::default(); header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap()); @@ -544,7 +544,7 @@ mod tests { #[test] fn can_do_seal_unordered_verification_fail() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; let header: Header = Header::default(); let verify_result = engine.verify_block_unordered(&header, None); @@ -558,7 +558,7 @@ mod tests { #[test] fn can_do_seal256_verification_fail() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; let mut header: Header = Header::default(); header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); let verify_result = engine.verify_block_unordered(&header, None); @@ -572,7 +572,7 @@ mod tests { #[test] fn can_do_proof_of_work_unordered_verification_fail() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; let mut header: Header = Header::default(); header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).to_vec(), rlp::encode(&H64::zero()).to_vec()]); header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap()); @@ -588,7 +588,7 @@ mod tests { #[test] fn can_verify_block_family_genesis_fail() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; let header: Header = Header::default(); let parent_header: Header = Header::default(); @@ -603,7 +603,7 @@ mod tests { #[test] fn can_verify_block_family_difficulty_fail() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; let mut header: Header = Header::default(); header.set_number(2); let mut parent_header: Header = Header::default(); @@ -620,7 +620,7 @@ mod tests { #[test] fn can_verify_block_family_gas_fail() { - let engine = new_morden().engine; + let engine = Spec::new_ethereum_morden().engine; let mut header: Header = Header::default(); header.set_number(2); header.set_difficulty(U256::from_str("0000000000000000000000000000000000000000000000000000000000020000").unwrap()); @@ -648,7 +648,7 @@ mod tests { #[test] fn difficulty_frontier() { - let spec = new_homestead_test(); + let spec = Spec::new_ethereum_homestead_test(); let ethparams = get_default_ethash_params(); let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); @@ -666,7 +666,7 @@ mod tests { #[test] fn difficulty_homestead() { - let spec = new_homestead_test(); + let spec = Spec::new_ethereum_homestead_test(); let ethparams = get_default_ethash_params(); let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); @@ -684,7 +684,7 @@ mod tests { #[test] fn difficulty_classic_bomb_delay() { - let spec = new_homestead_test(); + let spec = Spec::new_ethereum_homestead_test(); let ethparams = EthashParams { ecip1010_pause_transition: 3000000, ..get_default_ethash_params() @@ -717,7 +717,7 @@ mod tests { #[test] fn test_difficulty_bomb_continue() { - let spec = new_homestead_test(); + let spec = Spec::new_ethereum_homestead_test(); let ethparams = EthashParams { ecip1010_pause_transition: 3000000, ecip1010_continue_transition: 5000000, diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 253a12372..3df130a8d 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -27,56 +27,17 @@ pub mod denominations; pub use self::ethash::{Ethash}; pub use self::denominations::*; -use super::spec::*; - -fn load(b: &[u8]) -> Spec { - Spec::load(b).expect("chain spec is invalid") -} - -/// Create a new Olympic chain spec. -pub fn new_olympic() -> Spec { load(include_bytes!("../../res/ethereum/olympic.json")) } - -/// Create a new Frontier mainnet chain spec. -pub fn new_frontier() -> Spec { load(include_bytes!("../../res/ethereum/frontier.json")) } - -/// Create a new Frontier mainnet chain spec without the DAO hardfork. -pub fn new_classic() -> Spec { load(include_bytes!("../../res/ethereum/classic.json")) } - -/// Create a new Frontier mainnet chain spec without the DAO hardfork. -pub fn new_expanse() -> Spec { load(include_bytes!("../../res/ethereum/expanse.json")) } - -/// Create a new Frontier chain spec as though it never changes to Homestead. -pub fn new_frontier_test() -> Spec { load(include_bytes!("../../res/ethereum/frontier_test.json")) } - -/// Create a new Homestead chain spec as though it never changed from Frontier. -pub fn new_homestead_test() -> Spec { load(include_bytes!("../../res/ethereum/homestead_test.json")) } - -/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. -pub fn new_eip150_test() -> Spec { load(include_bytes!("../../res/ethereum/eip150_test.json")) } - -/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. -pub fn new_eip161_test() -> Spec { load(include_bytes!("../../res/ethereum/eip161_test.json")) } - -/// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8. -pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/transition_test.json")) } - -/// Create a new Frontier main net chain spec without genesis accounts. -pub fn new_mainnet_like() -> Spec { load(include_bytes!("../../res/ethereum/frontier_like_test.json")) } - -/// Create a new Morden chain spec. -pub fn new_morden() -> Spec { load(include_bytes!("../../res/ethereum/morden.json")) } - #[cfg(test)] mod tests { use util::*; use state::*; - use super::*; use tests::helpers::*; + use spec::Spec; use views::BlockView; #[test] fn ensure_db_good() { - let spec = new_morden(); + let spec = Spec::new_ethereum_morden(); let engine = &spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); @@ -93,7 +54,7 @@ mod tests { #[test] fn morden() { - let morden = new_morden(); + let morden = Spec::new_ethereum_morden(); assert_eq!(morden.state_root(), "f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9".into()); let genesis = morden.genesis_block(); @@ -104,7 +65,7 @@ mod tests { #[test] fn frontier() { - let frontier = new_frontier(); + let frontier = Spec::new_ethereum_frontier(); assert_eq!(frontier.state_root(), "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".into()); let genesis = frontier.genesis_block(); diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index da93dc0b7..a553daffc 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -27,12 +27,12 @@ //! extern crate ethcore_util as util; //! extern crate ethcore; //! use std::env; -//! use ethcore::ethereum; +//! use spec::Spec; //! use ethcore::client::{Client, ClientConfig}; //! use ethcore::miner::{Miner, MinerService}; //! //! fn main() { -//! let miner: Miner = Miner::with_spec(ðereum::new_frontier()); +//! let miner: Miner = Miner::with_spec(&Spec::new_ethereum_frontier()); //! // get status //! assert_eq!(miner.status().transactions_in_pending_queue, 0); //! diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 2babfb708..786b264ab 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -135,6 +135,12 @@ impl From for Spec { } } +macro_rules! load_bundled { + ($e:expr) => { + Spec::load(include_bytes!(concat!("../../res/", $e, ".json")) as &[u8]).expect("Chain spec is invalid") + }; +} + impl Spec { /// Convert engine spec into a arc'd Engine of the right underlying type. /// TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead. @@ -267,19 +273,46 @@ impl Spec { } /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus. - pub fn new_test() -> Self { - Spec::load(include_bytes!("../../res/null_morden.json") as &[u8]).expect("null_morden.json is invalid") - } + pub fn new_test() -> Spec { load_bundled!("null_morden") } /// Create a new Spec which is a NullEngine consensus with a premine of address whose secret is sha3(''). - pub fn new_null() -> Self { - Spec::load(include_bytes!("../../res/null.json") as &[u8]).expect("null.json is invalid") - } + pub fn new_null() -> Spec { load_bundled!("null") } /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring work). - pub fn new_test_instant() -> Self { - Spec::load(include_bytes!("../../res/instant_seal.json") as &[u8]).expect("instant_seal.json is invalid") - } + pub fn new_test_instant() -> Spec { load_bundled!("instant_seal") } + + /// Create a new Olympic chain spec. + pub fn new_ethereum_olympic() -> Spec { load_bundled!("ethereum/olympic") } + + /// Create a new Frontier mainnet chain spec. + pub fn new_ethereum_frontier() -> Spec { load_bundled!("ethereum/frontier") } + + /// Create a new Frontier mainnet chain spec without the DAO hardfork. + pub fn new_ethereum_classic() -> Spec { load_bundled!("ethereum/classic") } + + /// Create a new Frontier mainnet chain spec without the DAO hardfork. + pub fn new_expanse() -> Spec { load_bundled!("expanse") } + + /// Create a new Frontier chain spec as though it never changes to Homestead. + pub fn new_ethereum_frontier_test() -> Spec { load_bundled!("ethereum/frontier_test") } + + /// Create a new Homestead chain spec as though it never changed from Frontier. + pub fn new_ethereum_homestead_test() -> Spec { load_bundled!("ethereum/homestead_test") } + + /// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. + pub fn new_ethereum_eip150_test() -> Spec { load_bundled!("ethereum/eip150_test") } + + /// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. + pub fn new_ethereum_eip161_test() -> Spec { load_bundled!("ethereum/eip161_test") } + + /// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8. + pub fn new_ethereum_transition_test() -> Spec { load_bundled!("ethereum/transition_test") } + + /// Create a new Frontier main net chain spec without genesis accounts. + pub fn new_ethereum_mainnet_like() -> Spec { load_bundled!("ethereum/frontier_like_test") } + + /// Create a new Morden chain spec. + pub fn new_ethereum_morden() -> Spec { load_bundled!("ethereum/morden") } } #[cfg(test)] diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 99b251d66..e6fba0b0a 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -17,7 +17,6 @@ use io::IoChannel; use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockID}; use state::CleanupMode; -use ethereum; use block::IsBlock; use tests::helpers::*; use types::filter::Filter; @@ -50,7 +49,7 @@ fn imports_from_empty() { #[test] fn should_return_registrar() { let dir = RandomTempPath::new(); - let spec = ethereum::new_morden(); + let spec = Spec::new_ethereum_morden(); let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); let client = Client::new( diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 96d5f8366..a6a06608a 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -27,7 +27,6 @@ use state::*; use evm::Schedule; use engines::Engine; use env_info::EnvInfo; -use ethereum; use ethereum::ethash::EthashParams; use devtools::*; use miner::Miner; @@ -53,7 +52,7 @@ pub struct TestEngine { impl TestEngine { pub fn new(max_depth: usize) -> TestEngine { TestEngine { - engine: ethereum::new_frontier_test().engine, + engine: Spec::new_ethereum_frontier_test().engine, max_depth: max_depth, } } From beaa014543dc7f8010a45634d1ea479e4e7e1c66 Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 11 Nov 2016 16:59:22 +0000 Subject: [PATCH 12/49] tix doc test --- ethcore/src/miner/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index a553daffc..fc306c3de 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -27,7 +27,7 @@ //! extern crate ethcore_util as util; //! extern crate ethcore; //! use std::env; -//! use spec::Spec; +//! use ethcore::spec::Spec; //! use ethcore::client::{Client, ClientConfig}; //! use ethcore::miner::{Miner, MinerService}; //! From 225d0b02e7d82925450dee260d720b71789582e7 Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 11 Nov 2016 17:10:47 +0000 Subject: [PATCH 13/49] update parity module --- parity/params.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/parity/params.rs b/parity/params.rs index 5a81fba7f..783c4564a 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -19,7 +19,6 @@ use std::time::Duration; use util::{Address, U256, version_data}; use util::journaldb::Algorithm; use ethcore::spec::Spec; -use ethcore::ethereum; use ethcore::client::Mode; use ethcore::miner::{GasPricer, GasPriceCalibratorOptions}; use user_defaults::UserDefaults; @@ -59,11 +58,11 @@ impl str::FromStr for SpecType { impl SpecType { pub fn spec(&self) -> Result { match *self { - SpecType::Mainnet => Ok(ethereum::new_frontier()), - SpecType::Testnet => Ok(ethereum::new_morden()), - SpecType::Olympic => Ok(ethereum::new_olympic()), - SpecType::Classic => Ok(ethereum::new_classic()), - SpecType::Expanse => Ok(ethereum::new_expanse()), + SpecType::Mainnet => Ok(Spec::new_ethereum_frontier()), + SpecType::Testnet => Ok(Spec::new_ethereum_morden()), + SpecType::Olympic => Ok(Spec::new_ethereum_olympic()), + SpecType::Classic => Ok(Spec::new_ethereum_classic()), + SpecType::Expanse => Ok(Spec::new_expanse()), SpecType::Custom(ref filename) => { let file = try!(fs::File::open(filename).map_err(|_| "Could not load specification file.")); Spec::load(file) From 87c668ba9cbdc7521a98f4df72a58f525970a242 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 11 Nov 2016 18:24:12 +0100 Subject: [PATCH 14/49] test previous code fetch --- ethcore/src/snapshot/account.rs | 2 +- ethcore/src/snapshot/tests/state.rs | 54 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index 4db023017..327979ce3 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -225,7 +225,7 @@ mod tests { use util::{Address, FixedHash, H256, HashDB, DBValue}; use rlp::{UntrustedRlp, View}; - use std::collections::{HashSet, HashMap}; + use std::collections::HashSet; use super::{ACC_EMPTY, Account}; diff --git a/ethcore/src/snapshot/tests/state.rs b/ethcore/src/snapshot/tests/state.rs index e1d4df5f9..5257903d5 100644 --- a/ethcore/src/snapshot/tests/state.rs +++ b/ethcore/src/snapshot/tests/state.rs @@ -17,6 +17,7 @@ //! State snapshotting tests. use snapshot::{chunk_state, Progress, StateRebuilder}; +use snapshot::account::Account; use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter}; use super::helpers::{compare_dbs, StateProducer}; @@ -28,6 +29,8 @@ use util::memorydb::MemoryDB; use util::Mutex; use devtools::RandomTempPath; +use util::sha3::SHA3_NULL_RLP; + use std::sync::Arc; #[test] @@ -82,3 +85,54 @@ fn snap_and_restore() { compare_dbs(&old_db, new_db.as_hashdb()); } + +#[test] +fn get_code_from_prev_chunk() { + use std::collections::HashSet; + use rlp::{RlpStream, Stream}; + use util::{HashDB, H256, FixedHash, U256, Hashable}; + + use account_db::{AccountDBMut, AccountDB}; + + let code = b"this is definitely code"; + let mut used_code = HashSet::new(); + let mut acc_stream = RlpStream::new_list(4); + acc_stream.append(&U256::default()) + .append(&U256::default()) + .append(&SHA3_NULL_RLP) + .append(&code.sha3()); + + let (h1, h2) = (H256::random(), H256::random()); + + // two accounts with the same code, one per chunk. + // first one will have code inlined, + // second will just have its hash. + let thin_rlp = acc_stream.out(); + let acc1 = Account::from_thin_rlp(&thin_rlp); + let acc2 = Account::from_thin_rlp(&thin_rlp); + + let mut make_chunk = |acc: Account, hash| { + let mut db = MemoryDB::new(); + AccountDBMut::from_hash(&mut db, hash).insert(&code[..]); + + let fat_rlp = acc.to_fat_rlp(&AccountDB::from_hash(&db, hash), &mut used_code).unwrap(); + + let mut stream = RlpStream::new_list(1); + stream.begin_list(2).append(&hash).append_raw(&fat_rlp, 1); + stream.out() + }; + + let chunk1 = make_chunk(acc1, h1); + let chunk2 = make_chunk(acc2, h2); + + let db_path = RandomTempPath::create_dir(); + let db_cfg = DatabaseConfig::with_columns(::db::NUM_COLUMNS); + let new_db = Arc::new(Database::open(&db_cfg, &db_path.to_string_lossy()).unwrap()); + + let mut rebuilder = StateRebuilder::new(new_db, Algorithm::Archive); + + rebuilder.feed(&chunk1).unwrap(); + rebuilder.feed(&chunk2).unwrap(); + + rebuilder.check_missing().unwrap(); +} \ No newline at end of file From e63b7e51fb6e02b14420c80e6a2a797d59d74ec4 Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 11 Nov 2016 17:26:41 +0000 Subject: [PATCH 15/49] update instant_seal schedule --- ethcore/src/engines/instant_seal.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index acead19b4..75fae4d81 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -55,7 +55,7 @@ impl Engine for InstantSeal { } fn schedule(&self, _env_info: &EnvInfo) -> Schedule { - Schedule::new_homestead() + Schedule::new_post_eip150(false, false, false) } fn is_sealer(&self, _author: &Address) -> Option { Some(true) } @@ -79,7 +79,7 @@ mod tests { let tap = AccountProvider::transient_provider(); let addr = tap.insert_account("".sha3(), "").unwrap(); - let spec = Spec::new_test_instant(); + let spec = Spec::new_instant(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); @@ -95,7 +95,7 @@ mod tests { #[test] fn instant_cant_verify() { - let engine = Spec::new_test_instant().engine; + let engine = Spec::new_instant().engine; let mut header: Header = Header::default(); assert!(engine.verify_block_basic(&header, None).is_ok()); From 53258cca6cbeca1ef0e78b8418674b53d8953a1a Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 11 Nov 2016 17:27:20 +0000 Subject: [PATCH 16/49] add new dev spec --- ethcore/src/miner/miner.rs | 2 +- ethcore/src/spec/spec.rs | 2 +- parity/params.rs | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 19a2b9a10..af4677cf3 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1251,7 +1251,7 @@ mod tests { #[test] fn internal_seals_without_work() { - let miner = Miner::with_spec(&Spec::new_test_instant()); + let miner = Miner::with_spec(&Spec::new_instant()); let c = generate_dummy_client(2); let client = c.reference().as_ref(); diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 786b264ab..d8b2f72fc 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -279,7 +279,7 @@ impl Spec { pub fn new_null() -> Spec { load_bundled!("null") } /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring work). - pub fn new_test_instant() -> Spec { load_bundled!("instant_seal") } + pub fn new_instant() -> Spec { load_bundled!("instant_seal") } /// Create a new Olympic chain spec. pub fn new_ethereum_olympic() -> Spec { load_bundled!("ethereum/olympic") } diff --git a/parity/params.rs b/parity/params.rs index 783c4564a..0a24cc7dd 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -30,6 +30,7 @@ pub enum SpecType { Olympic, Classic, Expanse, + Dev, Custom(String), } @@ -49,6 +50,7 @@ impl str::FromStr for SpecType { "morden" | "testnet" => SpecType::Testnet, "olympic" => SpecType::Olympic, "expanse" => SpecType::Expanse, + "dev" => SpecType::Dev, other => SpecType::Custom(other.into()), }; Ok(spec) @@ -63,6 +65,7 @@ impl SpecType { SpecType::Olympic => Ok(Spec::new_ethereum_olympic()), SpecType::Classic => Ok(Spec::new_ethereum_classic()), SpecType::Expanse => Ok(Spec::new_expanse()), + SpecType::Dev => Ok(Spec::new_instant()), SpecType::Custom(ref filename) => { let file = try!(fs::File::open(filename).map_err(|_| "Could not load specification file.")); Spec::load(file) From 4a653942696a2115e8679c1b4ec6a62df8ff29eb Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 11 Nov 2016 18:38:44 +0000 Subject: [PATCH 17/49] change instant spec, update doc --- ethcore/res/instant_seal.json | 2 +- parity/cli/usage.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/res/instant_seal.json b/ethcore/res/instant_seal.json index b7c29a01f..eefe7431b 100644 --- a/ethcore/res/instant_seal.json +++ b/ethcore/res/instant_seal.json @@ -28,6 +28,6 @@ "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } + "0x00a329c0648769a73afac7f9381e08fb43dbea72": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } } diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index ba27c4902..89603d311 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -32,8 +32,8 @@ Operating Options: (default: {flag_mode_alarm}). --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, - homestead, mainnet, morden, classic, expanse or - testnet (default: {flag_chain}). + homestead, mainnet, morden, classic, expanse, + testnet or dev (default: {flag_chain}). -d --db-path PATH Specify the database & configuration directory path (default: {flag_db_path}). --keys-path PATH Specify the path for JSON key files to be found From cc39b245990dacfa0eeded56971a52ec44bb9778 Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 11 Nov 2016 18:41:04 +0000 Subject: [PATCH 18/49] update chain name --- ethcore/res/instant_seal.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/res/instant_seal.json b/ethcore/res/instant_seal.json index eefe7431b..2d5b38659 100644 --- a/ethcore/res/instant_seal.json +++ b/ethcore/res/instant_seal.json @@ -1,5 +1,5 @@ { - "name": "TestInstantSeal", + "name": "DevelopmentChain", "engine": { "InstantSeal": null }, From ea9c479fffcb904f4d2e75524f503bd5150e8b70 Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 11 Nov 2016 18:57:57 +0000 Subject: [PATCH 19/49] update json_tests --- ethcore/src/json_tests/chain.rs | 12 ++++++------ ethcore/src/json_tests/state.rs | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index b50241199..1146004b3 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -17,7 +17,7 @@ use super::test_common::*; use client::{BlockChainClient, Client, ClientConfig}; use block::Block; -use ethereum; +use spec::Spec; use tests::helpers::*; use devtools::*; use spec::Genesis; @@ -46,11 +46,11 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let genesis = Genesis::from(blockchain.genesis()); let state = From::from(blockchain.pre_state.clone()); let mut spec = match era { - ChainEra::Frontier => ethereum::new_frontier_test(), - ChainEra::Homestead => ethereum::new_homestead_test(), - ChainEra::Eip150 => ethereum::new_eip150_test(), - ChainEra::Eip161 => ethereum::new_eip161_test(), - ChainEra::TransitionTest => ethereum::new_transition_test(), + ChainEra::Frontier => Spec::new_ethereum_frontier_test(), + ChainEra::Homestead => Spec::new_ethereum_homestead_test(), + ChainEra::Eip150 => Spec::new_ethereum_eip150_test(), + ChainEra::Eip161 => Spec::new_ethereum_eip161_test(), + ChainEra::TransitionTest => Spec::new_ethereum_transition_test(), }; spec.set_genesis_state(state); spec.overwrite_genesis_params(genesis); diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index bf84d50ee..712b47feb 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -18,7 +18,7 @@ use super::test_common::*; use tests::helpers::*; use pod_state::{self, PodState}; use log_entry::LogEntry; -use ethereum; +use spec::Spec; use ethjson; pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { @@ -26,11 +26,11 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let tests = ethjson::state::Test::load(json_data).unwrap(); let mut failed = Vec::new(); let engine = match era { - ChainEra::Frontier => ethereum::new_mainnet_like().engine, - ChainEra::Homestead => ethereum::new_homestead_test().engine, - ChainEra::Eip150 => ethereum::new_eip150_test().engine, - ChainEra::Eip161 => ethereum::new_eip161_test().engine, - ChainEra::TransitionTest => ethereum::new_transition_test().engine, + ChainEra::Frontier => Spec::new_ethereum_mainnet_like().engine, + ChainEra::Homestead => Spec::new_ethereum_homestead_test().engine, + ChainEra::Eip150 => Spec::new_ethereum_eip150_test().engine, + ChainEra::Eip161 => Spec::new_ethereum_eip161_test().engine, + ChainEra::TransitionTest => Spec::new_ethereum_transition_test().engine, }; for (name, test) in tests.into_iter() { From aa296c3c0dee7323b86be3c6b56da70e1ee10e5f Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 11 Nov 2016 19:12:32 +0000 Subject: [PATCH 20/49] update rpc tests --- rpc/src/v1/tests/eth.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 2f5131f32..38597343e 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -23,7 +23,6 @@ use ethcore::ids::BlockID; use ethcore::spec::{Genesis, Spec}; use ethcore::block::Block; use ethcore::views::BlockView; -use ethcore::ethereum; use ethcore::miner::{MinerOptions, Banning, GasPricer, MinerService, ExternalMiner, Miner, PendingSet, PrioritizationStrategy, GasLimit}; use ethcore::account_provider::AccountProvider; use devtools::RandomTempPath; @@ -79,7 +78,7 @@ fn snapshot_service() -> Arc { fn make_spec(chain: &BlockChain) -> Spec { let genesis = Genesis::from(chain.genesis()); - let mut spec = ethereum::new_frontier_test(); + let mut spec = Spec::new_ethereum_frontier_test(); let state = chain.pre_state.clone().into(); spec.set_genesis_state(state); spec.overwrite_genesis_params(genesis); From 2d4b4cf5c90706a510fad8a4c24e62754afced88 Mon Sep 17 00:00:00 2001 From: keorn Date: Mon, 14 Nov 2016 10:04:34 +0000 Subject: [PATCH 21/49] revert moves to Spec --- ethcore/res/{ => ethereum}/expanse.json | 0 ethcore/src/ethereum/ethash.rs | 38 ++++++++++---------- ethcore/src/ethereum/mod.rs | 47 ++++++++++++++++++++++--- ethcore/src/json_tests/chain.rs | 12 +++---- ethcore/src/json_tests/state.rs | 12 +++---- ethcore/src/miner/mod.rs | 4 +-- ethcore/src/spec/spec.rs | 33 ----------------- ethcore/src/tests/client.rs | 3 +- ethcore/src/tests/helpers.rs | 3 +- parity/params.rs | 11 +++--- rpc/src/v1/tests/eth.rs | 3 +- 11 files changed, 88 insertions(+), 78 deletions(-) rename ethcore/res/{ => ethereum}/expanse.json (100%) diff --git a/ethcore/res/expanse.json b/ethcore/res/ethereum/expanse.json similarity index 100% rename from ethcore/res/expanse.json rename to ethcore/res/ethereum/expanse.json diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 2c7187b09..6436e3531 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -423,13 +423,13 @@ mod tests { use env_info::EnvInfo; use error::{BlockError, Error}; use header::Header; - use spec::Spec; + use super::super::{new_morden, new_homestead_test}; use super::{Ethash, EthashParams}; use rlp; #[test] fn on_close_block() { - let spec = Spec::new_ethereum_morden(); + let spec = new_morden(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); @@ -443,7 +443,7 @@ mod tests { #[test] fn on_close_block_with_uncle() { - let spec = Spec::new_ethereum_morden(); + let spec = new_morden(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); @@ -463,14 +463,14 @@ mod tests { #[test] fn has_valid_metadata() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; assert!(!engine.name().is_empty()); assert!(engine.version().major >= 1); } #[test] fn can_return_schedule() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; let schedule = engine.schedule(&EnvInfo { number: 10000000, author: 0.into(), @@ -498,8 +498,8 @@ mod tests { #[test] fn can_do_seal_verification_fail() { - let engine = Spec::new_ethereum_morden().engine; - //let engine = Ethash::new_test(Spec::new_ethereum_morden()); + let engine = new_morden().engine; + //let engine = Ethash::new_test(new_morden()); let header: Header = Header::default(); let verify_result = engine.verify_block_basic(&header, None); @@ -513,7 +513,7 @@ mod tests { #[test] fn can_do_difficulty_verification_fail() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; let mut header: Header = Header::default(); header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); @@ -528,7 +528,7 @@ mod tests { #[test] fn can_do_proof_of_work_verification_fail() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; let mut header: Header = Header::default(); header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap()); @@ -544,7 +544,7 @@ mod tests { #[test] fn can_do_seal_unordered_verification_fail() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; let header: Header = Header::default(); let verify_result = engine.verify_block_unordered(&header, None); @@ -558,7 +558,7 @@ mod tests { #[test] fn can_do_seal256_verification_fail() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; let mut header: Header = Header::default(); header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); let verify_result = engine.verify_block_unordered(&header, None); @@ -572,7 +572,7 @@ mod tests { #[test] fn can_do_proof_of_work_unordered_verification_fail() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; let mut header: Header = Header::default(); header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).to_vec(), rlp::encode(&H64::zero()).to_vec()]); header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap()); @@ -588,7 +588,7 @@ mod tests { #[test] fn can_verify_block_family_genesis_fail() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; let header: Header = Header::default(); let parent_header: Header = Header::default(); @@ -603,7 +603,7 @@ mod tests { #[test] fn can_verify_block_family_difficulty_fail() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; let mut header: Header = Header::default(); header.set_number(2); let mut parent_header: Header = Header::default(); @@ -620,7 +620,7 @@ mod tests { #[test] fn can_verify_block_family_gas_fail() { - let engine = Spec::new_ethereum_morden().engine; + let engine = new_morden().engine; let mut header: Header = Header::default(); header.set_number(2); header.set_difficulty(U256::from_str("0000000000000000000000000000000000000000000000000000000000020000").unwrap()); @@ -648,7 +648,7 @@ mod tests { #[test] fn difficulty_frontier() { - let spec = Spec::new_ethereum_homestead_test(); + let spec = new_homestead_test(); let ethparams = get_default_ethash_params(); let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); @@ -666,7 +666,7 @@ mod tests { #[test] fn difficulty_homestead() { - let spec = Spec::new_ethereum_homestead_test(); + let spec = new_homestead_test(); let ethparams = get_default_ethash_params(); let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); @@ -684,7 +684,7 @@ mod tests { #[test] fn difficulty_classic_bomb_delay() { - let spec = Spec::new_ethereum_homestead_test(); + let spec = new_homestead_test(); let ethparams = EthashParams { ecip1010_pause_transition: 3000000, ..get_default_ethash_params() @@ -717,7 +717,7 @@ mod tests { #[test] fn test_difficulty_bomb_continue() { - let spec = Spec::new_ethereum_homestead_test(); + let spec = new_homestead_test(); let ethparams = EthashParams { ecip1010_pause_transition: 3000000, ecip1010_continue_transition: 5000000, diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 3df130a8d..253a12372 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -27,17 +27,56 @@ pub mod denominations; pub use self::ethash::{Ethash}; pub use self::denominations::*; +use super::spec::*; + +fn load(b: &[u8]) -> Spec { + Spec::load(b).expect("chain spec is invalid") +} + +/// Create a new Olympic chain spec. +pub fn new_olympic() -> Spec { load(include_bytes!("../../res/ethereum/olympic.json")) } + +/// Create a new Frontier mainnet chain spec. +pub fn new_frontier() -> Spec { load(include_bytes!("../../res/ethereum/frontier.json")) } + +/// Create a new Frontier mainnet chain spec without the DAO hardfork. +pub fn new_classic() -> Spec { load(include_bytes!("../../res/ethereum/classic.json")) } + +/// Create a new Frontier mainnet chain spec without the DAO hardfork. +pub fn new_expanse() -> Spec { load(include_bytes!("../../res/ethereum/expanse.json")) } + +/// Create a new Frontier chain spec as though it never changes to Homestead. +pub fn new_frontier_test() -> Spec { load(include_bytes!("../../res/ethereum/frontier_test.json")) } + +/// Create a new Homestead chain spec as though it never changed from Frontier. +pub fn new_homestead_test() -> Spec { load(include_bytes!("../../res/ethereum/homestead_test.json")) } + +/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. +pub fn new_eip150_test() -> Spec { load(include_bytes!("../../res/ethereum/eip150_test.json")) } + +/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. +pub fn new_eip161_test() -> Spec { load(include_bytes!("../../res/ethereum/eip161_test.json")) } + +/// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8. +pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/transition_test.json")) } + +/// Create a new Frontier main net chain spec without genesis accounts. +pub fn new_mainnet_like() -> Spec { load(include_bytes!("../../res/ethereum/frontier_like_test.json")) } + +/// Create a new Morden chain spec. +pub fn new_morden() -> Spec { load(include_bytes!("../../res/ethereum/morden.json")) } + #[cfg(test)] mod tests { use util::*; use state::*; + use super::*; use tests::helpers::*; - use spec::Spec; use views::BlockView; #[test] fn ensure_db_good() { - let spec = Spec::new_ethereum_morden(); + let spec = new_morden(); let engine = &spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); @@ -54,7 +93,7 @@ mod tests { #[test] fn morden() { - let morden = Spec::new_ethereum_morden(); + let morden = new_morden(); assert_eq!(morden.state_root(), "f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9".into()); let genesis = morden.genesis_block(); @@ -65,7 +104,7 @@ mod tests { #[test] fn frontier() { - let frontier = Spec::new_ethereum_frontier(); + let frontier = new_frontier(); assert_eq!(frontier.state_root(), "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".into()); let genesis = frontier.genesis_block(); diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 1146004b3..b50241199 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -17,7 +17,7 @@ use super::test_common::*; use client::{BlockChainClient, Client, ClientConfig}; use block::Block; -use spec::Spec; +use ethereum; use tests::helpers::*; use devtools::*; use spec::Genesis; @@ -46,11 +46,11 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let genesis = Genesis::from(blockchain.genesis()); let state = From::from(blockchain.pre_state.clone()); let mut spec = match era { - ChainEra::Frontier => Spec::new_ethereum_frontier_test(), - ChainEra::Homestead => Spec::new_ethereum_homestead_test(), - ChainEra::Eip150 => Spec::new_ethereum_eip150_test(), - ChainEra::Eip161 => Spec::new_ethereum_eip161_test(), - ChainEra::TransitionTest => Spec::new_ethereum_transition_test(), + ChainEra::Frontier => ethereum::new_frontier_test(), + ChainEra::Homestead => ethereum::new_homestead_test(), + ChainEra::Eip150 => ethereum::new_eip150_test(), + ChainEra::Eip161 => ethereum::new_eip161_test(), + ChainEra::TransitionTest => ethereum::new_transition_test(), }; spec.set_genesis_state(state); spec.overwrite_genesis_params(genesis); diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index 712b47feb..bf84d50ee 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -18,7 +18,7 @@ use super::test_common::*; use tests::helpers::*; use pod_state::{self, PodState}; use log_entry::LogEntry; -use spec::Spec; +use ethereum; use ethjson; pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { @@ -26,11 +26,11 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let tests = ethjson::state::Test::load(json_data).unwrap(); let mut failed = Vec::new(); let engine = match era { - ChainEra::Frontier => Spec::new_ethereum_mainnet_like().engine, - ChainEra::Homestead => Spec::new_ethereum_homestead_test().engine, - ChainEra::Eip150 => Spec::new_ethereum_eip150_test().engine, - ChainEra::Eip161 => Spec::new_ethereum_eip161_test().engine, - ChainEra::TransitionTest => Spec::new_ethereum_transition_test().engine, + ChainEra::Frontier => ethereum::new_mainnet_like().engine, + ChainEra::Homestead => ethereum::new_homestead_test().engine, + ChainEra::Eip150 => ethereum::new_eip150_test().engine, + ChainEra::Eip161 => ethereum::new_eip161_test().engine, + ChainEra::TransitionTest => ethereum::new_transition_test().engine, }; for (name, test) in tests.into_iter() { diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index fc306c3de..da93dc0b7 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -27,12 +27,12 @@ //! extern crate ethcore_util as util; //! extern crate ethcore; //! use std::env; -//! use ethcore::spec::Spec; +//! use ethcore::ethereum; //! use ethcore::client::{Client, ClientConfig}; //! use ethcore::miner::{Miner, MinerService}; //! //! fn main() { -//! let miner: Miner = Miner::with_spec(&Spec::new_ethereum_frontier()); +//! let miner: Miner = Miner::with_spec(ðereum::new_frontier()); //! // get status //! assert_eq!(miner.status().transactions_in_pending_queue, 0); //! diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index d8b2f72fc..22eb13850 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -280,39 +280,6 @@ impl Spec { /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring work). pub fn new_instant() -> Spec { load_bundled!("instant_seal") } - - /// Create a new Olympic chain spec. - pub fn new_ethereum_olympic() -> Spec { load_bundled!("ethereum/olympic") } - - /// Create a new Frontier mainnet chain spec. - pub fn new_ethereum_frontier() -> Spec { load_bundled!("ethereum/frontier") } - - /// Create a new Frontier mainnet chain spec without the DAO hardfork. - pub fn new_ethereum_classic() -> Spec { load_bundled!("ethereum/classic") } - - /// Create a new Frontier mainnet chain spec without the DAO hardfork. - pub fn new_expanse() -> Spec { load_bundled!("expanse") } - - /// Create a new Frontier chain spec as though it never changes to Homestead. - pub fn new_ethereum_frontier_test() -> Spec { load_bundled!("ethereum/frontier_test") } - - /// Create a new Homestead chain spec as though it never changed from Frontier. - pub fn new_ethereum_homestead_test() -> Spec { load_bundled!("ethereum/homestead_test") } - - /// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. - pub fn new_ethereum_eip150_test() -> Spec { load_bundled!("ethereum/eip150_test") } - - /// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. - pub fn new_ethereum_eip161_test() -> Spec { load_bundled!("ethereum/eip161_test") } - - /// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8. - pub fn new_ethereum_transition_test() -> Spec { load_bundled!("ethereum/transition_test") } - - /// Create a new Frontier main net chain spec without genesis accounts. - pub fn new_ethereum_mainnet_like() -> Spec { load_bundled!("ethereum/frontier_like_test") } - - /// Create a new Morden chain spec. - pub fn new_ethereum_morden() -> Spec { load_bundled!("ethereum/morden") } } #[cfg(test)] diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index e6fba0b0a..99b251d66 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -17,6 +17,7 @@ use io::IoChannel; use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockID}; use state::CleanupMode; +use ethereum; use block::IsBlock; use tests::helpers::*; use types::filter::Filter; @@ -49,7 +50,7 @@ fn imports_from_empty() { #[test] fn should_return_registrar() { let dir = RandomTempPath::new(); - let spec = Spec::new_ethereum_morden(); + let spec = ethereum::new_morden(); let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); let client = Client::new( diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index a6a06608a..96d5f8366 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -27,6 +27,7 @@ use state::*; use evm::Schedule; use engines::Engine; use env_info::EnvInfo; +use ethereum; use ethereum::ethash::EthashParams; use devtools::*; use miner::Miner; @@ -52,7 +53,7 @@ pub struct TestEngine { impl TestEngine { pub fn new(max_depth: usize) -> TestEngine { TestEngine { - engine: Spec::new_ethereum_frontier_test().engine, + engine: ethereum::new_frontier_test().engine, max_depth: max_depth, } } diff --git a/parity/params.rs b/parity/params.rs index 0a24cc7dd..54e08da32 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -19,6 +19,7 @@ use std::time::Duration; use util::{Address, U256, version_data}; use util::journaldb::Algorithm; use ethcore::spec::Spec; +use ethcore::ethereum; use ethcore::client::Mode; use ethcore::miner::{GasPricer, GasPriceCalibratorOptions}; use user_defaults::UserDefaults; @@ -60,11 +61,11 @@ impl str::FromStr for SpecType { impl SpecType { pub fn spec(&self) -> Result { match *self { - SpecType::Mainnet => Ok(Spec::new_ethereum_frontier()), - SpecType::Testnet => Ok(Spec::new_ethereum_morden()), - SpecType::Olympic => Ok(Spec::new_ethereum_olympic()), - SpecType::Classic => Ok(Spec::new_ethereum_classic()), - SpecType::Expanse => Ok(Spec::new_expanse()), + SpecType::Mainnet => Ok(ethereum::new_frontier()), + SpecType::Testnet => Ok(ethereum::new_morden()), + SpecType::Olympic => Ok(ethereum::new_olympic()), + SpecType::Classic => Ok(ethereum::new_classic()), + SpecType::Expanse => Ok(ethereum::new_expanse()), SpecType::Dev => Ok(Spec::new_instant()), SpecType::Custom(ref filename) => { let file = try!(fs::File::open(filename).map_err(|_| "Could not load specification file.")); diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 38597343e..2f5131f32 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -23,6 +23,7 @@ use ethcore::ids::BlockID; use ethcore::spec::{Genesis, Spec}; use ethcore::block::Block; use ethcore::views::BlockView; +use ethcore::ethereum; use ethcore::miner::{MinerOptions, Banning, GasPricer, MinerService, ExternalMiner, Miner, PendingSet, PrioritizationStrategy, GasLimit}; use ethcore::account_provider::AccountProvider; use devtools::RandomTempPath; @@ -78,7 +79,7 @@ fn snapshot_service() -> Arc { fn make_spec(chain: &BlockChain) -> Spec { let genesis = Genesis::from(chain.genesis()); - let mut spec = Spec::new_ethereum_frontier_test(); + let mut spec = ethereum::new_frontier_test(); let state = chain.pre_state.clone().into(); spec.set_genesis_state(state); spec.overwrite_genesis_params(genesis); From e9e947583091f0fd64b747ec25fc7fa71d2d9572 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Mon, 14 Nov 2016 11:39:36 +0100 Subject: [PATCH 22/49] CopyToClipboard: remove tooltip --- js/src/ui/CopyToClipboard/copyToClipboard.css | 4 ++++ js/src/ui/CopyToClipboard/copyToClipboard.js | 9 ++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/js/src/ui/CopyToClipboard/copyToClipboard.css b/js/src/ui/CopyToClipboard/copyToClipboard.css index acf2bb204..0c511ba45 100644 --- a/js/src/ui/CopyToClipboard/copyToClipboard.css +++ b/js/src/ui/CopyToClipboard/copyToClipboard.css @@ -15,6 +15,10 @@ /* along with Parity. If not, see . */ +.wrapper { + display: inline-block; +} + .data { font-family: monospace; } diff --git a/js/src/ui/CopyToClipboard/copyToClipboard.js b/js/src/ui/CopyToClipboard/copyToClipboard.js index c78038617..568520b09 100644 --- a/js/src/ui/CopyToClipboard/copyToClipboard.js +++ b/js/src/ui/CopyToClipboard/copyToClipboard.js @@ -28,7 +28,6 @@ import styles from './copyToClipboard.css'; export default class CopyToClipboard extends Component { static propTypes = { data: PropTypes.string.isRequired, - label: PropTypes.string, onCopy: PropTypes.func, size: PropTypes.number, // in px cooldown: PropTypes.number // in ms @@ -36,7 +35,6 @@ export default class CopyToClipboard extends Component { static defaultProps = { className: '', - label: 'copy to clipboard', onCopy: () => {}, size: 16, cooldown: 1000 @@ -55,12 +53,12 @@ export default class CopyToClipboard extends Component { } render () { - const { data, label, size } = this.props; + const { data, size } = this.props; const { copied } = this.state; return ( -
+
From d02afc0e409b769ab487f7cc411edb62a8d00bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 14 Nov 2016 13:21:08 +0100 Subject: [PATCH 23/49] Beta -> Stable --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 80bf9ba10..6f3fd9933 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ matrix: include: - rust: stable env: RUN_TESTS="true" TEST_OPTIONS="--no-release" - - rust: beta + - rust: stable env: RUN_COVERAGE="true" - rust: stable env: RUN_DOCS="true" From 48b2252029c62c9f1617badabefb611536d5bc2a Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Mon, 14 Nov 2016 15:16:57 +0100 Subject: [PATCH 24/49] Swap from base to decimals --- .../tokenreg/Actions/Register/register.js | 10 +++++----- js/src/dapps/tokenreg/Actions/actions.js | 3 ++- js/src/dapps/tokenreg/Inputs/validation.js | 18 ++++++++++++++++++ js/src/dapps/tokenreg/Tokens/Token/token.js | 4 ++-- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/js/src/dapps/tokenreg/Actions/Register/register.js b/js/src/dapps/tokenreg/Actions/Register/register.js index 8ae042494..a008ce84f 100644 --- a/js/src/dapps/tokenreg/Actions/Register/register.js +++ b/js/src/dapps/tokenreg/Actions/Register/register.js @@ -21,7 +21,7 @@ import { Dialog, FlatButton } from 'material-ui'; import AccountSelector from '../../Accounts/AccountSelector'; import InputText from '../../Inputs/Text'; -import { TOKEN_ADDRESS_TYPE, TLA_TYPE, UINT_TYPE, STRING_TYPE } from '../../Inputs/validation'; +import { TOKEN_ADDRESS_TYPE, TLA_TYPE, DECIMAL_TYPE, STRING_TYPE } from '../../Inputs/validation'; import styles from '../actions.css'; @@ -41,11 +41,11 @@ const initState = { floatingLabelText: 'Token TLA', hintText: 'The token short name (3 characters)' }, - base: { + decimals: { ...defaultField, - type: UINT_TYPE, - floatingLabelText: 'Token Base', - hintText: 'The token precision' + type: DECIMAL_TYPE, + floatingLabelText: 'Token Decimals', + hintText: 'The number of decimals (0-18)' }, name: { ...defaultField, diff --git a/js/src/dapps/tokenreg/Actions/actions.js b/js/src/dapps/tokenreg/Actions/actions.js index 0f3390ea4..1c6703f77 100644 --- a/js/src/dapps/tokenreg/Actions/actions.js +++ b/js/src/dapps/tokenreg/Actions/actions.js @@ -47,7 +47,8 @@ export const registerToken = (tokenData) => (dispatch, getState) => { const contractInstance = state.status.contract.instance; const fee = state.status.contract.fee; - const { address, base, name, tla } = tokenData; + const { address, decimals, name, tla } = tokenData; + const base = Math.pow(10, decimals); dispatch(setRegisterSending(true)); diff --git a/js/src/dapps/tokenreg/Inputs/validation.js b/js/src/dapps/tokenreg/Inputs/validation.js index 38eba5ef1..fd394b4ec 100644 --- a/js/src/dapps/tokenreg/Inputs/validation.js +++ b/js/src/dapps/tokenreg/Inputs/validation.js @@ -32,6 +32,7 @@ export const SIMPLE_TOKEN_ADDRESS_TYPE = 'SIMPLE_TOKEN_ADDRESS_TYPE'; export const TLA_TYPE = 'TLA_TYPE'; export const SIMPLE_TLA_TYPE = 'SIMPLE_TLA_TYPE'; export const UINT_TYPE = 'UINT_TYPE'; +export const DECIMAL_TYPE = 'DECIMAL_TYPE'; export const STRING_TYPE = 'STRING_TYPE'; export const HEX_TYPE = 'HEX_TYPE'; export const URL_TYPE = 'URL_TYPE'; @@ -39,6 +40,7 @@ export const URL_TYPE = 'URL_TYPE'; export const ERRORS = { invalidTLA: 'The TLA should be 3 characters long', invalidUint: 'Please enter a non-negative integer', + invalidDecimal: 'Please enter a value between 0 and 18', invalidString: 'Please enter at least a character', invalidAccount: 'Please select an account to transact with', invalidRecipient: 'Please select an account to send to', @@ -152,6 +154,21 @@ const validateUint = (uint) => { }; }; +const validateDecimal = (decimal) => { + if (!/^\d+$/.test(decimal) || parseInt(decimal) < 0 || parseInt(decimal) > 18) { + return { + error: ERRORS.invalidDecimal, + valid: false + }; + } + + return { + value: parseInt(decimal), + error: null, + valid: true + }; +}; + const validateString = (string) => { if (string.toString().length === 0) { return { @@ -204,6 +221,7 @@ export const validate = (value, type, contract) => { if (type === TLA_TYPE) return validateTLA(value, contract); if (type === SIMPLE_TLA_TYPE) return validateTLA(value, contract, true); if (type === UINT_TYPE) return validateUint(value); + if (type === DECIMAL_TYPE) return validateDecimal(value); if (type === STRING_TYPE) return validateString(value); if (type === HEX_TYPE) return validateHex(value); if (type === URL_TYPE) return validateURL(value); diff --git a/js/src/dapps/tokenreg/Tokens/Token/token.js b/js/src/dapps/tokenreg/Tokens/Token/token.js index 34550ef48..660b21b97 100644 --- a/js/src/dapps/tokenreg/Tokens/Token/token.js +++ b/js/src/dapps/tokenreg/Tokens/Token/token.js @@ -152,8 +152,8 @@ export default class Token extends Component { if (!base || base < 0) return null; return ( + value={ Math.log10(base).toString() } + label='Decimals' /> ); } From 0b5a9a6e60b02b69ee83d056294159316dab92b6 Mon Sep 17 00:00:00 2001 From: keorn Date: Mon, 14 Nov 2016 14:29:33 +0000 Subject: [PATCH 25/49] nicer bundled spec message --- ethcore/src/spec/spec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 695483611..de1b7db42 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -137,7 +137,7 @@ impl From for Spec { macro_rules! load_bundled { ($e:expr) => { - Spec::load(include_bytes!(concat!("../../res/", $e, ".json")) as &[u8]).expect("Chain spec is invalid") + Spec::load(include_bytes!(concat!("../../res/", $e, ".json")) as &[u8]).expect(concat!("Chain spec ", $e, " is invalid.")) }; } From ecb89d3670fffc932bdeb6867b9d55e8243dcafb Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 14 Nov 2016 15:35:25 +0100 Subject: [PATCH 26/49] Scrollable Accounts list // Tab;Enter;Keydown for first input #3396 --- .../basiccoin/AddressSelect/addressSelect.css | 4 +++ js/src/ui/Form/AutoComplete/autocomplete.js | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/js/src/dapps/basiccoin/AddressSelect/addressSelect.css b/js/src/dapps/basiccoin/AddressSelect/addressSelect.css index ddfd334e8..818906708 100644 --- a/js/src/dapps/basiccoin/AddressSelect/addressSelect.css +++ b/js/src/dapps/basiccoin/AddressSelect/addressSelect.css @@ -21,3 +21,7 @@ .iconMenu option { padding-left: 30px; } + +.menu { + display: none; +} diff --git a/js/src/ui/Form/AutoComplete/autocomplete.js b/js/src/ui/Form/AutoComplete/autocomplete.js index b0958da31..89cc5ee16 100644 --- a/js/src/ui/Form/AutoComplete/autocomplete.js +++ b/js/src/ui/Form/AutoComplete/autocomplete.js @@ -15,6 +15,7 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; +import keycode from 'keycode'; import { MenuItem, AutoComplete as MUIAutoComplete } from 'material-ui'; import { PopoverAnimationVertical } from 'material-ui/Popover'; @@ -67,6 +68,9 @@ export default class AutoComplete extends Component { fullWidth floatingLabelFixed dataSource={ this.getDataSource() } + menuProps={ { maxHeight: 400 } } + ref='muiAutocomplete' + onKeyDown={ this.onKeyDown } /> ); } @@ -91,6 +95,29 @@ export default class AutoComplete extends Component { })); } + onKeyDown = (event) => { + const { muiAutocomplete } = this.refs; + + switch (keycode(event)) { + case 'down': + const { menu } = muiAutocomplete.refs; + menu.handleKeyDown(event); + break; + + case 'enter': + case 'tab': + event.preventDefault(); + event.stopPropagation(); + event.which = 'useless'; + + const e = new CustomEvent('down'); + e.which = 40; + + muiAutocomplete.handleKeyDown(e); + break; + } + } + onChange = (item, idx) => { if (idx === -1) { return; From d66cc0907dc96376d1ad3b302e2f090524550571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 14 Nov 2016 16:10:04 +0100 Subject: [PATCH 27/49] Bump ws-rs --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 95be811e2..420af2655 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1926,7 +1926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ws" version = "0.5.3" -source = "git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable#0cd6c5e3e9d5e61a37d53eb8dcbad523dcc69314" +source = "git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable#f5c0b35d660244d1b7500693c8cc28277ce1d418" dependencies = [ "bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)", "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", From 89f83b8cd7974df78f5b1734a03192a879b1aad2 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 14 Nov 2016 16:11:00 +0100 Subject: [PATCH 28/49] Fixes #3397 : fake blur handled --- js/src/ui/Form/AutoComplete/autocomplete.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/js/src/ui/Form/AutoComplete/autocomplete.js b/js/src/ui/Form/AutoComplete/autocomplete.js index 89cc5ee16..ada1176b6 100644 --- a/js/src/ui/Form/AutoComplete/autocomplete.js +++ b/js/src/ui/Form/AutoComplete/autocomplete.js @@ -41,7 +41,8 @@ export default class AutoComplete extends Component { state = { lastChangedValue: undefined, entry: null, - open: false + open: false, + fakeBlur: false } render () { @@ -102,6 +103,7 @@ export default class AutoComplete extends Component { case 'down': const { menu } = muiAutocomplete.refs; menu.handleKeyDown(event); + this.setState({ fakeBlur: true }); break; case 'enter': @@ -135,17 +137,22 @@ export default class AutoComplete extends Component { this.setState({ entry, open: false }); } - onBlur = () => { + onBlur = (event) => { const { onUpdateInput } = this.props; - // TODO: Handle blur gracefully where we use onUpdateInput (currently replaces input + // TODO: Handle blur gracefully where we use onUpdateInput (currently replaces // input where text is allowed with the last selected value from the dropdown) if (!onUpdateInput) { window.setTimeout(() => { - const { entry } = this.state; + const { entry, fakeBlur } = this.state; + + if (fakeBlur) { + this.setState({ fakeBlur: false }); + return; + } this.handleOnChange(entry); - }, 100); + }, 200); } } From c061eae64b88ab60b4f526cee918afce33445fbd Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Mon, 14 Nov 2016 15:46:21 +0000 Subject: [PATCH 29/49] [ci skip] js-precompiled 20161114-154454 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2e3b0690..0a7c27813 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1249,7 +1249,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#7bf550e482ef274480d1fd7e1ceb2efddd747dbd" +source = "git+https://github.com/ethcore/js-precompiled.git#1628fe95dd21b87f35a72f06c452b814876e3877" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index 1e2da7d5b..a68826c9a 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.38", + "version": "0.2.39", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 5127b997ebbb370d61faaf0db95401ee460d0eeb Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Mon, 14 Nov 2016 15:54:09 +0000 Subject: [PATCH 30/49] [ci skip] js-precompiled 20161114-155241 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a7c27813..487a8a40a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1249,7 +1249,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#1628fe95dd21b87f35a72f06c452b814876e3877" +source = "git+https://github.com/ethcore/js-precompiled.git#1c7339e275e82608a0380824f675a666de0b9e83" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index a68826c9a..6f3893bbb 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.39", + "version": "0.2.40", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 9e2214c513f24e4064321375a1d01c9b1dc766c1 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 14 Nov 2016 17:00:36 +0100 Subject: [PATCH 31/49] Working add/remove fields for var. length #3314 --- .../DeployContract/DetailsStep/detailsStep.js | 90 ++++++++++++++----- .../modals/DeployContract/deployContract.css | 4 +- .../ui/Form/AddressSelect/addressSelect.css | 4 + js/src/ui/Form/AddressSelect/addressSelect.js | 10 ++- 4 files changed, 82 insertions(+), 26 deletions(-) diff --git a/js/src/modals/DeployContract/DetailsStep/detailsStep.js b/js/src/modals/DeployContract/DetailsStep/detailsStep.js index c04a505bf..67c5586f0 100644 --- a/js/src/modals/DeployContract/DetailsStep/detailsStep.js +++ b/js/src/modals/DeployContract/DetailsStep/detailsStep.js @@ -18,6 +18,10 @@ import React, { Component, PropTypes } from 'react'; import { MenuItem } from 'material-ui'; import { range } from 'lodash'; +import IconButton from 'material-ui/IconButton'; +import AddIcon from 'material-ui/svg-icons/content/add'; +import RemoveIcon from 'material-ui/svg-icons/content/remove'; + import { AddressSelect, Form, Input, InputAddressSelect, Select } from '../../../ui'; import { validateAbi } from '../../../util/validation'; @@ -43,37 +47,65 @@ class TypedInput extends Component { const { accounts, label, value = param.default } = this.props; const { subtype, length } = param; - if (length) { - const inputs = range(length).map((_, index) => { - const onChange = (inputValue) => { - const newValues = [].concat(this.props.value); - newValues[index] = inputValue; - this.props.onChange(newValues); - }; + const fixedLength = !!length; - return ( - - ); - }); + const inputs = range(length || value.length).map((_, index) => { + const onChange = (inputValue) => { + const newValues = [].concat(this.props.value); + newValues[index] = inputValue; + this.props.onChange(newValues); + }; return ( -
- - { inputs } -
+ ); - } + }); + + return ( +
+ + { fixedLength ? null : this.renderLength() } + { inputs } +
+ ); } return this.renderType(type); } + renderLength () { + const style = { + width: 16, + height: 16 + }; + + return ( +
+ + + + + + + +
+ ); + } + renderType (type) { if (type === ADDRESS_TYPE) { return this.renderAddress(); @@ -184,6 +216,20 @@ class TypedInput extends Component { this.props.onChange(value); } + onAddField = () => { + const { value, onChange, param } = this.props; + const newValues = [].concat(value, param.subtype.default); + + onChange(newValues); + } + + onRemoveField = () => { + const { value, onChange } = this.props; + const newValues = value.slice(0, -1); + + onChange(newValues); + } + } export default class DetailsStep extends Component { diff --git a/js/src/modals/DeployContract/deployContract.css b/js/src/modals/DeployContract/deployContract.css index b8ce35b8a..ef92b24af 100644 --- a/js/src/modals/DeployContract/deployContract.css +++ b/js/src/modals/DeployContract/deployContract.css @@ -33,7 +33,7 @@ } .inputs { - padding-top: 18px; + padding-top: 2px; label { line-height: 22px; @@ -41,7 +41,7 @@ color: rgba(255, 255, 255, 0.498039); -webkit-user-select: none; font-size: 12px; - top: 8px; + top: 11px; position: relative; } } diff --git a/js/src/ui/Form/AddressSelect/addressSelect.css b/js/src/ui/Form/AddressSelect/addressSelect.css index 98dab4355..30671db73 100644 --- a/js/src/ui/Form/AddressSelect/addressSelect.css +++ b/js/src/ui/Form/AddressSelect/addressSelect.css @@ -39,6 +39,10 @@ position: absolute; left: 0; top: 35px; + + &.noLabel { + top: 11px; + } } .paddedInput input { diff --git a/js/src/ui/Form/AddressSelect/addressSelect.js b/js/src/ui/Form/AddressSelect/addressSelect.js index ac7f2da51..97195efe7 100644 --- a/js/src/ui/Form/AddressSelect/addressSelect.js +++ b/js/src/ui/Form/AddressSelect/addressSelect.js @@ -106,15 +106,21 @@ export default class AddressSelect extends Component { } renderIdentityIcon (inputValue) { - const { error, value } = this.props; + const { error, value, label } = this.props; if (error || !inputValue || value.length !== 42) { return null; } + const classes = [ styles.icon ]; + + if (!label) { + classes.push(styles.noLabel); + } + return ( ); From 29442673f8bae829df4cf93fc84878811af227a4 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 14 Nov 2016 17:39:45 +0100 Subject: [PATCH 32/49] Clean-Up #3314 --- .../DeployContract/DetailsStep/detailsStep.js | 337 +----------------- .../modals/DeployContract/deployContract.css | 14 - .../modals/DeployContract/deployContract.js | 2 - js/src/ui/Form/TypedInput/index.js | 17 + js/src/ui/Form/TypedInput/typedInput.css | 31 ++ js/src/ui/Form/TypedInput/typedInput.js | 239 +++++++++++++ js/src/ui/Form/index.js | 2 + js/src/ui/index.js | 3 +- js/src/util/abi.js | 146 ++++++++ 9 files changed, 440 insertions(+), 351 deletions(-) create mode 100644 js/src/ui/Form/TypedInput/index.js create mode 100644 js/src/ui/Form/TypedInput/typedInput.css create mode 100644 js/src/ui/Form/TypedInput/typedInput.js create mode 100644 js/src/util/abi.js diff --git a/js/src/modals/DeployContract/DetailsStep/detailsStep.js b/js/src/modals/DeployContract/DetailsStep/detailsStep.js index 1773fd0da..6e23f79c9 100644 --- a/js/src/modals/DeployContract/DetailsStep/detailsStep.js +++ b/js/src/modals/DeployContract/DetailsStep/detailsStep.js @@ -15,223 +15,13 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; -import { MenuItem } from 'material-ui'; -import { range } from 'lodash'; -import IconButton from 'material-ui/IconButton'; -import AddIcon from 'material-ui/svg-icons/content/add'; -import RemoveIcon from 'material-ui/svg-icons/content/remove'; - -import { AddressSelect, Form, Input, InputAddressSelect, Select } from '../../../ui'; +import { AddressSelect, Form, Input, TypedInput } from '../../../ui'; import { validateAbi } from '../../../util/validation'; +import { parseAbiType } from '../../../util/abi'; import styles from '../deployContract.css'; -class TypedInput extends Component { - - static propTypes = { - onChange: PropTypes.func.isRequired, - accounts: PropTypes.object.isRequired, - param: PropTypes.object.isRequired, - - error: PropTypes.any, - value: PropTypes.any, - label: PropTypes.string - }; - - render () { - const { param } = this.props; - const { type } = param; - - if (type === ARRAY_TYPE) { - const { accounts, label, value = param.default } = this.props; - const { subtype, length } = param; - - const fixedLength = !!length; - - const inputs = range(length || value.length).map((_, index) => { - const onChange = (inputValue) => { - const newValues = [].concat(this.props.value); - newValues[index] = inputValue; - this.props.onChange(newValues); - }; - - return ( - - ); - }); - - return ( -
- - { fixedLength ? null : this.renderLength() } - { inputs } -
- ); - } - - return this.renderType(type); - } - - renderLength () { - const style = { - width: 16, - height: 16 - }; - - return ( -
- - - - - - - -
- ); - } - - renderType (type) { - if (type === ADDRESS_TYPE) { - return this.renderAddress(); - } - - if (type === BOOL_TYPE) { - return this.renderBoolean(); - } - - if (type === STRING_TYPE) { - return this.renderDefault(); - } - - if (type === BYTES_TYPE) { - return this.renderDefault(); - } - - if (type === INT_TYPE) { - return this.renderNumber(); - } - - if (type === FIXED_TYPE) { - return this.renderNumber(); - } - - return this.renderDefault(); - } - - renderNumber () { - const { label, value, error, param } = this.props; - - return ( - - ); - } - - renderDefault () { - const { label, value, error } = this.props; - - return ( - - ); - } - - renderAddress () { - const { accounts, label, value, error } = this.props; - - return ( - - ); - } - - renderBoolean () { - const { label, value, error } = this.props; - - const boolitems = ['false', 'true'].map((bool) => { - return ( - - { bool } - - ); - }); - - return ( - - ); - } - - onChangeBool = (event, _index, value) => { - this.props.onChange(value === 'true'); - } - - onChange = (event, value) => { - this.props.onChange(value); - } - - onSubmit = (value) => { - this.props.onChange(value); - } - - onAddField = () => { - const { value, onChange, param } = this.props; - const newValues = [].concat(value, param.subtype.default); - - onChange(newValues); - } - - onRemoveField = () => { - const { value, onChange } = this.props; - const newValues = value.slice(0, -1); - - onChange(newValues); - } - -} - export default class DetailsStep extends Component { static contextTypes = { api: PropTypes.object.isRequired @@ -313,6 +103,7 @@ export default class DetailsStep extends Component { value={ code } onSubmit={ this.onCodeChange } readOnly={ readOnly } /> + { this.renderConstructorInputs() } ); @@ -400,125 +191,3 @@ export default class DetailsStep extends Component { onCodeChange(code); } } - -const ARRAY_TYPE = 'ARRAY_TYPE'; -const ADDRESS_TYPE = 'ADDRESS_TYPE'; -const STRING_TYPE = 'STRING_TYPE'; -const BOOL_TYPE = 'BOOL_TYPE'; -const BYTES_TYPE = 'BYTES_TYPE'; -const INT_TYPE = 'INT_TYPE'; -const FIXED_TYPE = 'FIXED_TYPE'; - -function parseAbiType (type) { - const arrayRegex = /^(.+)\[(\d*)\]$/; - - if (arrayRegex.test(type)) { - const matches = arrayRegex.exec(type); - - const subtype = parseAbiType(matches[1]); - const M = parseInt(matches[2]) || null; - const defaultValue = !M - ? [] - : range(M).map(() => subtype.default); - - return { - type: ARRAY_TYPE, - subtype: subtype, - length: M, - default: defaultValue - }; - } - - const lengthRegex = /^(u?int|bytes)(\d{1,3})$/; - - if (lengthRegex.test(type)) { - const matches = lengthRegex.exec(type); - - const subtype = parseAbiType(matches[1]); - const length = parseInt(matches[2]); - - return { - ...subtype, - length - }; - } - - const fixedLengthRegex = /^(u?fixed)(\d{1,3})x(\d{1,3})$/; - - if (fixedLengthRegex.test(type)) { - const matches = fixedLengthRegex.exec(type); - - const subtype = parseAbiType(matches[1]); - const M = parseInt(matches[2]); - const N = parseInt(matches[3]); - - return { - ...subtype, - M, N - }; - } - - if (type === 'string') { - return { - type: STRING_TYPE, - default: '' - }; - } - - if (type === 'bool') { - return { - type: BOOL_TYPE, - default: false - }; - } - - if (type === 'address') { - return { - type: ADDRESS_TYPE, - default: '0x' - }; - } - - if (type === 'bytes') { - return { - type: BYTES_TYPE, - default: '0x' - }; - } - - if (type === 'uint') { - return { - type: INT_TYPE, - default: 0, - length: 256, - signed: false - }; - } - - if (type === 'int') { - return { - type: INT_TYPE, - default: 0, - length: 256, - signed: true - }; - } - - if (type === 'ufixed') { - return { - type: FIXED_TYPE, - default: 0, - length: 256, - signed: false - }; - } - - if (type === 'fixed') { - return { - type: FIXED_TYPE, - default: 0, - length: 256, - signed: true - }; - } -} diff --git a/js/src/modals/DeployContract/deployContract.css b/js/src/modals/DeployContract/deployContract.css index ef92b24af..45fd7a852 100644 --- a/js/src/modals/DeployContract/deployContract.css +++ b/js/src/modals/DeployContract/deployContract.css @@ -31,17 +31,3 @@ .funcparams { padding-left: 3em; } - -.inputs { - padding-top: 2px; - - label { - line-height: 22px; - pointer-events: none; - color: rgba(255, 255, 255, 0.498039); - -webkit-user-select: none; - font-size: 12px; - top: 11px; - position: relative; - } -} diff --git a/js/src/modals/DeployContract/deployContract.js b/js/src/modals/DeployContract/deployContract.js index d38851ccb..257ede1f1 100644 --- a/js/src/modals/DeployContract/deployContract.js +++ b/js/src/modals/DeployContract/deployContract.js @@ -278,8 +278,6 @@ export default class DeployContract extends Component { return; } - console.log('onDeploymentState', data); - switch (data.state) { case 'estimateGas': case 'postTransaction': diff --git a/js/src/ui/Form/TypedInput/index.js b/js/src/ui/Form/TypedInput/index.js new file mode 100644 index 000000000..9c12bf7eb --- /dev/null +++ b/js/src/ui/Form/TypedInput/index.js @@ -0,0 +1,17 @@ +// Copyright 2015, 2016 Ethcore (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 . + +export default from './typedInput'; diff --git a/js/src/ui/Form/TypedInput/typedInput.css b/js/src/ui/Form/TypedInput/typedInput.css new file mode 100644 index 000000000..c13206c96 --- /dev/null +++ b/js/src/ui/Form/TypedInput/typedInput.css @@ -0,0 +1,31 @@ +/* Copyright 2015, 2016 Ethcore (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 . +*/ + +.inputs { + padding-top: 2px; + overflow-x: hidden; + + label { + line-height: 22px; + pointer-events: none; + color: rgba(255, 255, 255, 0.498039); + -webkit-user-select: none; + font-size: 12px; + top: 11px; + position: relative; + } +} diff --git a/js/src/ui/Form/TypedInput/typedInput.js b/js/src/ui/Form/TypedInput/typedInput.js new file mode 100644 index 000000000..6bcb5bbf1 --- /dev/null +++ b/js/src/ui/Form/TypedInput/typedInput.js @@ -0,0 +1,239 @@ +// Copyright 2015, 2016 Ethcore (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 . + +import React, { Component, PropTypes } from 'react'; +import { MenuItem } from 'material-ui'; +import { range } from 'lodash'; + +import IconButton from 'material-ui/IconButton'; +import AddIcon from 'material-ui/svg-icons/content/add'; +import RemoveIcon from 'material-ui/svg-icons/content/remove'; + +import { Input, InputAddressSelect, Select } from '../../../ui'; +import { ABI_TYPES } from '../../../util/abi'; + +import styles from './typedInput.css'; + +export default class TypedInput extends Component { + + static propTypes = { + onChange: PropTypes.func.isRequired, + accounts: PropTypes.object.isRequired, + param: PropTypes.object.isRequired, + + error: PropTypes.any, + value: PropTypes.any, + label: PropTypes.string + }; + + render () { + const { param } = this.props; + const { type } = param; + + if (type === ABI_TYPES.ARRAY) { + const { accounts, label, value = param.default } = this.props; + const { subtype, length } = param; + + const fixedLength = !!length; + + const inputs = range(length || value.length).map((_, index) => { + const onChange = (inputValue) => { + const newValues = [].concat(this.props.value); + newValues[index] = inputValue; + this.props.onChange(newValues); + }; + + return ( + + ); + }); + + return ( +
+ + { fixedLength ? null : this.renderLength() } + { inputs } +
+ ); + } + + return this.renderType(type); + } + + renderLength () { + const iconStyle = { + width: 16, + height: 16 + }; + + const style = { + width: 32, + height: 32, + padding: 0 + }; + + return ( +
+ + + + + + + +
+ ); + } + + renderType (type) { + if (type === ABI_TYPES.ADDRESS) { + return this.renderAddress(); + } + + if (type === ABI_TYPES.BOOL) { + return this.renderBoolean(); + } + + if (type === ABI_TYPES.STRING) { + return this.renderDefault(); + } + + if (type === ABI_TYPES.BYTES) { + return this.renderDefault(); + } + + if (type === ABI_TYPES.INT) { + return this.renderNumber(); + } + + if (type === ABI_TYPES.FIXED) { + return this.renderNumber(); + } + + return this.renderDefault(); + } + + renderNumber () { + const { label, value, error, param } = this.props; + + return ( + + ); + } + + renderDefault () { + const { label, value, error } = this.props; + + return ( + + ); + } + + renderAddress () { + const { accounts, label, value, error } = this.props; + + return ( + + ); + } + + renderBoolean () { + const { label, value, error } = this.props; + + const boolitems = ['false', 'true'].map((bool) => { + return ( + + { bool } + + ); + }); + + return ( + + ); + } + + onChangeBool = (event, _index, value) => { + this.props.onChange(value === 'true'); + } + + onChange = (event, value) => { + this.props.onChange(value); + } + + onSubmit = (value) => { + this.props.onChange(value); + } + + onAddField = () => { + const { value, onChange, param } = this.props; + const newValues = [].concat(value, param.subtype.default); + + onChange(newValues); + } + + onRemoveField = () => { + const { value, onChange } = this.props; + const newValues = value.slice(0, -1); + + onChange(newValues); + } + +} diff --git a/js/src/ui/Form/index.js b/js/src/ui/Form/index.js index 061cdddd0..46bb106f4 100644 --- a/js/src/ui/Form/index.js +++ b/js/src/ui/Form/index.js @@ -16,6 +16,7 @@ import AddressSelect from './AddressSelect'; import FormWrap from './FormWrap'; +import TypedInput from './TypedInput'; import Input from './Input'; import InputAddress from './InputAddress'; import InputAddressSelect from './InputAddressSelect'; @@ -27,6 +28,7 @@ export default from './form'; export { AddressSelect, FormWrap, + TypedInput, Input, InputAddress, InputAddressSelect, diff --git a/js/src/ui/index.js b/js/src/ui/index.js index ebfce3ad1..69a7d26c3 100644 --- a/js/src/ui/index.js +++ b/js/src/ui/index.js @@ -29,7 +29,7 @@ import ContextProvider from './ContextProvider'; import CopyToClipboard from './CopyToClipboard'; import Editor from './Editor'; import Errors from './Errors'; -import Form, { AddressSelect, FormWrap, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select } from './Form'; +import Form, { AddressSelect, FormWrap, TypedInput, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select } from './Form'; import IdentityIcon from './IdentityIcon'; import IdentityName from './IdentityName'; import MethodDecoding from './MethodDecoding'; @@ -62,6 +62,7 @@ export { Errors, Form, FormWrap, + TypedInput, Input, InputAddress, InputAddressSelect, diff --git a/js/src/util/abi.js b/js/src/util/abi.js new file mode 100644 index 000000000..9c6c597f5 --- /dev/null +++ b/js/src/util/abi.js @@ -0,0 +1,146 @@ +// Copyright 2015, 2016 Ethcore (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 . + +import { range } from 'lodash'; + +const ARRAY_TYPE = 'ARRAY_TYPE'; +const ADDRESS_TYPE = 'ADDRESS_TYPE'; +const STRING_TYPE = 'STRING_TYPE'; +const BOOL_TYPE = 'BOOL_TYPE'; +const BYTES_TYPE = 'BYTES_TYPE'; +const INT_TYPE = 'INT_TYPE'; +const FIXED_TYPE = 'FIXED_TYPE'; + +export const ABI_TYPES = { + ARRAY: ARRAY_TYPE, ADDRESS: ADDRESS_TYPE, + STRING: STRING_TYPE, BOOL: BOOL_TYPE, + BYTES: BYTES_TYPE, INT: INT_TYPE, + FIXED: FIXED_TYPE +}; + +export function parseAbiType (type) { + const arrayRegex = /^(.+)\[(\d*)\]$/; + + if (arrayRegex.test(type)) { + const matches = arrayRegex.exec(type); + + const subtype = parseAbiType(matches[1]); + const M = parseInt(matches[2]) || null; + const defaultValue = !M + ? [] + : range(M).map(() => subtype.default); + + return { + type: ARRAY_TYPE, + subtype: subtype, + length: M, + default: defaultValue + }; + } + + const lengthRegex = /^(u?int|bytes)(\d{1,3})$/; + + if (lengthRegex.test(type)) { + const matches = lengthRegex.exec(type); + + const subtype = parseAbiType(matches[1]); + const length = parseInt(matches[2]); + + return { + ...subtype, + length + }; + } + + const fixedLengthRegex = /^(u?fixed)(\d{1,3})x(\d{1,3})$/; + + if (fixedLengthRegex.test(type)) { + const matches = fixedLengthRegex.exec(type); + + const subtype = parseAbiType(matches[1]); + const M = parseInt(matches[2]); + const N = parseInt(matches[3]); + + return { + ...subtype, + M, N + }; + } + + if (type === 'string') { + return { + type: STRING_TYPE, + default: '' + }; + } + + if (type === 'bool') { + return { + type: BOOL_TYPE, + default: false + }; + } + + if (type === 'address') { + return { + type: ADDRESS_TYPE, + default: '0x' + }; + } + + if (type === 'bytes') { + return { + type: BYTES_TYPE, + default: '0x' + }; + } + + if (type === 'uint') { + return { + type: INT_TYPE, + default: 0, + length: 256, + signed: false + }; + } + + if (type === 'int') { + return { + type: INT_TYPE, + default: 0, + length: 256, + signed: true + }; + } + + if (type === 'ufixed') { + return { + type: FIXED_TYPE, + default: 0, + length: 256, + signed: false + }; + } + + if (type === 'fixed') { + return { + type: FIXED_TYPE, + default: 0, + length: 256, + signed: true + }; + } +} From 134622ea3ade5b2fa6bbb55735948d111561ca9e Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 14 Nov 2016 18:34:05 +0100 Subject: [PATCH 33/49] Adds error handler in Importer // Import AddressBook #2885 --- js/src/ui/Actionbar/Import/import.js | 34 +++++++++++-- js/src/ui/IdentityName/identityName.js | 12 +++-- js/src/views/Accounts/Summary/summary.js | 56 +++++++++++++++++---- js/src/views/Addresses/addresses.js | 64 +++++++++++++++++++++++- 4 files changed, 146 insertions(+), 20 deletions(-) diff --git a/js/src/ui/Actionbar/Import/import.js b/js/src/ui/Actionbar/Import/import.js index 776e5bb08..081fe1a17 100644 --- a/js/src/ui/Actionbar/Import/import.js +++ b/js/src/ui/Actionbar/Import/import.js @@ -29,6 +29,8 @@ const initialState = { show: false, validate: false, validationBody: null, + error: false, + errorText: '', content: '' }; @@ -65,7 +67,7 @@ export default class ActionbarImport extends Component { renderModal () { const { title, renderValidation } = this.props; - const { show, step } = this.state; + const { show, step, error } = this.state; if (!show) { return null; @@ -73,7 +75,7 @@ export default class ActionbarImport extends Component { const hasSteps = typeof renderValidation === 'function'; - const steps = hasSteps ? [ 'select a file', 'validate' ] : null; + const steps = hasSteps ? [ 'select a file', error ? 'error' : 'validate' ] : null; return ( ); + if (error) { + return [ cancelBtn ]; + } + if (validate) { const confirmBtn = (
+ ); + } if (validate) { return this.renderValidation(); @@ -169,10 +183,20 @@ export default class ActionbarImport extends Component { return this.onCloseModal(); } + const validationBody = renderValidation(content); + + if (validationBody && validationBody.error) { + return this.setState({ + step: 1, + error: true, + errorText: validationBody.error + }); + } + this.setState({ step: 1, validate: true, - validationBody: renderValidation(content), + validationBody, content }); }; diff --git a/js/src/ui/IdentityName/identityName.js b/js/src/ui/IdentityName/identityName.js index 6b6c75be2..f19e2bb2e 100644 --- a/js/src/ui/IdentityName/identityName.js +++ b/js/src/ui/IdentityName/identityName.js @@ -28,11 +28,12 @@ class IdentityName extends Component { tokens: PropTypes.object, empty: PropTypes.bool, shorten: PropTypes.bool, - unknown: PropTypes.bool + unknown: PropTypes.bool, + name: PropTypes.string } render () { - const { address, accountsInfo, tokens, empty, shorten, unknown, className } = this.props; + const { address, accountsInfo, tokens, empty, name, shorten, unknown, className } = this.props; const account = accountsInfo[address] || tokens[address]; const hasAccount = account && (!account.meta || !account.meta.deleted); @@ -43,13 +44,14 @@ class IdentityName extends Component { const addressFallback = shorten ? this.formatHash(address) : address; const fallback = unknown ? defaultName : addressFallback; const isUuid = hasAccount && account.name === account.uuid; - const name = hasAccount && !isUuid + const displayName = (name && name.toUpperCase().trim()) || + (hasAccount && !isUuid ? account.name.toUpperCase().trim() - : fallback; + : fallback); return ( - { name && name.length ? name : fallback } + { displayName && displayName.length ? displayName : fallback } ); } diff --git a/js/src/views/Accounts/Summary/summary.js b/js/src/views/Accounts/Summary/summary.js index 51bb81215..5a96f64ff 100644 --- a/js/src/views/Accounts/Summary/summary.js +++ b/js/src/views/Accounts/Summary/summary.js @@ -22,22 +22,28 @@ import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName, Tags, I export default class Summary extends Component { static contextTypes = { api: React.PropTypes.object - } + }; static propTypes = { account: PropTypes.object.isRequired, - balance: PropTypes.object.isRequired, + balance: PropTypes.object, link: PropTypes.string, + name: PropTypes.string, + noLink: PropTypes.bool, children: PropTypes.node, handleAddSearchToken: PropTypes.func - } + }; + + static defaultProps = { + noLink: false + }; state = { name: 'Unnamed' - } + }; render () { - const { account, balance, children, link, handleAddSearchToken } = this.props; + const { account, children, handleAddSearchToken } = this.props; const { tags } = account.meta; if (!account) { @@ -45,7 +51,6 @@ export default class Summary extends Component { } const { address } = account; - const viewLink = `/${link || 'account'}/${address}`; const addressComponent = ( { } } + title={ this.renderLink() } byline={ addressComponent } /> - + + { this.renderBalance() } { children } ); } + + renderLink () { + const { link, noLink, account, name } = this.props; + + const { address } = account; + const viewLink = `/${link || 'account'}/${address}`; + + const content = ( + + ); + + if (noLink) { + return content; + } + + return ( + + { content } + + ); + } + + renderBalance () { + const { balance } = this.props; + + if (!balance) { + return null; + } + + return ( + + ); + } } diff --git a/js/src/views/Addresses/addresses.js b/js/src/views/Addresses/addresses.js index 13c512713..0347f8fa2 100644 --- a/js/src/views/Addresses/addresses.js +++ b/js/src/views/Addresses/addresses.js @@ -21,8 +21,9 @@ import ContentAdd from 'material-ui/svg-icons/content/add'; import { uniq } from 'lodash'; import List from '../Accounts/List'; +import Summary from '../Accounts/Summary'; import { AddAddress } from '../../modals'; -import { Actionbar, ActionbarExport, ActionbarSearch, ActionbarSort, Button, Page } from '../../ui'; +import { Actionbar, ActionbarExport, ActionbarImport, ActionbarSearch, ActionbarSort, Button, Page } from '../../ui'; import styles from './addresses.css'; @@ -107,6 +108,12 @@ class Addresses extends Component { content={ contacts } filename='addressbook.json' />, + , + this.renderSearchButton(), this.renderSortButton() ]; @@ -134,6 +141,61 @@ class Addresses extends Component { ); } + renderValidation = (content) => { + let addresses; + + try { + addresses = JSON.parse(content); + } catch (e) { + return { + error: 'The provided file is invalid...' + }; + } + + const body = Object.values(addresses).map((address, index) => ( + + )); + + return ( +
+ { body } +
+ ); + } + + onImport = (content) => { + try { + const addresses = JSON.parse(content); + + Object.values(addresses).forEach((account) => { + this.onAddAccount(account); + }); + } catch (e) { + console.error('onImport', content, e); + } + } + + onAddAccount = (account) => { + const { api } = this.context; + const { address, name, meta } = account; + + Promise.all([ + api.parity.setAccountName(address, name), + api.parity.setAccountMeta(address, { + ...meta, + timestamp: Date.now(), + deleted: false + }) + ]).catch((error) => { + console.error('onAddAccount', error); + }); + } + onAddSearchToken = (token) => { const { searchTokens } = this.state; const newSearchTokens = uniq([].concat(searchTokens, token)); From 3bfa56c72a9890b97eb55e91be85a9388b122b34 Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Mon, 14 Nov 2016 17:48:20 +0000 Subject: [PATCH 34/49] [ci skip] js-precompiled 20161114-174654 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 487a8a40a..7a20e3dee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1249,7 +1249,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#1c7339e275e82608a0380824f675a666de0b9e83" +source = "git+https://github.com/ethcore/js-precompiled.git#610876fb2bb01705b81de14dd7e04d6a3cdf80ab" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index 6f3893bbb..6022072ea 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.40", + "version": "0.2.41", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 09ec0c1f2f62c2e0c26710b0af4d73dc5191a23c Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 14 Nov 2016 20:26:21 +0100 Subject: [PATCH 35/49] More robust import #2885 --- js/src/views/Addresses/addresses.js | 45 ++++++++++++++++------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/js/src/views/Addresses/addresses.js b/js/src/views/Addresses/addresses.js index 0347f8fa2..8b5fc0818 100644 --- a/js/src/views/Addresses/addresses.js +++ b/js/src/views/Addresses/addresses.js @@ -142,30 +142,35 @@ class Addresses extends Component { } renderValidation = (content) => { - let addresses; + const error = { + error: 'The provided file is invalid...' + }; try { - addresses = JSON.parse(content); - } catch (e) { - return { - error: 'The provided file is invalid...' - }; - } + const addresses = JSON.parse(content); - const body = Object.values(addresses).map((address, index) => ( - - )); + if (!addresses || Object.keys(addresses).length === 0) { + return error; + } - return ( -
- { body } -
- ); + const body = Object + .values(addresses) + .filter((account) => account && account.address) + .map((account, index) => ( + + )); + + return ( +
+ { body } +
+ ); + } catch (e) { return error; } } onImport = (content) => { From 53227276175a813dcad7f4d96fd82b3b5dd09c5b Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 14 Nov 2016 20:29:37 +0100 Subject: [PATCH 36/49] Fixing linting issues #3430 --- js/src/util/abi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/util/abi.js b/js/src/util/abi.js index 9c6c597f5..2d849f09d 100644 --- a/js/src/util/abi.js +++ b/js/src/util/abi.js @@ -32,7 +32,7 @@ export const ABI_TYPES = { }; export function parseAbiType (type) { - const arrayRegex = /^(.+)\[(\d*)\]$/; + const arrayRegex = /^(.+)\[(\d*)]$/; if (arrayRegex.test(type)) { const matches = arrayRegex.exec(type); From 85fdcc7bf30d1047b1a6095bd76ee0477e2f676e Mon Sep 17 00:00:00 2001 From: "Denis S. Soldatov aka General-Beck" Date: Mon, 14 Nov 2016 23:45:58 +0400 Subject: [PATCH 37/49] Update gitlab-ci remove -Zorbit=off switch to rust 1.13 --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 591807e24..1d152114c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -326,7 +326,7 @@ windows: - set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include;C:\vs2015\VC\include;C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt - set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64 - set RUST_BACKTRACE=1 - - set RUSTFLAGS=%RUSTFLAGS% -Zorbit=off + - set RUSTFLAGS=%RUSTFLAGS% - rustup default stable-x86_64-pc-windows-msvc - cargo build --release %CARGOFLAGS% - curl -sL --url "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll From c4885a14237dfc3ac31ab333dcc9c83dd202a032 Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Mon, 14 Nov 2016 20:11:54 +0000 Subject: [PATCH 38/49] [ci skip] js-precompiled 20161114-201022 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a20e3dee..2e6196014 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1249,7 +1249,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#610876fb2bb01705b81de14dd7e04d6a3cdf80ab" +source = "git+https://github.com/ethcore/js-precompiled.git#5555504896f109c2930838999b8915f44ee5ed27" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index 6022072ea..b0a543344 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.41", + "version": "0.2.42", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 9857f632d8e6a99d7e313f1d017572412479861c Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Tue, 15 Nov 2016 08:52:53 +0000 Subject: [PATCH 39/49] [ci skip] js-precompiled 20161115-085029 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e6196014..a93d2d551 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1249,7 +1249,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#5555504896f109c2930838999b8915f44ee5ed27" +source = "git+https://github.com/ethcore/js-precompiled.git#ce7e830d36483dab10419d9105ac39dc520e7a61" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index b0a543344..8829b6f8b 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.42", + "version": "0.2.43", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 6ea4b258591ed55fecfe3238d0e599175b59d492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Nov 2016 10:28:52 +0100 Subject: [PATCH 40/49] Create directories only if feature is enabled --- parity/blockchain.rs | 4 ++-- parity/dir.rs | 10 +++++++--- parity/run.rs | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 9575b293a..75a589d68 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -117,7 +117,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result { let panic_handler = PanicHandler::new_in_arc(); // create dirs used by parity - try!(cmd.dirs.create_dirs()); + try!(cmd.dirs.create_dirs(false, false)); // load spec file let spec = try!(cmd.spec.spec()); @@ -263,7 +263,7 @@ fn execute_export(cmd: ExportBlockchain) -> Result { let panic_handler = PanicHandler::new_in_arc(); // create dirs used by parity - try!(cmd.dirs.create_dirs()); + try!(cmd.dirs.create_dirs(false, false)); let format = cmd.format.unwrap_or_default(); diff --git a/parity/dir.rs b/parity/dir.rs index d7638e33b..b9c02efd6 100644 --- a/parity/dir.rs +++ b/parity/dir.rs @@ -44,11 +44,15 @@ impl Default for Directories { } impl Directories { - pub fn create_dirs(&self) -> Result<(), String> { + pub fn create_dirs(&self, dapps_enabled: bool, signer_enabled: bool) -> Result<(), String> { try!(fs::create_dir_all(&self.db).map_err(|e| e.to_string())); try!(fs::create_dir_all(&self.keys).map_err(|e| e.to_string())); - try!(fs::create_dir_all(&self.signer).map_err(|e| e.to_string())); - try!(fs::create_dir_all(&self.dapps).map_err(|e| e.to_string())); + if signer_enabled { + try!(fs::create_dir_all(&self.signer).map_err(|e| e.to_string())); + } + if dapps_enabled { + try!(fs::create_dir_all(&self.dapps).map_err(|e| e.to_string())); + } Ok(()) } diff --git a/parity/run.rs b/parity/run.rs index 56ff92c25..9fdd811de 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -110,7 +110,7 @@ pub fn execute(cmd: RunCmd, logger: Arc) -> Result<(), String> { raise_fd_limit(); // create dirs used by parity - try!(cmd.dirs.create_dirs()); + try!(cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.signer_conf.enabled)); // load spec let spec = try!(cmd.spec.spec()); From 3a013527440884fe7d1919ed15271ef5ab2228c8 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Tue, 15 Nov 2016 12:30:08 +0100 Subject: [PATCH 41/49] Use Contract owner for unregistering Token #3440 --- js/src/dapps/tokenreg/Status/reducer.js | 2 +- js/src/dapps/tokenreg/Tokens/actions.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/js/src/dapps/tokenreg/Status/reducer.js b/js/src/dapps/tokenreg/Status/reducer.js index 7b018bd85..357cb2244 100644 --- a/js/src/dapps/tokenreg/Status/reducer.js +++ b/js/src/dapps/tokenreg/Status/reducer.js @@ -25,7 +25,7 @@ const initialState = { isLoading: true, subscriptionId: null, contract: { - addres: null, + address: null, instance: null, raw: null, owner: null, diff --git a/js/src/dapps/tokenreg/Tokens/actions.js b/js/src/dapps/tokenreg/Tokens/actions.js index 7953bb241..bd4413163 100644 --- a/js/src/dapps/tokenreg/Tokens/actions.js +++ b/js/src/dapps/tokenreg/Tokens/actions.js @@ -239,22 +239,22 @@ export const addGithubhintURL = (from, key, url) => (dispatch, getState) => { export const unregisterToken = (index) => (dispatch, getState) => { console.log('unregistering token', index); - const state = getState(); - const contractInstance = state.status.contract.instance; + const { contract } = getState().status; + const { instance, owner } = contract; const values = [ index ]; const options = { - from: state.accounts.selected.address + from: owner }; - contractInstance + instance .unregister .estimateGas(options, values) .then((gasEstimate) => { options.gas = gasEstimate.mul(1.2).toFixed(0); console.log(`transfer: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`); - return contractInstance.unregister.postTransaction(options, values); + return instance.unregister.postTransaction(options, values); }) .catch((e) => { console.error(`unregisterToken #${index} error`, e); From 2b30d4b75f23363cb1cea0d9494a6ad9439ca47b Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Tue, 15 Nov 2016 12:35:50 +0100 Subject: [PATCH 42/49] Empty default Address Field #3395 --- js/src/util/abi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/util/abi.js b/js/src/util/abi.js index 2d849f09d..e7947233b 100644 --- a/js/src/util/abi.js +++ b/js/src/util/abi.js @@ -97,7 +97,7 @@ export function parseAbiType (type) { if (type === 'address') { return { type: ADDRESS_TYPE, - default: '0x' + default: '' }; } From 771ce13ddc1cfef2d3a378f0af7e93b79a7e7259 Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Tue, 15 Nov 2016 11:44:42 +0000 Subject: [PATCH 43/49] [ci skip] js-precompiled 20161115-114313 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a93d2d551..a418a1aeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1249,7 +1249,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#ce7e830d36483dab10419d9105ac39dc520e7a61" +source = "git+https://github.com/ethcore/js-precompiled.git#0094343aad80e3aa0883a0a134b02e1c6872abbe" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index 8829b6f8b..67774afba 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.43", + "version": "0.2.44", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 723005635a68e98fb9e960909e27467200c0c3ae Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Tue, 15 Nov 2016 12:50:20 +0100 Subject: [PATCH 44/49] Close and not Cancel on deploy contract #3393 --- js/src/abi/util/pad.js | 3 ++- js/src/modals/DeployContract/deployContract.js | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/js/src/abi/util/pad.js b/js/src/abi/util/pad.js index a7d940431..5a6751a4f 100644 --- a/js/src/abi/util/pad.js +++ b/js/src/abi/util/pad.js @@ -46,7 +46,8 @@ function stringToBytes (input) { if (isArray(input)) { return input; } else if (input.substr(0, 2) === '0x') { - return input.substr(2).toLowerCase().match(/.{1,2}/g).map((value) => parseInt(value, 16)); + const matches = input.substr(2).toLowerCase().match(/.{1,2}/g) || []; + return matches.map((value) => parseInt(value, 16)); } else { return input.split('').map((char) => char.charCodeAt(0)); } diff --git a/js/src/modals/DeployContract/deployContract.js b/js/src/modals/DeployContract/deployContract.js index 257ede1f1..952217edc 100644 --- a/js/src/modals/DeployContract/deployContract.js +++ b/js/src/modals/DeployContract/deployContract.js @@ -119,6 +119,13 @@ export default class DeployContract extends Component { onClick={ this.onClose } /> ); + const closeBtn = ( +
From 039bd3c9f93ed96388b707dd7af0dc3c5b5dae00 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Tue, 15 Nov 2016 16:46:48 +0100 Subject: [PATCH 49/49] Use Babel in vendor when needed #3419 (#3451) --- js/webpack.vendor.js | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/js/webpack.vendor.js b/js/webpack.vendor.js index 74a51dada..222f6ab4e 100644 --- a/js/webpack.vendor.js +++ b/js/webpack.vendor.js @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +const HappyPack = require('happypack'); const webpack = require('webpack'); const ENV = process.env.NODE_ENV || 'development'; @@ -22,10 +23,26 @@ const DEST = process.env.BUILD_DEST || '.build'; let modules = [ 'babel-polyfill', - 'browserify-aes', 'ethereumjs-tx', 'scryptsy', - 'react', 'react-dom', 'react-redux', 'react-router', - 'redux', 'redux-thunk', 'react-router-redux', - 'lodash', 'material-ui', 'moment', 'blockies' + 'bignumber.js', + 'blockies', + 'brace', + 'browserify-aes', + 'chart.js', + 'ethereumjs-tx', + 'lodash', + 'material-ui', + 'mobx', + 'mobx-react', + 'moment', + 'react', + 'react-dom', + 'react-redux', + 'react-router', + 'react-router-redux', + 'recharts', + 'redux', + 'redux-thunk', + 'scryptsy' ]; if (!isProd) { @@ -44,6 +61,11 @@ module.exports = { { test: /\.json$/, loaders: ['json'] + }, + { + test: /\.js$/, + include: /(ethereumjs-tx)/, + loaders: [ 'happypack/loader?id=js' ] } ] }, @@ -63,6 +85,12 @@ module.exports = { 'process.env': { NODE_ENV: JSON.stringify(ENV) } + }), + + new HappyPack({ + id: 'js', + threads: 4, + loaders: ['babel'] }) ];