Backporting to beta (#3229)

* Use ethcore_dappsPort when constructing URLs (#3139)

* Upon connect, retrieve the available api ports

* Update dapps to load from dappsPort

* Update dapps summary with dappsPort

* Allow proxy to use dappsPort

* Replace /api/ping with HEAD /

* Dynamic port for available apps

* Retrieve content images with dappsPort

* Fix /

* Transfer token dropdown image fix

* IdentityIcon loads images via contentHash

* Update apps fetch to cater for dev & prod

* DRY up 127.0.0.1:${dappsPort} with ${dappsUrl}

* Cleaning up polluted namespaces (#3143)

* Renaming ethcore_ to parity_

* Renaming files

* Renaming poluted EthSigning

* Tidy up the namespaces

* Renaming files to match new structure

* Splitting EthSigning into separate traits

* jsapi move ethcore.* -> parity.*

* Move jsonrpc parity definitions

* Update UI API calls for parity interfaces

* Move jsapi signer interfaces from personal to signer

* Update UI to use signer.* where applicable

* Updsate jsapi subscriptions for signer

* Fix dodgy merge.

* Update README.

* Fix some tests.

* Move parity-only personal.* to parity.*

* Update UI for personal -> parity API moves

* Update subscription APIs after personal -> parity move

* personal. generateAuthorizationToken -> parity. generateAuthorizationToken (UI)

* enode, dappsPort & signerPort (UI)

* Update subscription tests (accountsInfo)

* subscription update

* personal -> parity

* Additional error logging on method failures

* move postTransaction to parity

* Additional debug info with method failures

* Fix personal tests.

* Console wrning shows parameters, error object does not

* Include parity_ signing methods.

* Console log http transport info

* Fix failing tests

* Add RPC stubs for parity_accounts.

* Allow some secure built-in dapps

* Use parity_accounts in place of accountsInfo

* Improve error reporting

* Cleanup GHH error handling


Former-commit-id: 5a094ccb9f0596d0e07abc23504b80dc099ad584
This commit is contained in:
Arkadiy Paronyan 2016-11-07 14:46:41 +01:00 committed by GitHub
parent aea995cf55
commit 043ca21863
106 changed files with 1974 additions and 1485 deletions

View File

@ -1,9 +1,12 @@
# [Parity](https://ethcore.io/parity.html)
### Fast, light, and robust Ethereum implementation
[![Join the chat at https://gitter.im/ethcore/parity.js](https://badges.gitter.im/ethcore/parity.js.svg)](https://gitter.im/ethcore/parity.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status][travis-image]][travis-url] [![build status](https://gitlab.ethcore.io/Mirrors/ethcore-parity/badges/master/build.svg)](https://gitlab.ethcore.io/Mirrors/ethcore-parity/commits/master) [![Coverage Status][coveralls-image]][coveralls-url] [![GPLv3][license-image]][license-url]
[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/ethcore/parity][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url]
### Join the chat!
Parity [![Join the chat at https://gitter.im/ethcore/parity][gitter-image]][gitter-url] and
parity.js [![Join the chat at https://gitter.im/ethcore/parity.js](https://badges.gitter.im/ethcore/parity.js.svg)](https://gitter.im/ethcore/parity.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[Internal Documentation][doc-url]
@ -21,7 +24,7 @@ Be sure to check out [our wiki][wiki-url] for more information.
[doc-url]: https://ethcore.github.io/parity/ethcore/index.html
[wiki-url]: https://github.com/ethcore/parity/wiki
**Requires Rust version 1.12.0 to build**
**Parity requires Rust version 1.12.0 to build**
----
@ -31,12 +34,15 @@ Be sure to check out [our wiki][wiki-url] for more information.
Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and
cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs.
By default, Parity will run a JSONRPC server on `127.0.0.1:8545`. This is fully configurable and supports a number
of RPC APIs.
Parity comes with a built-in wallet. To access [Parity Wallet](http://127.0.0.1:8080/) this simply go to http://127.0.0.1:8080/. It
includes various functionality allowing you to:
- create and manage your Ethereum accounts;
- manage your Ether and any Ethereum tokens;
- create and register your own tokens;
- and much more.
Parity also runs a server for running decentralized apps, or "Dapps", on `http://127.0.0.1:8080`.
This includes a few useful Dapps, including Ethereum Wallet, Maker OTC, and a node status page.
In a near-future release, it will be easy to install Dapps and use them through this web interface.
By default, Parity will also run a JSONRPC server on `127.0.0.1:8545`. This is fully configurable and supports a number
of RPC APIs.
If you run into an issue while using parity, feel free to file one in this repository
or hop on our [gitter chat room][gitter-url] to ask a question. We are glad to help!

View File

@ -135,10 +135,11 @@ APIs implement the calls as exposed in the [Ethcore JSON Ethereum RPC](https://g
- [ethapi.db](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#db)
- [ethapi.eth](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#eth)
- [ethapi.ethcore](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#ethcore)
- [ethapi.parity](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#parity)
- [ethapi.net](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#net)
- [ethapi.personal](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#personal)
- [ethapi.shh](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#shh)
- [ethapi.signer](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#signer)
- [ethapi.trace](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#trace)
- [ethapi.web3](https://github.com/ethcore/ethereum-rpc-json/blob/master/interfaces.md#web3)

View File

@ -17,7 +17,7 @@
import { Http, Ws } from './transport';
import Contract from './contract';
import { Db, Eth, Ethcore, Net, Personal, Shh, Trace, Web3 } from './rpc';
import { Db, Eth, Parity, Net, Personal, Shh, Signer, Trace, Web3 } from './rpc';
import Subscriptions from './subscriptions';
import util from './util';
import { isFunction } from './util/types';
@ -32,10 +32,11 @@ export default class Api {
this._db = new Db(transport);
this._eth = new Eth(transport);
this._ethcore = new Ethcore(transport);
this._net = new Net(transport);
this._parity = new Parity(transport);
this._personal = new Personal(transport);
this._shh = new Shh(transport);
this._signer = new Signer(transport);
this._trace = new Trace(transport);
this._web3 = new Web3(transport);
@ -50,8 +51,8 @@ export default class Api {
return this._eth;
}
get ethcore () {
return this._ethcore;
get parity () {
return this._parity;
}
get net () {
@ -66,6 +67,10 @@ export default class Api {
return this._shh;
}
get signer () {
return this._signer;
}
get trace () {
return this._trace;
}

View File

@ -102,7 +102,7 @@ export default class Contract {
options.gas = gas.toFixed(0);
setState({ state: 'postTransaction', gas });
return this._api.eth.postTransaction(this._encodeOptions(this.constructors[0], options, values));
return this._api.parity.postTransaction(this._encodeOptions(this.constructors[0], options, values));
})
.then((requestId) => {
setState({ state: 'checkRequest', requestId });
@ -166,7 +166,7 @@ export default class Contract {
}
_pollCheckRequest = (requestId) => {
return this._api.pollMethod('eth_checkRequest', requestId);
return this._api.pollMethod('parity_checkRequest', requestId);
}
_pollTransactionReceipt = (txhash, gas) => {
@ -208,7 +208,7 @@ export default class Contract {
if (!func.constant) {
func.postTransaction = (options, values = []) => {
return this._api.eth
return this._api.parity
.postTransaction(this._encodeOptions(func, this._addOptionsTo(options), values));
};

View File

@ -249,9 +249,9 @@ describe('api/contract/Contract', () => {
before(() => {
scope = mockHttp([
{ method: 'eth_estimateGas', reply: { result: 1000 } },
{ method: 'eth_postTransaction', reply: { result: '0x678' } },
{ method: 'eth_checkRequest', reply: { result: null } },
{ method: 'eth_checkRequest', reply: { result: '0x890' } },
{ method: 'parity_postTransaction', reply: { result: '0x678' } },
{ method: 'parity_checkRequest', reply: { result: null } },
{ method: 'parity_checkRequest', reply: { result: '0x890' } },
{ method: 'eth_getTransactionReceipt', reply: { result: null } },
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_PEND } },
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_DONE } },
@ -266,7 +266,7 @@ describe('api/contract/Contract', () => {
});
it('passes the options through to postTransaction (incl. gas calculation)', () => {
expect(scope.body.eth_postTransaction.params).to.deep.equal([
expect(scope.body.parity_postTransaction.params).to.deep.equal([
{ data: '0x123', gas: '0x4b0' }
]);
});
@ -280,8 +280,8 @@ describe('api/contract/Contract', () => {
it('fails when gasUsed == gas', () => {
mockHttp([
{ method: 'eth_estimateGas', reply: { result: 1000 } },
{ method: 'eth_postTransaction', reply: { result: '0x678' } },
{ method: 'eth_checkRequest', reply: { result: '0x789' } },
{ method: 'parity_postTransaction', reply: { result: '0x678' } },
{ method: 'parity_checkRequest', reply: { result: '0x789' } },
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_EXCP } }
]);
@ -295,8 +295,8 @@ describe('api/contract/Contract', () => {
it('fails when no code was deployed', () => {
mockHttp([
{ method: 'eth_estimateGas', reply: { result: 1000 } },
{ method: 'eth_postTransaction', reply: { result: '0x678' } },
{ method: 'eth_checkRequest', reply: { result: '0x789' } },
{ method: 'parity_postTransaction', reply: { result: '0x678' } },
{ method: 'parity_checkRequest', reply: { result: '0x789' } },
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_DONE } },
{ method: 'eth_getCode', reply: { result: '0x' } }
]);
@ -360,15 +360,15 @@ describe('api/contract/Contract', () => {
describe('postTransaction', () => {
beforeEach(() => {
scope = mockHttp([{ method: 'eth_postTransaction', reply: { result: ['hashId'] } }]);
scope = mockHttp([{ method: 'parity_postTransaction', reply: { result: ['hashId'] } }]);
});
it('encodes options and mades an eth_postTransaction call', () => {
it('encodes options and mades an parity_postTransaction call', () => {
return func
.postTransaction({ someExtras: 'foo' }, VALUES)
.then(() => {
expect(scope.isDone()).to.be.true;
expect(scope.body.eth_postTransaction.params[0]).to.deep.equal({
expect(scope.body.parity_postTransaction.params[0]).to.deep.equal({
someExtras: 'foo',
to: ADDR,
data: ENCODED

View File

@ -39,11 +39,6 @@ export default class Eth {
.execute('eth_call', inOptions(options), inBlockNumber(blockNumber));
}
checkRequest (requestId) {
return this._transport
.execute('eth_checkRequest', inNumber16(requestId));
}
coinbase () {
return this._transport
.execute('eth_coinbase')
@ -267,11 +262,6 @@ export default class Eth {
.execute('eth_pendingTransactions');
}
postTransaction (options) {
return this._transport
.execute('eth_postTransaction', inOptions(options));
}
protocolVersion () {
return this._transport
.execute('eth_protocolVersion');

View File

@ -1,201 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
import { inAddress, inData, inNumber16 } from '../../format/input';
import { outAddress, outHistogram, outNumber, outPeers } from '../../format/output';
export default class Ethcore {
constructor (transport) {
this._transport = transport;
}
acceptNonReservedPeers () {
return this._transport
.execute('ethcore_acceptNonReservedPeers');
}
addReservedPeer (encode) {
return this._transport
.execute('ethcore_addReservedPeer', encode);
}
dappsPort () {
return this._transport
.execute('ethcore_dappsPort')
.then(outNumber);
}
defaultExtraData () {
return this._transport
.execute('ethcore_defaultExtraData');
}
devLogs () {
return this._transport
.execute('ethcore_devLogs');
}
devLogsLevels () {
return this._transport
.execute('ethcore_devLogsLevels');
}
dropNonReservedPeers () {
return this._transport
.execute('ethcore_dropNonReservedPeers');
}
enode () {
return this._transport
.execute('ethcore_enode');
}
extraData () {
return this._transport
.execute('ethcore_extraData');
}
gasFloorTarget () {
return this._transport
.execute('ethcore_gasFloorTarget')
.then(outNumber);
}
gasPriceHistogram () {
return this._transport
.execute('ethcore_gasPriceHistogram')
.then(outHistogram);
}
generateSecretPhrase () {
return this._transport
.execute('ethcore_generateSecretPhrase');
}
hashContent (url) {
return this._transport
.execute('ethcore_hashContent', url);
}
minGasPrice () {
return this._transport
.execute('ethcore_minGasPrice')
.then(outNumber);
}
mode () {
return this._transport
.execute('ethcore_mode');
}
netChain () {
return this._transport
.execute('ethcore_netChain');
}
netPeers () {
return this._transport
.execute('ethcore_netPeers')
.then(outPeers);
}
netMaxPeers () {
return this._transport
.execute('ethcore_netMaxPeers')
.then(outNumber);
}
netPort () {
return this._transport
.execute('ethcore_netPort')
.then(outNumber);
}
nodeName () {
return this._transport
.execute('ethcore_nodeName');
}
phraseToAddress (phrase) {
return this._transport
.execute('ethcore_phraseToAddress', phrase)
.then(outAddress);
}
registryAddress () {
return this._transport
.execute('ethcore_registryAddress')
.then(outAddress);
}
removeReservedPeer (encode) {
return this._transport
.execute('ethcore_removeReservedPeer', encode);
}
rpcSettings () {
return this._transport
.execute('ethcore_rpcSettings');
}
setAuthor (address) {
return this._transport
.execute('ethcore_setAuthor', inAddress(address));
}
setExtraData (data) {
return this._transport
.execute('ethcore_setExtraData', inData(data));
}
setGasFloorTarget (quantity) {
return this._transport
.execute('ethcore_setGasFloorTarget', inNumber16(quantity));
}
setMinGasPrice (quantity) {
return this._transport
.execute('ethcore_setMinGasPrice', inNumber16(quantity));
}
setMode (mode) {
return this._transport
.execute('ethcore_setMode', mode);
}
setTransactionsLimit (quantity) {
return this._transport
.execute('ethcore_setTransactionsLimit', inNumber16(quantity));
}
signerPort () {
return this._transport
.execute('ethcore_signerPort')
.then(outNumber);
}
transactionsLimit () {
return this._transport
.execute('ethcore_transactionsLimit')
.then(outNumber);
}
unsignedTransactionsCount () {
return this._transport
.execute('ethcore_unsignedTransactionsCount')
.then(outNumber);
}
}

View File

@ -16,9 +16,10 @@
export Db from './db';
export Eth from './eth';
export Ethcore from './ethcore';
export Parity from './parity';
export Net from './net';
export Personal from './personal';
export Shh from './shh';
export Signer from './signer';
export Trace from './trace';
export Web3 from './web3';

View File

@ -14,4 +14,4 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './ethcore';
export default from './parity';

View File

@ -16,12 +16,12 @@
import { createHttpApi } from '../../../../test/e2e/ethapi';
describe('ethapi.ethcore', () => {
describe('ethapi.parity', () => {
const ethapi = createHttpApi();
describe('gasFloorTarget', () => {
it('returns and translates the target', () => {
return ethapi.ethcore.gasFloorTarget().then((value) => {
return ethapi.parity.gasFloorTarget().then((value) => {
expect(value.gt(0)).to.be.true;
});
});
@ -29,7 +29,7 @@ describe('ethapi.ethcore', () => {
describe('gasPriceHistogram', () => {
it('returns and translates the target', () => {
return ethapi.ethcore.gasPriceHistogram().then((result) => {
return ethapi.parity.gasPriceHistogram().then((result) => {
expect(Object.keys(result)).to.deep.equal(['bucketBounds', 'counts']);
expect(result.bucketBounds.length > 0).to.be.true;
expect(result.counts.length > 0).to.be.true;
@ -39,7 +39,7 @@ describe('ethapi.ethcore', () => {
describe('netChain', () => {
it('returns and the chain', () => {
return ethapi.ethcore.netChain().then((value) => {
return ethapi.parity.netChain().then((value) => {
expect(value).to.equal('morden');
});
});
@ -47,7 +47,7 @@ describe('ethapi.ethcore', () => {
describe('netPort', () => {
it('returns and translates the port', () => {
return ethapi.ethcore.netPort().then((value) => {
return ethapi.parity.netPort().then((value) => {
expect(value.gt(0)).to.be.true;
});
});
@ -55,7 +55,7 @@ describe('ethapi.ethcore', () => {
describe('transactionsLimit', () => {
it('returns and translates the limit', () => {
return ethapi.ethcore.transactionsLimit().then((value) => {
return ethapi.parity.transactionsLimit().then((value) => {
expect(value.gt(0)).to.be.true;
});
});
@ -63,7 +63,7 @@ describe('ethapi.ethcore', () => {
describe('rpcSettings', () => {
it('returns and translates the settings', () => {
return ethapi.ethcore.rpcSettings().then((value) => {
return ethapi.parity.rpcSettings().then((value) => {
expect(value).to.be.ok;
});
});

View File

@ -0,0 +1,273 @@
// 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 <http://www.gnu.org/licenses/>.
import { inAddress, inData, inHex, inNumber16, inOptions } from '../../format/input';
import { outAccountInfo, outAddress, outHistogram, outNumber, outPeers } from '../../format/output';
export default class Parity {
constructor (transport) {
this._transport = transport;
}
acceptNonReservedPeers () {
return this._transport
.execute('parity_acceptNonReservedPeers');
}
accounts () {
return this._transport
.execute('parity_accounts')
.then(outAccountInfo);
}
accountsInfo () {
return this._transport
.execute('parity_accountsInfo')
.then(outAccountInfo);
}
addReservedPeer (encode) {
return this._transport
.execute('parity_addReservedPeer', encode);
}
changePassword (account, password, newPassword) {
return this._transport
.execute('parity_changePassword', inAddress(account), password, newPassword);
}
checkRequest (requestId) {
return this._transport
.execute('parity_checkRequest', inNumber16(requestId));
}
dappsPort () {
return this._transport
.execute('parity_dappsPort')
.then(outNumber);
}
defaultExtraData () {
return this._transport
.execute('parity_defaultExtraData');
}
devLogs () {
return this._transport
.execute('parity_devLogs');
}
devLogsLevels () {
return this._transport
.execute('parity_devLogsLevels');
}
dropNonReservedPeers () {
return this._transport
.execute('parity_dropNonReservedPeers');
}
enode () {
return this._transport
.execute('parity_enode');
}
extraData () {
return this._transport
.execute('parity_extraData');
}
gasFloorTarget () {
return this._transport
.execute('parity_gasFloorTarget')
.then(outNumber);
}
gasPriceHistogram () {
return this._transport
.execute('parity_gasPriceHistogram')
.then(outHistogram);
}
generateSecretPhrase () {
return this._transport
.execute('parity_generateSecretPhrase');
}
hashContent (url) {
return this._transport
.execute('parity_hashContent', url);
}
listGethAccounts () {
return this._transport
.execute('parity_listGethAccounts')
.then((accounts) => (accounts || []).map(outAddress));
}
importGethAccounts (accounts) {
return this._transport
.execute('parity_importGethAccounts', (accounts || []).map(inAddress))
.then((accounts) => (accounts || []).map(outAddress));
}
minGasPrice () {
return this._transport
.execute('parity_minGasPrice')
.then(outNumber);
}
mode () {
return this._transport
.execute('parity_mode');
}
netChain () {
return this._transport
.execute('parity_netChain');
}
netPeers () {
return this._transport
.execute('parity_netPeers')
.then(outPeers);
}
netMaxPeers () {
return this._transport
.execute('parity_netMaxPeers')
.then(outNumber);
}
netPort () {
return this._transport
.execute('parity_netPort')
.then(outNumber);
}
newAccountFromPhrase (phrase, password) {
return this._transport
.execute('parity_newAccountFromPhrase', phrase, password)
.then(outAddress);
}
newAccountFromSecret (secret, password) {
return this._transport
.execute('parity_newAccountFromSecret', inHex(secret), password)
.then(outAddress);
}
newAccountFromWallet (json, password) {
return this._transport
.execute('parity_newAccountFromWallet', json, password)
.then(outAddress);
}
nodeName () {
return this._transport
.execute('parity_nodeName');
}
phraseToAddress (phrase) {
return this._transport
.execute('parity_phraseToAddress', phrase)
.then(outAddress);
}
postTransaction (options) {
return this._transport
.execute('parity_postTransaction', inOptions(options));
}
registryAddress () {
return this._transport
.execute('parity_registryAddress')
.then(outAddress);
}
removeReservedPeer (encode) {
return this._transport
.execute('parity_removeReservedPeer', encode);
}
rpcSettings () {
return this._transport
.execute('parity_rpcSettings');
}
setAccountName (address, name) {
return this._transport
.execute('parity_setAccountName', inAddress(address), name);
}
setAccountMeta (address, meta) {
return this._transport
.execute('parity_setAccountMeta', inAddress(address), JSON.stringify(meta));
}
setAuthor (address) {
return this._transport
.execute('parity_setAuthor', inAddress(address));
}
setExtraData (data) {
return this._transport
.execute('parity_setExtraData', inData(data));
}
setGasFloorTarget (quantity) {
return this._transport
.execute('parity_setGasFloorTarget', inNumber16(quantity));
}
setMinGasPrice (quantity) {
return this._transport
.execute('parity_setMinGasPrice', inNumber16(quantity));
}
setMode (mode) {
return this._transport
.execute('parity_setMode', mode);
}
setTransactionsLimit (quantity) {
return this._transport
.execute('parity_setTransactionsLimit', inNumber16(quantity));
}
signerPort () {
return this._transport
.execute('parity_signerPort')
.then(outNumber);
}
testPassword (account, password) {
return this._transport
.execute('parity_testPassword', inAddress(account), password);
}
transactionsLimit () {
return this._transport
.execute('parity_transactionsLimit')
.then(outNumber);
}
unsignedTransactionsCount () {
return this._transport
.execute('parity_unsignedTransactionsCount')
.then(outNumber);
}
}

View File

@ -18,14 +18,36 @@ import { TEST_HTTP_URL, mockHttp } from '../../../../test/mockRpc';
import { isBigNumber } from '../../../../test/types';
import Http from '../../transport/http';
import Ethcore from './ethcore';
import Parity from './parity';
const instance = new Ethcore(new Http(TEST_HTTP_URL));
const instance = new Parity(new Http(TEST_HTTP_URL));
describe('api/rpc/parity', () => {
describe('accountsInfo', () => {
it('retrieves the available account info', () => {
mockHttp([{ method: 'parity_accountsInfo', reply: {
result: {
'0x63cf90d3f0410092fc0fca41846f596223979195': {
name: 'name', uuid: 'uuid', meta: '{"data":"data"}'
}
}
} }]);
return instance.accountsInfo().then((result) => {
expect(result).to.deep.equal({
'0x63Cf90D3f0410092FC0fca41846f596223979195': {
name: 'name', uuid: 'uuid', meta: {
data: 'data'
}
}
});
});
});
});
describe('api/rpc/Ethcore', () => {
describe('gasFloorTarget', () => {
it('returns the gasfloor, formatted', () => {
mockHttp([{ method: 'ethcore_gasFloorTarget', reply: { result: '0x123456' } }]);
mockHttp([{ method: 'parity_gasFloorTarget', reply: { result: '0x123456' } }]);
return instance.gasFloorTarget().then((count) => {
expect(isBigNumber(count)).to.be.true;
@ -36,7 +58,7 @@ describe('api/rpc/Ethcore', () => {
describe('minGasPrice', () => {
it('returns the min gasprice, formatted', () => {
mockHttp([{ method: 'ethcore_minGasPrice', reply: { result: '0x123456' } }]);
mockHttp([{ method: 'parity_minGasPrice', reply: { result: '0x123456' } }]);
return instance.minGasPrice().then((count) => {
expect(isBigNumber(count)).to.be.true;
@ -47,7 +69,7 @@ describe('api/rpc/Ethcore', () => {
describe('netMaxPeers', () => {
it('returns the max peers, formatted', () => {
mockHttp([{ method: 'ethcore_netMaxPeers', reply: { result: 25 } }]);
mockHttp([{ method: 'parity_netMaxPeers', reply: { result: 25 } }]);
return instance.netMaxPeers().then((count) => {
expect(isBigNumber(count)).to.be.true;
@ -58,7 +80,7 @@ describe('api/rpc/Ethcore', () => {
describe('newPeers', () => {
it('returns the peer structure, formatted', () => {
mockHttp([{ method: 'ethcore_netPeers', reply: { result: { active: 123, connected: 456, max: 789 } } }]);
mockHttp([{ method: 'parity_netPeers', reply: { result: { active: 123, connected: 456, max: 789 } } }]);
return instance.netPeers().then((peers) => {
expect(peers.active.eq(123)).to.be.true;
@ -70,7 +92,7 @@ describe('api/rpc/Ethcore', () => {
describe('netPort', () => {
it('returns the connected port, formatted', () => {
mockHttp([{ method: 'ethcore_netPort', reply: { result: 33030 } }]);
mockHttp([{ method: 'parity_netPort', reply: { result: 33030 } }]);
return instance.netPort().then((count) => {
expect(isBigNumber(count)).to.be.true;
@ -81,7 +103,7 @@ describe('api/rpc/Ethcore', () => {
describe('transactionsLimit', () => {
it('returns the tx limit, formatted', () => {
mockHttp([{ method: 'ethcore_transactionsLimit', reply: { result: 1024 } }]);
mockHttp([{ method: 'parity_transactionsLimit', reply: { result: 1024 } }]);
return instance.transactionsLimit().then((count) => {
expect(isBigNumber(count)).to.be.true;

View File

@ -14,113 +14,31 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { inAddress, inHex, inNumber10, inNumber16, inOptions } from '../../format/input';
import { outAccountInfo, outAddress, outSignerRequest } from '../../format/output';
import { inAddress, inNumber10, inOptions } from '../../format/input';
import { outAddress } from '../../format/output';
export default class Personal {
constructor (transport) {
this._transport = transport;
}
accountsInfo () {
return this._transport
.execute('personal_accountsInfo')
.then(outAccountInfo);
}
confirmRequest (requestId, options, password) {
return this._transport
.execute('personal_confirmRequest', inNumber16(requestId), options, password);
}
changePassword (account, password, newPassword) {
return this._transport
.execute('personal_changePassword', inAddress(account), password, newPassword);
}
generateAuthorizationToken () {
return this._transport
.execute('personal_generateAuthorizationToken');
}
listAccounts () {
return this._transport
.execute('personal_listAccounts')
.then((accounts) => (accounts || []).map(outAddress));
}
listGethAccounts () {
return this._transport
.execute('personal_listGethAccounts')
.then((accounts) => (accounts || []).map(outAddress));
}
importGethAccounts (accounts) {
return this._transport
.execute('personal_importGethAccounts', (accounts || []).map(inAddress))
.then((accounts) => (accounts || []).map(outAddress));
}
newAccount (password) {
return this._transport
.execute('personal_newAccount', password)
.then(outAddress);
}
newAccountFromPhrase (phrase, password) {
return this._transport
.execute('personal_newAccountFromPhrase', phrase, password)
.then(outAddress);
}
newAccountFromSecret (secret, password) {
return this._transport
.execute('personal_newAccountFromSecret', inHex(secret), password)
.then(outAddress);
}
newAccountFromWallet (json, password) {
return this._transport
.execute('personal_newAccountFromWallet', json, password)
.then(outAddress);
}
rejectRequest (requestId) {
return this._transport
.execute('personal_rejectRequest', inNumber16(requestId));
}
requestsToConfirm () {
return this._transport
.execute('personal_requestsToConfirm')
.then((requests) => (requests || []).map(outSignerRequest));
}
setAccountName (address, name) {
return this._transport
.execute('personal_setAccountName', inAddress(address), name);
}
setAccountMeta (address, meta) {
return this._transport
.execute('personal_setAccountMeta', inAddress(address), JSON.stringify(meta));
}
signAndSendTransaction (options, password) {
return this._transport
.execute('personal_signAndSendTransaction', inOptions(options), password);
}
signerEnabled () {
return this._transport
.execute('personal_signerEnabled');
}
testPassword (account, password) {
return this._transport
.execute('personal_testPassword', inAddress(account), password);
}
unlockAccount (account, password, duration = 1) {
return this._transport
.execute('personal_unlockAccount', inAddress(account), password, inNumber10(duration));

View File

@ -26,28 +26,6 @@ describe('rpc/Personal', () => {
const checksum = '0x63Cf90D3f0410092FC0fca41846f596223979195';
let scope;
describe('accountsInfo', () => {
it('retrieves the available account info', () => {
scope = mockHttp([{ method: 'personal_accountsInfo', reply: {
result: {
'0x63cf90d3f0410092fc0fca41846f596223979195': {
name: 'name', uuid: 'uuid', meta: '{"data":"data"}'
}
}
} }]);
return instance.accountsInfo().then((result) => {
expect(result).to.deep.equal({
'0x63Cf90D3f0410092FC0fca41846f596223979195': {
name: 'name', uuid: 'uuid', meta: {
data: 'data'
}
}
});
});
});
});
describe('listAccounts', () => {
it('retrieves a list of available accounts', () => {
scope = mockHttp([{ method: 'personal_listAccounts', reply: { result: [account] } }]);

View File

@ -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 <http://www.gnu.org/licenses/>.
export default from './signer';

View File

@ -0,0 +1,50 @@
// 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 <http://www.gnu.org/licenses/>.
import { inNumber16 } from '../../format/input';
import { outSignerRequest } from '../../format/output';
export default class Signer {
constructor (transport) {
this._transport = transport;
}
confirmRequest (requestId, options, password) {
return this._transport
.execute('signer_confirmRequest', inNumber16(requestId), options, password);
}
generateAuthorizationToken () {
return this._transport
.execute('signer_generateAuthorizationToken');
}
rejectRequest (requestId) {
return this._transport
.execute('signer_rejectRequest', inNumber16(requestId));
}
requestsToConfirm () {
return this._transport
.execute('signer_requestsToConfirm')
.then((requests) => (requests || []).map(outSignerRequest));
}
signerEnabled () {
return this._transport
.execute('signer_signerEnabled');
}
}

View File

@ -24,9 +24,9 @@ import Signer from './signer';
const events = {
'logging': { module: 'logging' },
'eth_blockNumber': { module: 'eth' },
'personal_accountsInfo': { module: 'personal' },
'personal_listAccounts': { module: 'personal' },
'personal_requestsToConfirm': { module: 'signer' }
'parity_accountsInfo': { module: 'personal' },
'eth_accounts': { module: 'personal' },
'signer_requestsToConfirm': { module: 'signer' }
};
export default class Manager {

View File

@ -37,18 +37,18 @@ export default class Personal {
}
_listAccounts = () => {
return this._api.personal
.listAccounts()
return this._api.eth
.accounts()
.then((accounts) => {
this._updateSubscriptions('personal_listAccounts', null, accounts);
this._updateSubscriptions('eth_accounts', null, accounts);
});
}
_accountsInfo = () => {
return this._api.personal
return this._api.parity
.accountsInfo()
.then((info) => {
this._updateSubscriptions('personal_accountsInfo', null, info);
this._updateSubscriptions('parity_accountsInfo', null, info);
});
}
@ -59,16 +59,16 @@ export default class Personal {
}
switch (data.method) {
case 'personal_importGethAccounts':
case 'parity_importGethAccounts':
case 'personal_newAccount':
case 'personal_newAccountFromPhrase':
case 'personal_newAccountFromWallet':
case 'parity_newAccountFromPhrase':
case 'parity_newAccountFromWallet':
this._listAccounts();
this._accountsInfo();
return;
case 'personal_setAccountName':
case 'personal_setAccountMeta':
case 'parity_setAccountName':
case 'parity_setAccountMeta':
this._accountsInfo();
return;
}

View File

@ -34,14 +34,15 @@ function stubApi (accounts, info) {
return {
_calls,
personal: {
parity: {
accountsInfo: () => {
const stub = sinon.stub().resolves(info || TEST_INFO)();
_calls.accountsInfo.push(stub);
return stub;
},
listAccounts: () => {
}
},
eth: {
accounts: () => {
const stub = sinon.stub().resolves(accounts || TEST_LIST)();
_calls.listAccounts.push(stub);
return stub;
@ -85,17 +86,17 @@ describe('api/subscriptions/personal', () => {
expect(personal.isStarted).to.be.true;
});
it('calls personal_accountsInfo', () => {
it('calls parity_accountsInfo', () => {
expect(api._calls.accountsInfo.length).to.be.ok;
});
it('calls personal_listAccounts', () => {
it('calls eth_accounts', () => {
expect(api._calls.listAccounts.length).to.be.ok;
});
it('updates subscribers', () => {
expect(cb.firstCall).to.have.been.calledWith('personal_listAccounts', null, TEST_LIST);
expect(cb.secondCall).to.have.been.calledWith('personal_accountsInfo', null, TEST_INFO);
expect(cb.firstCall).to.have.been.calledWith('eth_accounts', null, TEST_LIST);
expect(cb.secondCall).to.have.been.calledWith('parity_accountsInfo', null, TEST_INFO);
});
});

View File

@ -49,10 +49,10 @@ export default class Signer {
return;
}
return this._api.personal
return this._api.signer
.requestsToConfirm()
.then((requests) => {
this._updateSubscriptions('personal_requestsToConfirm', null, requests);
this._updateSubscriptions('signer_requestsToConfirm', null, requests);
nextTimeout();
})
.catch(nextTimeout);
@ -65,7 +65,7 @@ export default class Signer {
}
switch (data.method) {
case 'eth_postTransaction':
case 'parity_postTransaction':
case 'eth_sendTranasction':
case 'eth_sendRawTransaction':
this._listRequests(false);

View File

@ -56,6 +56,8 @@ export default class Http extends JsonRpcBase {
if (response.status !== 200) {
this._connected = false;
this.error(JSON.stringify({ status: response.status, statusText: response.statusText }));
console.error(`${method}(${JSON.stringify(params)}): ${response.status}: ${response.statusText}`);
throw new Error(`${response.status}: ${response.statusText}`);
}
@ -66,7 +68,9 @@ export default class Http extends JsonRpcBase {
if (response.error) {
this.error(JSON.stringify(response));
throw new Error(`${response.error.code}: ${response.error.message}`);
console.error(`${method}(${JSON.stringify(params)}): ${response.error.code}: ${response.error.message}`);
throw new Error(`${method}: ${response.error.code}: ${response.error.message}`);
}
this.log(JSON.stringify(response));

View File

@ -107,7 +107,9 @@ export default class Ws extends JsonRpcBase {
if (result.error) {
this.error(event.data);
reject(new Error(`${result.error.code}: ${result.error.message}`));
console.error(`${method}(${JSON.stringify(params)}): ${result.error.code}: ${result.error.message}`);
reject(new Error(`${method}: ${result.error.code}: ${result.error.message}`));
delete this._messages[result.id];
return;
}

View File

@ -32,7 +32,7 @@ export default class Registry {
return;
}
this._api.ethcore
this._api.parity
.registryAddress()
.then((address) => {
this._instance = this._api.newContract(abis.registry, address).instance;

View File

@ -83,7 +83,7 @@ export default class Application extends Component {
Promise
.all([
attachInstances(),
api.personal.accountsInfo()
api.parity.accounts()
])
.then(([{ managerInstance, registryInstance, tokenregInstance }, accountsInfo]) => {
accountsInfo = accountsInfo || {};

View File

@ -296,7 +296,7 @@ export default class Deployment extends Component {
.then((signerRequestId) => {
this.setState({ signerRequestId, deployState: 'Transaction posted, Waiting for transaction authorization' });
return api.pollMethod('eth_checkRequest', signerRequestId);
return api.pollMethod('parity_checkRequest', signerRequestId);
})
.then((txHash) => {
this.setState({ txHash, deployState: 'Transaction authorized, Waiting for network confirmations' });

View File

@ -279,7 +279,7 @@ export default class Send extends Component {
.then((signerRequestId) => {
this.setState({ signerRequestId, sendState: 'Transaction posted, Waiting for transaction authorization' });
return api.pollMethod('eth_checkRequest', signerRequestId);
return api.pollMethod('parity_checkRequest', signerRequestId);
})
.then((txHash) => {
this.setState({ txHash, sendState: 'Transaction authorized, Waiting for network confirmations' });

View File

@ -100,8 +100,8 @@ export function attachInstances () {
return Promise
.all([
api.ethcore.registryAddress(),
api.ethcore.netChain()
api.parity.registryAddress(),
api.parity.netChain()
])
.then(([registryAddress, netChain]) => {
const registry = api.newContract(abis.registry, registryAddress).instance;

View File

@ -11,7 +11,6 @@
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="/parity-utils/parity.js"></script>
<script src="githubhint.js"></script>
</body>
</html>

View File

@ -41,7 +41,9 @@ export default class Application extends Component {
registerBusy: false,
registerError: null,
registerState: '',
registerType: 'file'
registerType: 'file',
repo: '',
repoError: null
}
componentDidMount () {
@ -206,47 +208,64 @@ export default class Application extends Component {
}
onChangeCommit = (event) => {
const commit = event.target.value;
let commit = event.target.value;
const commitError = null;
let hasContent = false;
// TODO: field validation
this.setState({ commit, commitError, contentHashError: null }, () => {
const { repo } = this.state || '';
const parts = repo.split('/');
this.setState({ commit, commitError, contentHashError: 'hash lookup in progress' }, () => {
const { repo } = this.state;
this.lookupHash(`https://codeload.github.com/${repo}/zip/${commit}`);
hasContent = commit.length !== 0 && parts.length === 2 && parts[0].length !== 0 && parts[1].length !== 0;
if (!commitError && hasContent) {
this.setState({ contentHashError: 'hash lookup in progress' });
this.lookupHash(`https://codeload.github.com/${repo}/zip/${commit}`);
}
});
}
onChangeRepo = (event) => {
let repo = event.target.value;
const repoError = null;
let hasContent = false;
// TODO: field validation
if (!repoError) {
repo = repo.replace('https://github.com/', '');
}
this.setState({ repo, repoError, contentHashError: 'hash lookup in progress' }, () => {
const { commit } = this.state;
this.lookupHash(`https://codeload.github.com/${repo}/zip/${commit}`);
this.setState({ repo, repoError, contentHashError: null }, () => {
const { commit } = this.state || '';
const parts = repo.split('/');
hasContent = commit.length !== 0 && parts.length === 2 && parts[0].length !== 0 && parts[1].length !== 0;
if (!repoError && hasContent) {
this.setState({ contentHashError: 'hash lookup in progress' });
this.lookupHash(`https://codeload.github.com/${repo}/zip/${commit}`);
}
});
}
onChangeUrl = (event) => {
let url = event.target.value;
const urlError = null;
let hasContent = false;
// TODO: field validation
if (!urlError) {
const parts = url.split('/');
hasContent = parts.length !== 0;
if (parts[2] === 'github.com' || parts[2] === 'raw.githubusercontent.com') {
url = `https://raw.githubusercontent.com/${parts.slice(3).join('/')}`.replace('/blob/', '/');
}
}
this.setState({ url, urlError, contentHashError: 'hash lookup in progress' }, () => {
this.lookupHash(url);
this.setState({ url, urlError, contentHashError: null }, () => {
if (!urlError && hasContent) {
this.setState({ contentHashError: 'hash lookup in progress' });
this.lookupHash(url);
}
});
}
@ -271,7 +290,7 @@ export default class Application extends Component {
.then((signerRequestId) => {
this.setState({ signerRequestId, registerState: 'Transaction posted, Waiting for transaction authorization' });
return api.pollMethod('eth_checkRequest', signerRequestId);
return api.pollMethod('parity_checkRequest', signerRequestId);
})
.then((txHash) => {
this.setState({ txHash, registerState: 'Transaction authorized, Waiting for network confirmations' });
@ -285,7 +304,7 @@ export default class Application extends Component {
});
})
.then((txReceipt) => {
this.setState({ txReceipt, registerBusy: false, registerState: 'Network confirmed, Received transaction receipt', url: '', commit: '', commitError: null, contentHash: '', contentHashOwner: null, contentHashError: null });
this.setState({ txReceipt, registerBusy: false, registerState: 'Network confirmed, Received transaction receipt', url: '', commit: '', repo: '', commitError: null, contentHash: '', contentHashOwner: null, contentHashError: null });
})
.catch((error) => {
console.error('onSend', error);
@ -298,7 +317,7 @@ export default class Application extends Component {
this.setState({ registerBusy: true, registerState: 'Estimating gas for the transaction' });
const values = [contentHash, repo, commit];
const values = [contentHash, repo, commit.substr(0, 2) === '0x' ? commit : `0x${commit}`];
const options = { from: fromAddress };
this.trackRequest(
@ -367,7 +386,7 @@ export default class Application extends Component {
console.log(`lookupHash ${url}`);
api.ethcore
api.parity
.hashContent(url)
.then((contentHash) => {
console.log('lookupHash', contentHash);

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
const { api } = window.parity;
const api = window.parent.secureApi;
export {
api

View File

@ -18,7 +18,7 @@ import * as abis from '../../contracts/abi';
import { api } from './parity';
export function attachInterface () {
return api.ethcore
return api.parity
.registryAddress()
.then((registryAddress) => {
console.log(`the registry was found at ${registryAddress}`);
@ -29,7 +29,7 @@ export function attachInterface () {
.all([
registry.getAddress.call({}, [api.util.sha3('githubhint'), 'A']),
api.eth.accounts(),
api.personal.accountsInfo()
api.parity.accounts()
]);
})
.then(([address, addresses, accountsInfo]) => {

View File

@ -29,7 +29,7 @@ export { addresses, accounts, lookup, events, names, records };
export const setContract = (contract) => ({ type: 'set contract', contract });
export const fetchContract = () => (dispatch) =>
api.ethcore.registryAddress()
api.parity.registryAddress()
.then((address) => {
const contract = api.newContract(registryAbi, address);
dispatch(setContract(contract));

View File

@ -22,7 +22,7 @@ export const fetch = () => (dispatch) => {
return Promise
.all([
api.eth.accounts(),
api.personal.accountsInfo()
api.parity.accounts()
])
.then(([ accounts, data ]) => {
data = data || {};

View File

@ -39,7 +39,7 @@ const logToEvent = (log) => {
};
export function attachInterface (callback) {
return api.ethcore
return api.parity
.registryAddress()
.then((registryAddress) => {
console.log(`the registry was found at ${registryAddress}`);
@ -50,7 +50,7 @@ export function attachInterface (callback) {
.all([
registry.getAddress.call({}, [api.util.sha3('signaturereg'), 'A']),
api.eth.accounts(),
api.personal.accountsInfo()
api.parity.accounts()
]);
})
.then(([address, addresses, accountsInfo]) => {

View File

@ -38,7 +38,7 @@ export const loadAccounts = () => (dispatch) => {
Promise
.all([
api.eth.accounts(),
api.personal.accountsInfo()
api.parity.accounts()
])
.then(([ accounts, accountsInfo ]) => {
accountsInfo = accountsInfo || {};

View File

@ -34,7 +34,7 @@ export const FIND_CONTRACT = 'FIND_CONTRACT';
export const loadContract = () => (dispatch) => {
dispatch(setLoading(true));
api.ethcore
api.parity
.registryAddress()
.then((registryAddress) => {
console.log(`registry found at ${registryAddress}`);

View File

@ -72,7 +72,7 @@ ReactDOM.render(
<Route path='addresses' component={ Addresses } />
<Route path='address/:address' component={ Address } />
<Route path='apps' component={ Dapps } />
<Route path='app/:type/:name' component={ Dapp } />
<Route path='app/:id' component={ Dapp } />
<Route path='contracts' component={ Contracts } />
<Route path='contract/:address' component={ Contract } />
<Route path='settings' component={ Settings }>

View File

@ -16,20 +16,22 @@
import db from './interfaces/db';
import eth from './interfaces/eth';
import ethcore from './interfaces/ethcore';
import net from './interfaces/net';
import parity from './interfaces/parity';
import personal from './interfaces/personal';
import shh from './interfaces/shh';
import signer from './interfaces/signer';
import trace from './interfaces/trace';
import web3 from './interfaces/web3';
export default {
db: db,
eth: eth,
ethcore: ethcore,
net: net,
personal: personal,
shh: shh,
trace: trace,
web3: web3
db,
eth,
parity,
net,
personal,
shh,
signer,
trace,
web3
};

View File

@ -86,20 +86,6 @@ export default {
}
},
checkRequest: {
desc: 'Returns the transactionhash of the requestId (received from eth_postTransaction) if the request was confirmed',
params: [
{
type: Quantity,
desc: 'The requestId to check for'
}
],
returns: {
type: Hash,
desc: '32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available'
}
},
coinbase: {
desc: 'Returns the client coinbase address.',
params: [],
@ -823,22 +809,6 @@ export default {
}
},
postTransaction: {
desc: 'Posts a transaction to the Signer.',
params: [
{
type: Object,
desc: 'see [eth_sendTransaction](#eth_sendTransaction)',
format: 'inputCallFormatter'
}
],
returns: {
type: Quantity,
desc: 'The id of the actual transaction',
format: 'utils.toDecimal'
}
},
protocolVersion: {
desc: 'Returns the current ethereum protocol version.',
params: [],

View File

@ -26,6 +26,52 @@ export default {
}
},
accounts: {
desc: 'returns a map of accounts as an object',
params: [],
returns: {
type: Array,
desc: 'Account metadata',
details: {
name: {
type: String,
desc: 'Account name'
},
meta: {
type: String,
desc: 'Encoded JSON string the defines additional account metadata'
},
uuid: {
type: String,
desc: 'The account UUID, or null if not available/unknown/not applicable.'
}
}
}
},
accountsInfo: {
desc: 'returns a map of accounts as an object',
params: [],
returns: {
type: Array,
desc: 'Account metadata',
details: {
name: {
type: String,
desc: 'Account name'
},
meta: {
type: String,
desc: 'Encoded JSON string the defines additional account metadata'
},
uuid: {
type: String,
desc: 'The account UUID, or null if not available/unknown/not applicable.'
}
}
}
},
addReservedPeer: {
desc: '?',
params: [
@ -40,6 +86,20 @@ export default {
}
},
checkRequest: {
desc: 'Returns the transactionhash of the requestId (received from parity_postTransaction) if the request was confirmed',
params: [
{
type: Quantity,
desc: 'The requestId to check for'
}
],
returns: {
type: Hash,
desc: '32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available'
}
},
dappsPort: {
desc: 'Returns the port the dapps are running on, error if not enabled',
params: [],
@ -155,6 +215,29 @@ export default {
}
},
listGethAccounts: {
desc: 'Returns a list of the accounts available from Geth',
params: [],
returns: {
type: Array,
desc: '20 Bytes addresses owned by the client.'
}
},
importGethAccounts: {
desc: 'Imports a list of accounts from geth',
params: [
{
type: Array,
desc: 'List of the geth addresses to import'
}
],
returns: {
type: Array,
desc: 'Array of the imported addresses'
}
},
minGasPrice: {
desc: 'Returns currently set minimal gas price',
params: [],
@ -210,6 +293,60 @@ export default {
}
},
newAccountFromPhrase: {
desc: 'Creates a new account from a recovery passphrase',
params: [
{
type: String,
desc: 'Phrase'
},
{
type: String,
desc: 'Password'
}
],
returns: {
type: Address,
desc: 'The created address'
}
},
newAccountFromSecret: {
desc: 'Creates a new account from a private ethstore secret key',
params: [
{
type: Data,
desc: 'Secret, 32-byte hex'
},
{
type: String,
desc: 'Password'
}
],
returns: {
type: Address,
desc: 'The created address'
}
},
newAccountFromWallet: {
desc: 'Creates a new account from a JSON import',
params: [
{
type: String,
desc: 'JSON'
},
{
type: String,
desc: 'Password'
}
],
returns: {
type: Address,
desc: 'The created address'
}
},
nodeName: {
desc: 'Returns node name (identity)',
params: [],
@ -233,6 +370,22 @@ export default {
}
},
postTransaction: {
desc: 'Posts a transaction to the Signer.',
params: [
{
type: Object,
desc: 'see [eth_sendTransaction](#eth_sendTransaction)',
format: 'inputCallFormatter'
}
],
returns: {
type: Quantity,
desc: 'The id of the actual transaction',
format: 'utils.toDecimal'
}
},
removeReservedPeer: {
desc: '?',
params: [
@ -265,6 +418,42 @@ export default {
}
},
setAccountName: {
desc: 'Sets a name for the account',
params: [
{
type: Address,
desc: 'Address'
},
{
type: String,
desc: 'Name'
}
],
returns: {
type: Object,
desc: 'Returns null in all cases'
}
},
setAccountMeta: {
desc: 'Sets metadata for the account',
params: [
{
type: Address,
desc: 'Address'
},
{
type: String,
desc: 'Metadata (JSON encoded)'
}
],
returns: {
type: Object,
desc: 'Returns null in all cases'
}
},
setAuthor: {
desc: 'Changes author (coinbase) for mined blocks.',
params: [

View File

@ -17,83 +17,6 @@
import { Address, Data, Quantity } from '../types';
export default {
accountsInfo: {
desc: 'returns a map of accounts as an object',
params: [],
returns: {
type: Array,
desc: 'Account metadata',
details: {
name: {
type: String,
desc: 'Account name'
},
meta: {
type: String,
desc: 'Encoded JSON string the defines additional account metadata'
},
uuid: {
type: String,
desc: 'The account UUID, or null if not available/unknown/not applicable.'
}
}
}
},
generateAuthorizationToken: {
desc: 'Generates a new authorization token',
params: [],
returns: {
type: String,
desc: 'The new authorization token'
}
},
requestsToConfirm: {
desc: 'Returns a list of the transactions requiring authorization',
params: [],
returns: {
type: Array,
desc: 'A list of the outstanding transactions'
}
},
confirmRequest: {
desc: 'Confirm a request in the signer queue',
params: [
{
type: Quantity,
desc: 'The request id'
},
{
type: Object,
desc: 'The request options'
},
{
type: String,
desc: 'The account password'
}
],
returns: {
type: Boolean,
desc: 'The status of the confirmation'
}
},
rejectRequest: {
desc: 'Rejects a request in the signer queue',
params: [
{
type: Quantity,
desc: 'The request id'
}
],
returns: {
type: Boolean,
desc: 'The status of the rejection'
}
},
listAccounts: {
desc: 'Returns a list of addresses owned by client.',
params: [],
@ -103,29 +26,6 @@ export default {
}
},
listGethAccounts: {
desc: 'Returns a list of the accounts available from Geth',
params: [],
returns: {
type: Array,
desc: '20 Bytes addresses owned by the client.'
}
},
importGethAccounts: {
desc: 'Imports a list of accounts from geth',
params: [
{
type: Array,
desc: 'List of the geth addresses to import'
}
],
returns: {
type: Array,
desc: 'Array of the imported addresses'
}
},
newAccount: {
desc: 'Creates new account',
params: [
@ -140,96 +40,6 @@ export default {
}
},
newAccountFromPhrase: {
desc: 'Creates a new account from a recovery passphrase',
params: [
{
type: String,
desc: 'Phrase'
},
{
type: String,
desc: 'Password'
}
],
returns: {
type: Address,
desc: 'The created address'
}
},
newAccountFromSecret: {
desc: 'Creates a new account from a private ethstore secret key',
params: [
{
type: Data,
desc: 'Secret, 32-byte hex'
},
{
type: String,
desc: 'Password'
}
],
returns: {
type: Address,
desc: 'The created address'
}
},
newAccountFromWallet: {
desc: 'Creates a new account from a JSON import',
params: [
{
type: String,
desc: 'JSON'
},
{
type: String,
desc: 'Password'
}
],
returns: {
type: Address,
desc: 'The created address'
}
},
setAccountName: {
desc: 'Sets a name for the account',
params: [
{
type: Address,
desc: 'Address'
},
{
type: String,
desc: 'Name'
}
],
returns: {
type: Object,
desc: 'Returns null in all cases'
}
},
setAccountMeta: {
desc: 'Sets metadata for the account',
params: [
{
type: Address,
desc: 'Address'
},
{
type: String,
desc: 'Metadata (JSON encoded)'
}
],
returns: {
type: Object,
desc: 'Returns null in all cases'
}
},
signAndSendTransaction: {
desc: 'Sends and signs a transaction given account passphrase. Does not require the account to be unlocked nor unlocks the account for future transactions. ',
params: [
@ -284,15 +94,6 @@ export default {
}
},
signerEnabled: {
desc: 'Returns whether signer is enabled/disabled.',
params: [],
returns: {
type: Boolean,
desc: 'true when enabled, false when disabled'
}
},
unlockAccount: {
desc: '?',
params: [

View File

@ -0,0 +1,82 @@
// 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 <http://www.gnu.org/licenses/>.
import { Quantity } from '../types';
export default {
generateAuthorizationToken: {
desc: 'Generates a new authorization token',
params: [],
returns: {
type: String,
desc: 'The new authorization token'
}
},
requestsToConfirm: {
desc: 'Returns a list of the transactions requiring authorization',
params: [],
returns: {
type: Array,
desc: 'A list of the outstanding transactions'
}
},
confirmRequest: {
desc: 'Confirm a request in the signer queue',
params: [
{
type: Quantity,
desc: 'The request id'
},
{
type: Object,
desc: 'The request options'
},
{
type: String,
desc: 'The account password'
}
],
returns: {
type: Boolean,
desc: 'The status of the confirmation'
}
},
rejectRequest: {
desc: 'Rejects a request in the signer queue',
params: [
{
type: Quantity,
desc: 'The request id'
}
],
returns: {
type: Boolean,
desc: 'The status of the rejection'
}
},
signerEnabled: {
desc: 'Returns whether signer is enabled/disabled.',
params: [],
returns: {
type: Boolean,
desc: 'true when enabled, false when disabled'
}
}
};

View File

@ -133,8 +133,8 @@ export default class AddAddress extends Component {
const { address, name, description } = this.state;
Promise.all([
api.personal.setAccountName(address, name),
api.personal.setAccountMeta(address, {
api.parity.setAccountName(address, name),
api.parity.setAccountMeta(address, {
description,
timestamp: Date.now(),
deleted: false

View File

@ -141,8 +141,8 @@ export default class AddContract extends Component {
const { abiParsed, address, name, description } = this.state;
Promise.all([
api.personal.setAccountName(address, name),
api.personal.setAccountMeta(address, {
api.parity.setAccountName(address, name),
api.parity.setAccountMeta(address, {
contract: true,
deleted: false,
timestamp: Date.now(),

View File

@ -173,15 +173,15 @@ export default class CreateAccount extends Component {
Promise
.all([
api.ethcore.generateSecretPhrase(),
api.ethcore.generateSecretPhrase(),
api.ethcore.generateSecretPhrase(),
api.ethcore.generateSecretPhrase(),
api.ethcore.generateSecretPhrase()
api.parity.generateSecretPhrase(),
api.parity.generateSecretPhrase(),
api.parity.generateSecretPhrase(),
api.parity.generateSecretPhrase(),
api.parity.generateSecretPhrase()
])
.then((phrases) => {
return Promise
.all(phrases.map((phrase) => api.ethcore.phraseToAddress(phrase)))
.all(phrases.map((phrase) => api.parity.phraseToAddress(phrase)))
.then((addresses) => {
const accounts = {};

View File

@ -102,7 +102,7 @@ export default class NewGeth extends Component {
const { api } = this.context;
const { accounts } = this.props;
api.personal
api.parity
.listGethAccounts()
.then((_addresses) => {
const addresses = (addresses || []).filter((address) => !accounts[address]);

View File

@ -208,13 +208,13 @@ export default class CreateAccount extends Component {
});
if (createType === 'fromNew' || createType === 'fromPhrase') {
return api.personal
return api.parity
.newAccountFromPhrase(this.state.phrase, this.state.password)
.then((address) => {
this.setState({ address });
return api.personal
return api.parity
.setAccountName(address, this.state.name)
.then(() => api.personal.setAccountMeta(address, {
.then(() => api.parity.setAccountMeta(address, {
timestamp: Date.now(),
passwordHint: this.state.passwordHint
}));
@ -233,13 +233,13 @@ export default class CreateAccount extends Component {
this.newError(error);
});
} else if (createType === 'fromRaw') {
return api.personal
return api.parity
.newAccountFromSecret(this.state.rawKey, this.state.password)
.then((address) => {
this.setState({ address });
return api.personal
return api.parity
.setAccountName(address, this.state.name)
.then(() => api.personal.setAccountMeta(address, {
.then(() => api.parity.setAccountMeta(address, {
timestamp: Date.now(),
passwordHint: this.state.passwordHint
}));
@ -258,13 +258,13 @@ export default class CreateAccount extends Component {
this.newError(error);
});
} else if (createType === 'fromGeth') {
return api.personal
return api.parity
.importGethAccounts(this.state.gethAddresses)
.then((result) => {
console.log('result', result);
return Promise.all(this.state.gethAddresses.map((address) => {
return api.personal.setAccountName(address, 'Geth Import');
return api.parity.setAccountName(address, 'Geth Import');
}));
})
.then(() => {
@ -282,16 +282,16 @@ export default class CreateAccount extends Component {
});
}
return api.personal
return api.parity
.newAccountFromWallet(this.state.json, this.state.password)
.then((address) => {
this.setState({
address: address
});
return api.personal
return api.parity
.setAccountName(address, this.state.name)
.then(() => api.personal.setAccountMeta(address, {
.then(() => api.parity.setAccountMeta(address, {
timestamp: Date.now(),
passwordHint: this.state.passwordHint
}));

View File

@ -212,8 +212,8 @@ export default class DeployContract extends Component {
.deploy(options, params, this.onDeploymentState)
.then((address) => {
return Promise.all([
api.personal.setAccountName(address, name),
api.personal.setAccountMeta(address, {
api.parity.setAccountName(address, name),
api.parity.setAccountMeta(address, {
abi: abiParsed,
contract: true,
timestamp: Date.now(),

View File

@ -139,8 +139,8 @@ export default class EditMeta extends Component {
Promise
.all([
api.personal.setAccountName(account.address, name),
api.personal.setAccountMeta(account.address, Object.assign({}, account.meta, meta))
api.parity.setAccountName(account.address, name),
api.parity.setAccountMeta(account.address, Object.assign({}, account.meta, meta))
])
.then(() => this.props.onClose())
.catch((error) => {

View File

@ -221,7 +221,7 @@ export default class ExecuteContract extends Component {
})
.then((requestId) => {
this.setState({ busyState: 'Waiting for authorization in the Parity Signer' });
return api.pollMethod('eth_checkRequest', requestId);
return api.pollMethod('parity_checkRequest', requestId);
})
.then((txhash) => {
this.setState({ sending: false, step: 2, txhash, busyState: 'Your transaction has been posted to the network' });

View File

@ -183,9 +183,9 @@ export default class FirstRun extends Component {
canCreate: false
});
return api.personal
return api.parity
.newAccountFromPhrase(phrase, password)
.then((address) => api.personal.setAccountName(address, name))
.then((address) => api.parity.setAccountName(address, name))
.then(() => {
this.onNext();
})

View File

@ -317,7 +317,7 @@ export default class PasswordManager extends Component {
this.setState({ waiting: true, showMessage: false });
this.context
.api.personal
.api.parity
.testPassword(account.address, currentPass)
.then(correct => {
const message = correct
@ -343,7 +343,7 @@ export default class PasswordManager extends Component {
this.setState({ waiting: true, showMessage: false });
this.context
.api.personal
.api.parity
.testPassword(account.address, currentPass)
.then(correct => {
if (!correct) {
@ -363,11 +363,11 @@ export default class PasswordManager extends Component {
return Promise.all([
this.context
.api.personal
.api.parity
.setAccountMeta(account.address, meta),
this.context
.api.personal
.api.parity
.changePassword(account.address, currentPass, newPass)
])
.then(() => {

View File

@ -123,7 +123,13 @@ export default class Details extends Component {
.map((balance, index) => {
const token = balance.token;
const isEth = index === 0;
const imagesrc = token.image || images[token.address] || imageUnknown;
let imagesrc = token.image;
if (!imagesrc) {
imagesrc =
images[token.address]
? `${api.dappsUrl}${images[token.address]}`
: imageUnknown;
}
let value = 0;
if (isEth) {

View File

@ -424,7 +424,7 @@ export default class Transfer extends Component {
options.data = data;
}
return api.eth.postTransaction(options);
return api.parity.postTransaction(options);
}
_sendToken () {
@ -455,7 +455,7 @@ export default class Transfer extends Component {
: this._sendToken()
).then((requestId) => {
this.setState({ busyState: 'Waiting for authorization in the Parity Signer' });
return api.pollMethod('eth_checkRequest', requestId);
return api.pollMethod('parity_checkRequest', requestId);
})
.then((txhash) => {
this.onNext();
@ -592,7 +592,7 @@ export default class Transfer extends Component {
Promise
.all([
api.ethcore.gasPriceHistogram(),
api.parity.gasPriceHistogram(),
api.eth.gasPrice()
])
.then(([gasPriceHistogram, gasPrice]) => {

View File

@ -42,7 +42,7 @@ export default class Balances {
_subscribeAccountsInfo () {
this._api
.subscribe('personal_accountsInfo', (error, accountsInfo) => {
.subscribe('parity_accountsInfo', (error, accountsInfo) => {
if (error) {
return;
}
@ -76,7 +76,7 @@ export default class Balances {
}
_retrieveTokens () {
this._api.ethcore
this._api.parity
.registryAddress()
.then((registryAddress) => {
const registry = this._api.newContract(abis.registry, registryAddress);

View File

@ -17,8 +17,6 @@
import { handleActions } from 'redux-actions';
import { bytesToHex } from '../../api/util/format';
import { parityNode } from '../../environment';
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000';
const initialState = {
@ -28,7 +26,7 @@ const initialState = {
export function hashToImageUrl (hashArray) {
const hash = hashArray ? bytesToHex(hashArray) : ZERO;
return hash === ZERO ? null : `${parityNode}/api/content/${hash.substr(2)}`;
return hash === ZERO ? null : `/api/content/${hash.substr(2)}`;
}
export default handleActions({

View File

@ -28,9 +28,9 @@ export default class Personal {
_subscribeAccountsInfo () {
this._api
.subscribe('personal_accountsInfo', (error, accountsInfo) => {
.subscribe('parity_accountsInfo', (error, accountsInfo) => {
if (error) {
console.error('personal_accountsInfo', error);
console.error('parity_accountsInfo', error);
return;
}

View File

@ -14,22 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// 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 <http://www.gnu.org/licenses/>.
import { signerRequestsToConfirm } from './signerActions';
export default class Signer {
@ -44,7 +28,7 @@ export default class Signer {
_subscribeRequestsToConfirm () {
this._api
.subscribe('personal_requestsToConfirm', (error, pending) => {
.subscribe('signer_requestsToConfirm', (error, pending) => {
if (error) {
return;
}

View File

@ -51,7 +51,7 @@ export default class SignerMiddleware {
onConfirmStart = (store, action) => {
const { id, password } = action.payload;
this._api.personal
this._api.signer
.confirmRequest(id, {}, password)
.then((txHash) => {
console.log('confirmRequest', id, txHash);
@ -71,7 +71,7 @@ export default class SignerMiddleware {
onRejectStart = (store, action) => {
const id = action.payload;
this._api.personal
this._api.signer
.rejectRequest(id)
.then(() => {
store.dispatch(actions.successRejectRequest({ id }));

View File

@ -16,8 +16,6 @@
import { statusBlockNumber, statusCollection, statusLogs } from './statusActions';
import { parityNode } from '../../environment';
export default class Status {
constructor (store, api) {
this._api = api;
@ -33,8 +31,8 @@ export default class Status {
}
_fetchEnode () {
this._api
.ethcore.enode()
this._api.parity
.enode()
.then((enode) => {
this._store.dispatch(statusCollection({ enode }));
})
@ -65,7 +63,7 @@ export default class Status {
setTimeout(this._pollPing, timeout);
};
fetch(`${parityNode}/api/ping`, { method: 'GET' })
fetch('/', { method: 'HEAD' })
.then((response) => dispatch(!!response.ok))
.catch(() => dispatch(false));
}
@ -103,16 +101,16 @@ export default class Status {
.all([
this._api.web3.clientVersion(),
this._api.eth.coinbase(),
this._api.ethcore.defaultExtraData(),
this._api.ethcore.extraData(),
this._api.ethcore.gasFloorTarget(),
this._api.parity.defaultExtraData(),
this._api.parity.extraData(),
this._api.parity.gasFloorTarget(),
this._api.eth.hashrate(),
this._api.ethcore.minGasPrice(),
this._api.ethcore.netChain(),
this._api.ethcore.netPeers(),
this._api.ethcore.netPort(),
this._api.ethcore.nodeName(),
this._api.ethcore.rpcSettings(),
this._api.parity.minGasPrice(),
this._api.parity.netChain(),
this._api.parity.netPeers(),
this._api.parity.netPort(),
this._api.parity.nodeName(),
this._api.parity.rpcSettings(),
this._api.eth.syncing(),
this._pollTraceMode()
])
@ -155,8 +153,8 @@ export default class Status {
Promise
.all([
this._api.ethcore.devLogs(),
this._api.ethcore.devLogsLevels()
this._api.parity.devLogs(),
this._api.parity.devLogsLevels()
])
.then(([devLogs, devLogsLevels]) => {
this._store.dispatch(statusLogs({

View File

@ -25,6 +25,8 @@ export default class SecureApi extends Api {
this._isConnecting = true;
this._connectState = 0;
this._needsToken = false;
this._dappsPort = 8080;
this._signerPort = 8180;
this._followConnection();
}
@ -50,7 +52,7 @@ export default class SecureApi extends Api {
case 0:
if (isConnected) {
this._isConnecting = false;
return this.setToken();
return this.connectSuccess();
} else if (lastError) {
this.updateToken('initial', 1);
}
@ -60,7 +62,7 @@ export default class SecureApi extends Api {
case 1:
if (isConnected) {
this._connectState = 2;
this.personal
this.parity
.generateAuthorizationToken()
.then((token) => {
this.updateToken(token, 2);
@ -79,7 +81,7 @@ export default class SecureApi extends Api {
case 2:
if (isConnected) {
this._isConnecting = false;
return this.setToken();
return this.connectSuccess();
} else if (lastError) {
return setManual();
}
@ -89,12 +91,38 @@ export default class SecureApi extends Api {
nextTick();
}
connectSuccess () {
this.setToken();
Promise
.all([
this.parity.dappsPort(),
this.parity.signerPort()
])
.then(([dappsPort, signerPort]) => {
this._dappsPort = dappsPort.toNumber();
this._signerPort = signerPort.toNumber();
});
}
updateToken (token, connectedState = 0) {
this._connectState = connectedState;
this._transport.updateToken(token.replace(/[^a-zA-Z0-9]/g, ''));
this._followConnection();
}
get dappsPort () {
return this._dappsPort;
}
get dappsUrl () {
return `http://127.0.0.1:${this._dappsPort}`;
}
get signerPort () {
return this._signerPort;
}
get isConnecting () {
return this._isConnecting;
}

View File

@ -47,7 +47,13 @@ class Balance extends Component {
const value = token.format
? new BigNumber(balance.value).div(new BigNumber(token.format)).toFormat(3)
: api.util.fromWei(balance.value).toFormat(3);
const imagesrc = token.image || images[token.address] || unknownImage;
let imagesrc = token.image;
if (!imagesrc) {
imagesrc =
images[token.address]
? `${api.dappsUrl}${images[token.address]}`
: unknownImage;
}
return (
<div

View File

@ -59,10 +59,9 @@ class IdentityIcon extends Component {
updateIcon (_address, images) {
const { api } = this.context;
const { button, inline, tiny } = this.props;
const iconsrc = images[_address];
if (iconsrc) {
this.setState({ iconsrc });
if (images[_address]) {
this.setState({ iconsrc: `${api.dappsUrl}${images[_address]}` });
return;
}

View File

@ -149,7 +149,7 @@ export default class Header extends Component {
const { account } = this.props;
this.setState({ name }, () => {
api.personal
api.parity
.setAccountName(account.address, name)
.catch((error) => {
console.error(error);

View File

@ -81,7 +81,7 @@ class Delete extends Component {
account.meta.deleted = true;
api.personal
api.parity
.setAccountMeta(account.address, account.meta)
.then(() => {
router.push(route);

View File

@ -104,8 +104,8 @@ class Application extends Component {
checkAccounts () {
const { api } = this.context;
api.personal
.listAccounts()
api.eth
.accounts()
.then((accounts) => {
this.setState({
showFirstRun: showFirstRun || accounts.length === 0

View File

@ -16,20 +16,54 @@
import React, { Component, PropTypes } from 'react';
import Contracts from '../../contracts';
import { fetchAvailable } from '../Dapps/registry';
import styles from './dapp.css';
const dapphost = process.env.NODE_ENV === 'production' ? 'http://127.0.0.1:8080/ui' : '';
export default class Dapp extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = {
params: PropTypes.object
};
state = {
app: null
}
componentWillMount () {
this.lookup();
}
render () {
const { name, type } = this.props.params;
const src = (type === 'builtin')
? `${dapphost}/${name}.html`
: `http://127.0.0.1:8080/${name}/`;
const { app } = this.state;
const { dappsUrl } = this.context.api;
if (!app) {
return null;
}
let src = null;
switch (app.type) {
case 'builtin':
const dapphost = process.env.NODE_ENV === 'production' && !app.secure
? `${dappsUrl}/ui`
: '';
src = `${dapphost}/${app.url}.html`;
break;
case 'local':
src = `${dappsUrl}/${app.id}/`;
break;
case 'network':
src = `${dappsUrl}/${app.contentHash}/`;
break;
default:
console.error('unknown type', app.type);
break;
}
return (
<iframe
@ -42,4 +76,30 @@ export default class Dapp extends Component {
</iframe>
);
}
lookup () {
const { api } = this.context;
const { id } = this.props.params;
const { dappReg } = Contracts.get();
fetchAvailable(api)
.then((available) => {
return available.find((app) => app.id === id);
})
.then((app) => {
if (app.type !== 'network') {
return app;
}
return dappReg
.getContent(app.id)
.then((contentHash) => {
app.contentHash = api.util.bytesToHex(contentHash).substr(2);
return app;
});
})
.then((app) => {
this.setState({ app });
});
}
}

View File

@ -32,31 +32,27 @@ export default class Summary extends Component {
}
render () {
const { dappsPort } = this.context.api;
const { app } = this.props;
if (!app) {
return null;
}
let type = 'builtin';
if (app.network) {
type = 'network';
} else if (app.local) {
type = 'local';
let image = <div className={ styles.image }>&nbsp;</div>;
if (app.image) {
image = <img src={ `http://127.0.0.1:${dappsPort}${app.image}` } className={ styles.image } />;
} else if (app.iconUrl) {
image = <img src={ `http://127.0.0.1:${dappsPort}/${app.id}/${app.iconUrl}` } className={ styles.image } />;
}
const url = `/app/${type}/${app.url || app.contentHash || app.id}`;
const image = app.image || app.iconUrl
? <img src={ app.image || `http://127.0.0.1:8080/${app.id}/${app.iconUrl}` } className={ styles.image } />
: <div className={ styles.image }>&nbsp;</div>;
return (
<Container className={ styles.container }>
{ image }
<div className={ styles.description }>
<ContainerTitle
className={ styles.title }
title={ <Link to={ url }>{ app.name }</Link> }
title={ <Link to={ `/app/${app.id}` }>{ app.name }</Link> }
byline={ app.description } />
<div className={ styles.author }>{ app.author }, v{ app.version }</div>
{ this.props.children }

View File

@ -16,8 +16,6 @@
import BigNumber from 'bignumber.js';
import { parityNode } from '../../environment';
const builtinApps = [
{
id: '0xf9f2d620c2e08f83e45555247146c62185e4ab7cf82a4b9002a265a0d020348f',
@ -57,7 +55,8 @@ const builtinApps = [
name: 'GitHub Hint',
description: 'A mapping of GitHub URLs to hashes for use in contracts as references',
author: 'Parity Team <admin@ethcore.io>',
version: '1.0.0'
version: '1.0.0',
secure: true
}
];
@ -76,16 +75,14 @@ const networkApps = [
}
];
export function fetchAvailable (api) {
// TODO: Since we don't have an extensive GithubHint app, get the value somehow
// RESULT: 0x22cd66e1b05882c0fa17a16d252d3b3ee2238ccbac8153f69a35c83f02ca76ee
// api.ethcore
// .hashContent('https://codeload.github.com/gavofyork/gavcoin/zip/5a9f11ff2ad0d05c565a938ceffdfa0d23af9981')
// .then((sha3) => {
// console.log('archive', sha3);
// });
function getHost (api) {
return process.env.NODE_ENV === 'production'
? api.dappsUrl
: '';
}
return fetch(`${parityNode}/api/apps`)
export function fetchAvailable (api) {
return fetch(`${getHost(api)}/api/apps`)
.then((response) => {
return response.ok
? response.json()
@ -99,11 +96,11 @@ export function fetchAvailable (api) {
const localApps = _localApps
.filter((app) => !['ui'].includes(app.id))
.map((app) => {
app.local = true;
app.type = 'local';
return app;
});
return api.ethcore
return api.parity
.registryAddress()
.then((registryAddress) => {
if (new BigNumber(registryAddress).eq(0)) {
@ -112,13 +109,13 @@ export function fetchAvailable (api) {
const _builtinApps = builtinApps
.map((app) => {
app.builtin = true;
app.type = 'builtin';
return app;
});
return networkApps
.map((app) => {
app.network = true;
app.type = 'network';
return app;
})
.concat(_builtinApps);
@ -134,8 +131,8 @@ export function fetchAvailable (api) {
});
}
export function fetchManifest (app, contentHash) {
return fetch(`${parityNode}/${contentHash}/manifest.json`)
export function fetchManifest (api, app, contentHash) {
return fetch(`${getHost(api)}/${contentHash}/manifest.json`)
.then((response) => {
return response.ok
? response.json()

View File

@ -89,7 +89,7 @@ export default class Parity extends Component {
onChangeMode = (event, index, mode) => {
const { api } = this.context;
api.ethcore
api.parity
.setMode(mode)
.then((result) => {
if (result) {
@ -104,7 +104,7 @@ export default class Parity extends Component {
loadMode () {
const { api } = this.context;
api.ethcore
api.parity
.mode()
.then((mode) => {
this.setState({ mode });

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react';
import React, { Component, PropTypes } from 'react';
import { Container, ContainerTitle } from '../../../ui';
@ -22,8 +22,13 @@ import layout from '../layout.css';
import styles from './proxy.css';
export default class Proxy extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
render () {
const proxyurl = 'http://127.0.0.1:8080/proxy/proxy.pac';
const { dappsUrl } = this.context.api;
const proxyurl = `${dappsUrl}/proxy/proxy.pac`;
return (
<Container>

View File

@ -50,7 +50,7 @@ export default class SignRequest extends Component {
}
componentWillMount () {
this.context.api.ethcore.netChain()
this.context.api.parity.netChain()
.then((chain) => {
this.setState({ chain });
})

View File

@ -65,7 +65,7 @@ export default class TransactionFinished extends Component {
const totalValue = tUtil.getTotalValue(fee, value);
this.setState({ totalValue });
this.context.api.ethcore.netChain()
this.context.api.parity.netChain()
.then((chain) => {
this.setState({ chain });
})

View File

@ -64,7 +64,7 @@ export default class TransactionPending extends Component {
const gasToDisplay = tUtil.getGasDisplay(gas);
this.setState({ gasPriceEthmDisplay, totalValue, gasToDisplay });
this.context.api.ethcore.netChain()
this.context.api.parity.netChain()
.then((chain) => {
this.setState({ chain });
})

View File

@ -87,7 +87,7 @@ export default class MiningSettings extends Component {
onMinGasPriceChange = (newVal) => {
const { api } = this.context;
api.ethcore.setMinGasPrice(numberFromString(newVal));
api.parity.setMinGasPrice(numberFromString(newVal));
};
onExtraDataChange = (newVal, isResetToDefault) => {
@ -97,18 +97,18 @@ export default class MiningSettings extends Component {
// In case of resetting to default we are just using raw bytes from defaultExtraData
// When user sets new value we can safely send a string that will be converted to hex by formatter.
const val = isResetToDefault ? nodeStatus.defaultExtraData : newVal;
api.ethcore.setExtraData(val);
api.parity.setExtraData(val);
};
onAuthorChange = (newVal) => {
const { api } = this.context;
api.ethcore.setAuthor(newVal);
api.parity.setAuthor(newVal);
};
onGasFloorTargetChange = (newVal) => {
const { api } = this.context;
api.ethcore.setGasFloorTarget(numberFromString(newVal));
api.parity.setGasFloorTarget(numberFromString(newVal));
};
}

View File

@ -41,13 +41,13 @@ disable = false
port = 8545
interface = "local"
cors = "null"
apis = ["web3", "eth", "net", "ethcore", "traces", "rpc", "personal_safe"]
apis = ["web3", "eth", "net", "parity", "traces", "rpc"]
hosts = ["none"]
[ipc]
disable = false
path = "$HOME/.parity/jsonrpc.ipc"
apis = ["web3", "eth", "net", "ethcore", "traces", "rpc", "personal", "personal_safe"]
apis = ["web3", "eth", "net", "parity", "parity_accounts", "personal", "traces", "rpc"]
[dapps]
disable = false

View File

@ -143,7 +143,7 @@ usage! {
or |c: &Config| otry!(c.rpc).interface.clone(),
flag_jsonrpc_cors: Option<String> = None,
or |c: &Config| otry!(c.rpc).cors.clone().map(Some),
flag_jsonrpc_apis: String = "web3,eth,net,ethcore,traces,rpc,personal_safe",
flag_jsonrpc_apis: String = "web3,eth,net,parity,traces,rpc",
or |c: &Config| otry!(c.rpc).apis.clone().map(|vec| vec.join(",")),
flag_jsonrpc_hosts: String = "none",
or |c: &Config| otry!(c.rpc).hosts.clone().map(|vec| vec.join(",")),
@ -153,7 +153,7 @@ usage! {
or |c: &Config| otry!(c.ipc).disable.clone(),
flag_ipc_path: String = "$HOME/.parity/jsonrpc.ipc",
or |c: &Config| otry!(c.ipc).path.clone(),
flag_ipc_apis: String = "web3,eth,net,ethcore,traces,rpc,personal,personal_safe",
flag_ipc_apis: String = "web3,eth,net,parity,parity_accounts,traces,rpc",
or |c: &Config| otry!(c.ipc).apis.clone().map(|vec| vec.join(",")),
// DAPPS
@ -540,13 +540,13 @@ mod tests {
flag_jsonrpc_port: 8545u16,
flag_jsonrpc_interface: "local".into(),
flag_jsonrpc_cors: Some("null".into()),
flag_jsonrpc_apis: "web3,eth,net,ethcore,traces,rpc,personal_safe".into(),
flag_jsonrpc_apis: "web3,eth,net,parity,traces,rpc".into(),
flag_jsonrpc_hosts: "none".into(),
// IPC
flag_no_ipc: false,
flag_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(),
flag_ipc_apis: "web3,eth,net,ethcore,traces,rpc,personal,personal_safe".into(),
flag_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,rpc".into(),
// DAPPS
flag_no_dapps: false,

View File

@ -107,7 +107,7 @@ API and Console Options:
--jsonrpc-apis APIS Specify the APIs available through the JSONRPC
interface. APIS is a comma-delimited list of API
name. Possible name are web3, eth, net, personal,
ethcore, ethcore_set, traces, rpc, personal_safe.
parity, parity_set, traces, rpc, parity_accounts.
(default: {flag_jsonrpc_apis}).
--jsonrpc-hosts HOSTS List of allowed Host header values. This option will
validate the Host header sent by the browser, it
@ -284,7 +284,7 @@ Legacy Options:
--geth Run in Geth-compatibility mode. Sets the IPC path
to be the same as Geth's. Overrides the --ipc-path
and --ipcpath options. Alters RPCs to reflect Geth
bugs.
bugs. Includes the personal_ RPC by default.
--testnet Geth-compatible testnet mode. Equivalent to --chain
testnet --keys-path $HOME/parity/testnet-keys.
Overrides the --keys-path option.

View File

@ -509,7 +509,11 @@ impl Configuration {
}
fn rpc_apis(&self) -> String {
self.args.flag_rpcapi.clone().unwrap_or(self.args.flag_jsonrpc_apis.clone())
let mut apis = self.args.flag_rpcapi.clone().unwrap_or(self.args.flag_jsonrpc_apis.clone());
if self.args.flag_geth {
apis.push_str(",personal");
}
apis
}
fn rpc_cors(&self) -> Option<Vec<String>> {
@ -541,7 +545,13 @@ impl Configuration {
let conf = IpcConfiguration {
enabled: !(self.args.flag_ipcdisable || self.args.flag_ipc_off || self.args.flag_no_ipc),
socket_addr: self.ipc_path(),
apis: try!(self.args.flag_ipcapi.clone().unwrap_or(self.args.flag_ipc_apis.clone()).parse()),
apis: {
let mut apis = self.args.flag_ipcapi.clone().unwrap_or(self.args.flag_ipc_apis.clone());
if self.args.flag_geth {
apis.push_str("personal");
}
try!(apis.parse())
},
};
Ok(conf)

View File

@ -31,15 +31,25 @@ pub use ethcore_rpc::SignerService;
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub enum Api {
/// Web3 (Safe)
Web3,
/// Net (Safe)
Net,
/// Eth (Safe)
Eth,
PersonalSafe,
PersonalAccounts,
/// Geth-compatible "personal" API (DEPRECATED; only used in `--geth` mode.)
Personal,
/// Signer - Confirm transactions in Signer (UNSAFE: Passwords, List of transactions)
Signer,
Ethcore,
EthcoreSet,
/// Parity - Custom extensions (Safe)
Parity,
/// Parity Accounts extensions (UNSAFE: Passwords, Side Effects (new account))
ParityAccounts,
/// Parity - Set methods (UNSAFE: Side Effects affecting node operation)
ParitySet,
/// Traces (Safe)
Traces,
/// Rpc (Safe)
Rpc,
}
@ -53,11 +63,11 @@ impl FromStr for Api {
"web3" => Ok(Web3),
"net" => Ok(Net),
"eth" => Ok(Eth),
"personal" => Ok(PersonalAccounts),
"personal_safe" => Ok(PersonalSafe),
"personal" => Ok(Personal),
"signer" => Ok(Signer),
"ethcore" => Ok(Ethcore),
"ethcore_set" => Ok(EthcoreSet),
"parity" => Ok(Parity),
"parity_accounts" => Ok(ParityAccounts),
"parity_set" => Ok(ParitySet),
"traces" => Ok(Traces),
"rpc" => Ok(Rpc),
api => Err(format!("Unknown api: {}", api))
@ -119,11 +129,11 @@ fn to_modules(apis: &[Api]) -> BTreeMap<String, String> {
Api::Web3 => ("web3", "1.0"),
Api::Net => ("net", "1.0"),
Api::Eth => ("eth", "1.0"),
Api::PersonalSafe => ("personal_safe", "1.0"),
Api::PersonalAccounts => ("personal", "1.0"),
Api::Personal => ("personal", "1.0"),
Api::Signer => ("signer", "1.0"),
Api::Ethcore => ("ethcore", "1.0"),
Api::EthcoreSet => ("ethcore_set", "1.0"),
Api::Parity => ("parity", "1.0"),
Api::ParityAccounts => ("parity_accounts", "1.0"),
Api::ParitySet => ("parity_set", "1.0"),
Api::Traces => ("traces", "1.0"),
Api::Rpc => ("rpc", "1.0"),
};
@ -134,24 +144,37 @@ fn to_modules(apis: &[Api]) -> BTreeMap<String, String> {
impl ApiSet {
pub fn list_apis(&self) -> HashSet<Api> {
let mut safe_list = vec![Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc]
.into_iter().collect();
match *self {
ApiSet::List(ref apis) => apis.clone(),
ApiSet::UnsafeContext => {
vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc, Api::PersonalSafe]
.into_iter().collect()
},
ApiSet::UnsafeContext => safe_list,
ApiSet::IpcContext => {
vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc, Api::PersonalAccounts, Api::PersonalSafe]
.into_iter().collect()
safe_list.insert(Api::ParityAccounts);
safe_list
},
ApiSet::SafeContext => {
vec![Api::Web3, Api::Net, Api::Eth, Api::PersonalAccounts, Api::PersonalSafe, Api::Signer, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc]
.into_iter().collect()
safe_list.insert(Api::ParityAccounts);
safe_list.insert(Api::ParitySet);
safe_list.insert(Api::Signer);
safe_list
},
}
}
}
macro_rules! add_signing_methods {
($namespace:ident, $server:expr, $deps:expr) => {
let server = &$server;
let deps = &$deps;
if deps.signer_service.is_enabled() {
server.add_delegate($namespace::to_delegate(SigningQueueClient::new(&deps.signer_service, &deps.client, &deps.miner, &deps.secret_store)))
} else {
server.add_delegate($namespace::to_delegate(SigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner)))
}
}
}
pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet) -> T {
use ethcore_rpc::v1::*;
@ -183,39 +206,39 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
let filter_client = EthFilterClient::new(&deps.client, &deps.miner);
server.add_delegate(filter_client.to_delegate());
if deps.signer_service.is_enabled() {
server.add_delegate(EthSigningQueueClient::new(&deps.signer_service, &deps.client, &deps.miner, &deps.secret_store).to_delegate());
} else {
server.add_delegate(EthSigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner).to_delegate());
}
add_signing_methods!(EthSigning, server, deps);
},
Api::PersonalAccounts => {
server.add_delegate(PersonalAccountsClient::new(&deps.secret_store, &deps.client, &deps.miner, deps.geth_compatibility).to_delegate());
},
Api::PersonalSafe => {
server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client).to_delegate());
Api::Personal => {
server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner, deps.geth_compatibility).to_delegate());
},
Api::Signer => {
server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_service).to_delegate());
},
Api::Ethcore => {
Api::Parity => {
let signer = match deps.signer_service.is_enabled() {
true => Some(deps.signer_service.clone()),
false => None,
};
server.add_delegate(EthcoreClient::new(
server.add_delegate(ParityClient::new(
&deps.client,
&deps.miner,
&deps.sync,
&deps.net_service,
&deps.secret_store,
deps.logger.clone(),
deps.settings.clone(),
signer,
deps.dapps_port,
).to_delegate())
).to_delegate());
add_signing_methods!(EthSigning, server, deps);
add_signing_methods!(ParitySigning, server, deps);
},
Api::EthcoreSet => {
server.add_delegate(EthcoreSetClient::new(&deps.client, &deps.miner, &deps.net_service).to_delegate())
Api::ParityAccounts => {
server.add_delegate(ParityAccountsClient::new(&deps.secret_store, &deps.client).to_delegate());
},
Api::ParitySet => {
server.add_delegate(ParitySetClient::new(&deps.client, &deps.miner, &deps.net_service).to_delegate())
},
Api::Traces => {
server.add_delegate(TracesClient::new(&deps.client, &deps.miner).to_delegate())
@ -238,11 +261,11 @@ mod test {
assert_eq!(Api::Web3, "web3".parse().unwrap());
assert_eq!(Api::Net, "net".parse().unwrap());
assert_eq!(Api::Eth, "eth".parse().unwrap());
assert_eq!(Api::PersonalAccounts, "personal".parse().unwrap());
assert_eq!(Api::PersonalSafe, "personal_safe".parse().unwrap());
assert_eq!(Api::Personal, "personal".parse().unwrap());
assert_eq!(Api::Signer, "signer".parse().unwrap());
assert_eq!(Api::Ethcore, "ethcore".parse().unwrap());
assert_eq!(Api::EthcoreSet, "ethcore_set".parse().unwrap());
assert_eq!(Api::Parity, "parity".parse().unwrap());
assert_eq!(Api::ParityAccounts, "parity_accounts".parse().unwrap());
assert_eq!(Api::ParitySet, "parity_set".parse().unwrap());
assert_eq!(Api::Traces, "traces".parse().unwrap());
assert_eq!(Api::Rpc, "rpc".parse().unwrap());
assert!("rp".parse::<Api>().is_err());
@ -260,15 +283,34 @@ mod test {
#[test]
fn test_api_set_unsafe_context() {
let expected = vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc, Api::PersonalSafe]
.into_iter().collect();
let expected = vec![
// make sure this list contains only SAFE methods
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc
].into_iter().collect();
assert_eq!(ApiSet::UnsafeContext.list_apis(), expected);
}
#[test]
fn test_api_set_ipc_context() {
let expected = vec![
// safe
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
// semi-safe
Api::ParityAccounts
].into_iter().collect();
assert_eq!(ApiSet::IpcContext.list_apis(), expected);
}
#[test]
fn test_api_set_safe_context() {
let expected = vec![Api::Web3, Api::Net, Api::Eth, Api::PersonalAccounts, Api::PersonalSafe, Api::Signer, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc]
.into_iter().collect();
let expected = vec![
// safe
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
// semi-safe
Api::ParityAccounts,
// Unsafe
Api::ParitySet, Api::Signer,
].into_iter().collect();
assert_eq!(ApiSet::SafeContext.list_apis(), expected);
}
}

View File

@ -27,13 +27,14 @@ macro_rules! take_weak {
mod eth;
mod eth_filter;
mod eth_signing;
mod ethcore;
mod ethcore_set;
mod net;
mod parity;
mod parity_accounts;
mod parity_set;
mod personal;
mod personal_accounts;
mod personal_signer;
mod signer;
mod signing;
mod signing_unsafe;
mod rpc;
mod traces;
mod web3;
@ -41,12 +42,13 @@ mod web3;
pub use self::web3::Web3Client;
pub use self::eth::{EthClient, EthClientOptions};
pub use self::eth_filter::EthFilterClient;
pub use self::eth_signing::{EthSigningUnsafeClient, EthSigningQueueClient};
pub use self::net::NetClient;
pub use self::parity::ParityClient;
pub use self::parity_accounts::ParityAccountsClient;
pub use self::parity_set::ParitySetClient;
pub use self::personal::PersonalClient;
pub use self::personal_accounts::PersonalAccountsClient;
pub use self::personal_signer::SignerClient;
pub use self::ethcore::EthcoreClient;
pub use self::ethcore_set::EthcoreSetClient;
pub use self::signer::SignerClient;
pub use self::signing::SigningQueueClient;
pub use self::signing_unsafe::SigningUnsafeClient;
pub use self::traces::TracesClient;
pub use self::rpc::RpcClient;

View File

@ -14,16 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Ethcore-specific rpc implementation.
use std::{fs, io};
use std::sync::{mpsc, Arc, Weak};
//! Parity-specific rpc implementation.
use std::sync::{Arc, Weak};
use std::str::FromStr;
use std::collections::BTreeMap;
use util::{RotatingLogger, Address, Mutex, sha3};
use util::{RotatingLogger, Address};
use util::misc::version_data;
use crypto::ecies;
use fetch::{Client as FetchClient, Fetch};
use ethkey::{Brain, Generator};
use ethstore::random_phrase;
use ethsync::{SyncProvider, ManageNetwork};
@ -31,77 +30,57 @@ use ethcore::miner::MinerService;
use ethcore::client::{MiningBlockChainClient};
use ethcore::ids::BlockID;
use ethcore::mode::Mode;
use ethcore::account_provider::AccountProvider;
use jsonrpc_core::Error;
use v1::traits::Ethcore;
use v1::traits::Parity;
use v1::types::{Bytes, U256, H160, H256, H512, Peers, Transaction, RpcSettings, Histogram};
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings};
use v1::helpers::dispatch::DEFAULT_MAC;
use v1::helpers::auto_args::Ready;
/// Ethcore implementation.
pub struct EthcoreClient<C, M, S: ?Sized, F=FetchClient> where
/// Parity implementation.
pub struct ParityClient<C, M, S: ?Sized> where
C: MiningBlockChainClient,
M: MinerService,
S: SyncProvider,
F: Fetch {
{
client: Weak<C>,
miner: Weak<M>,
sync: Weak<S>,
net: Weak<ManageNetwork>,
accounts: Weak<AccountProvider>,
logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>,
signer: Option<Arc<SignerService>>,
fetch: Mutex<F>,
dapps_port: Option<u16>,
}
impl<C, M, S: ?Sized> EthcoreClient<C, M, S> where
impl<C, M, S: ?Sized> ParityClient<C, M, S> where
C: MiningBlockChainClient,
M: MinerService,
S: SyncProvider, {
/// Creates new `EthcoreClient` with default `Fetch`.
S: SyncProvider,
{
/// Creates new `ParityClient`.
pub fn new(
client: &Arc<C>,
miner: &Arc<M>,
sync: &Arc<S>,
net: &Arc<ManageNetwork>,
store: &Arc<AccountProvider>,
logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>,
signer: Option<Arc<SignerService>>,
dapps_port: Option<u16>,
) -> Self {
Self::with_fetch(client, miner, sync, net, logger, settings, signer, dapps_port)
}
}
impl<C, M, S: ?Sized, F> EthcoreClient<C, M, S, F> where
C: MiningBlockChainClient,
M: MinerService,
S: SyncProvider,
F: Fetch, {
/// Creates new `EthcoreClient` with customizable `Fetch`.
pub fn with_fetch(
client: &Arc<C>,
miner: &Arc<M>,
sync: &Arc<S>,
net: &Arc<ManageNetwork>,
logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>,
signer: Option<Arc<SignerService>>,
dapps_port: Option<u16>,
) -> Self {
EthcoreClient {
ParityClient {
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
sync: Arc::downgrade(sync),
net: Arc::downgrade(net),
accounts: Arc::downgrade(store),
logger: logger,
settings: settings,
signer: signer,
fetch: Mutex::new(F::default()),
dapps_port: dapps_port,
}
}
@ -113,11 +92,10 @@ impl<C, M, S: ?Sized, F> EthcoreClient<C, M, S, F> where
}
}
impl<C, M, S: ?Sized, F> Ethcore for EthcoreClient<C, M, S, F> where
impl<C, M, S: ?Sized> Parity for ParityClient<C, M, S> where
M: MinerService + 'static,
C: MiningBlockChainClient + 'static,
S: SyncProvider + 'static,
F: Fetch + 'static {
S: SyncProvider + 'static {
fn transactions_limit(&self) -> Result<usize, Error> {
try!(self.active());
@ -278,48 +256,6 @@ impl<C, M, S: ?Sized, F> Ethcore for EthcoreClient<C, M, S, F> where
Ok(take_weak!(self.miner).all_transactions().into_iter().map(Into::into).collect::<Vec<_>>())
}
fn hash_content(&self, ready: Ready<H256>, url: String) {
let res = self.active();
let hash_content = |result| {
let path = try!(result);
let mut file = io::BufReader::new(try!(fs::File::open(&path)));
// Try to hash
let result = sha3(&mut file);
// Remove file (always)
try!(fs::remove_file(&path));
// Return the result
Ok(try!(result))
};
match res {
Err(e) => ready.ready(Err(e)),
Ok(()) => {
let (tx, rx) = mpsc::channel();
let res = self.fetch.lock().request_async(&url, Default::default(), Box::new(move |result| {
let result = hash_content(result)
.map_err(errors::from_fetch_error)
.map(Into::into);
// Receive ready and invoke with result.
let ready: Ready<H256> = rx.recv().expect(
"recv() fails when `tx` has been dropped, if this closure is invoked `tx` is not dropped (`res == Ok()`); qed"
);
ready.ready(result);
}));
// Either invoke ready right away or transfer it to the closure.
if let Err(e) = res {
ready.ready(Err(errors::from_fetch_error(e)));
} else {
tx.send(ready).expect(
"send() fails when `rx` end is dropped, if `res == Ok()`: `rx` is moved to the closure; qed"
);
}
}
}
}
fn signer_port(&self) -> Result<u16, Error> {
try!(self.active());
@ -361,4 +297,22 @@ impl<C, M, S: ?Sized, F> Ethcore for EthcoreClient<C, M, S, F> where
fn enode(&self) -> Result<String, Error> {
take_weak!(self.sync).enode().ok_or_else(errors::network_disabled)
}
fn accounts(&self) -> Result<BTreeMap<String, BTreeMap<String, String>>, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
let info = try!(store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e)));
let other = store.addresses_info().expect("addresses_info always returns Ok; qed");
Ok(info.into_iter().chain(other.into_iter()).map(|(a, v)| {
let mut m = map![
"name".to_owned() => v.name,
"meta".to_owned() => v.meta
];
if let &Some(ref uuid) = &v.uuid {
m.insert("uuid".to_owned(), format!("{}", uuid));
}
(format!("0x{}", a.hex()), m)
}).collect())
}
}

View File

@ -16,33 +16,30 @@
//! Account management (personal) rpc implementation
use std::sync::{Arc, Weak};
use std::collections::BTreeMap;
use util::{Address};
use jsonrpc_core::*;
use ethkey::{Brain, Generator};
use v1::traits::PersonalAccounts;
use v1::types::{H160 as RpcH160, H256 as RpcH256, TransactionRequest};
use v1::helpers::errors;
use v1::helpers::dispatch::sign_and_dispatch;
use ethcore::account_provider::AccountProvider;
use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService;
use jsonrpc_core::{Value, Error, to_value};
use v1::traits::ParityAccounts;
use v1::types::{H160 as RpcH160, H256 as RpcH256};
use v1::helpers::errors;
/// Account management (personal) rpc implementation.
pub struct PersonalAccountsClient<C, M> where C: MiningBlockChainClient, M: MinerService {
pub struct ParityAccountsClient<C> where C: MiningBlockChainClient {
accounts: Weak<AccountProvider>,
client: Weak<C>,
miner: Weak<M>,
allow_perm_unlock: bool,
}
impl<C, M> PersonalAccountsClient<C, M> where C: MiningBlockChainClient, M: MinerService {
impl<C> ParityAccountsClient<C> where C: MiningBlockChainClient {
/// Creates new PersonalClient
pub fn new(store: &Arc<AccountProvider>, client: &Arc<C>, miner: &Arc<M>, allow_perm_unlock: bool) -> Self {
PersonalAccountsClient {
pub fn new(store: &Arc<AccountProvider>, client: &Arc<C>) -> Self {
ParityAccountsClient {
accounts: Arc::downgrade(store),
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
allow_perm_unlock: allow_perm_unlock,
}
}
@ -53,15 +50,25 @@ impl<C, M> PersonalAccountsClient<C, M> where C: MiningBlockChainClient, M: Mine
}
}
impl<C: 'static, M: 'static> PersonalAccounts for PersonalAccountsClient<C, M> where C: MiningBlockChainClient, M: MinerService {
fn new_account(&self, pass: String) -> Result<RpcH160, Error> {
impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlockChainClient {
fn accounts_info(&self) -> Result<BTreeMap<String, Value>, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
let info = try!(store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e)));
let other = store.addresses_info().expect("addresses_info always returns Ok; qed");
store.new_account(&pass)
.map(Into::into)
.map_err(|e| errors::account("Could not create account.", e))
Ok(info.into_iter().chain(other.into_iter()).map(|(a, v)| {
let m = map![
"name".to_owned() => to_value(&v.name),
"meta".to_owned() => to_value(&v.meta),
"uuid".to_owned() => if let &Some(ref uuid) = &v.uuid {
to_value(uuid)
} else {
Value::Null
}
];
(format!("0x{}", a.hex()), Value::Object(m))
}).collect())
}
fn new_account_from_phrase(&self, phrase: String, pass: String) -> Result<RpcH160, Error> {
@ -92,24 +99,6 @@ impl<C: 'static, M: 'static> PersonalAccounts for PersonalAccountsClient<C, M> w
.map_err(|e| errors::account("Could not create account.", e))
}
fn unlock_account(&self, account: RpcH160, account_pass: String, duration: Option<u64>) -> Result<bool, Error> {
try!(self.active());
let account: Address = account.into();
let store = take_weak!(self.accounts);
let r = match (self.allow_perm_unlock, duration) {
(false, _) => store.unlock_account_temporarily(account, account_pass),
(true, Some(0)) => store.unlock_account_permanently(account, account_pass),
(true, Some(d)) => store.unlock_account_timed(account, account_pass, d as u32 * 1000),
(true, None) => store.unlock_account_timed(account, account_pass, 300_000),
};
match r {
Ok(_) => Ok(true),
// TODO [ToDr] Proper error here?
Err(_) => Ok(false),
}
}
fn test_password(&self, account: RpcH160, password: String) -> Result<bool, Error> {
try!(self.active());
let account: Address = account.into();
@ -128,18 +117,6 @@ impl<C: 'static, M: 'static> PersonalAccounts for PersonalAccountsClient<C, M> w
.map_err(|e| errors::account("Could not fetch account info.", e))
}
fn sign_and_send_transaction(&self, request: TransactionRequest, password: String) -> Result<RpcH256, Error> {
try!(self.active());
sign_and_dispatch(
&*take_weak!(self.client),
&*take_weak!(self.miner),
&*take_weak!(self.accounts),
request.into(),
Some(password)
)
}
fn set_account_name(&self, addr: RpcH160, name: String) -> Result<bool, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
@ -162,6 +139,10 @@ impl<C: 'static, M: 'static> PersonalAccounts for PersonalAccountsClient<C, M> w
Ok(true)
}
fn set_account_visibility(&self, _address: RpcH160, _dapp: RpcH256, _visible: bool) -> Result<bool, Error> {
Ok(false)
}
fn import_geth_accounts(&self, addresses: Vec<RpcH160>) -> Result<Vec<RpcH160>, Error> {
let store = take_weak!(self.accounts);

View File

@ -14,36 +14,57 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
/// Ethcore-specific rpc interface for operations altering the settings.
use std::sync::{Arc, Weak};
use jsonrpc_core::*;
/// Parity-specific rpc interface for operations altering the settings.
use std::{fs, io};
use std::sync::{Arc, Weak, mpsc};
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
use ethcore::mode::Mode;
use ethsync::ManageNetwork;
use v1::helpers::errors;
use v1::traits::EthcoreSet;
use v1::types::{Bytes, H160, U256};
use fetch::{Client as FetchClient, Fetch};
use util::{Mutex, sha3};
/// Ethcore-specific rpc interface for operations altering the settings.
pub struct EthcoreSetClient<C, M> where
use jsonrpc_core::Error;
use v1::helpers::auto_args::Ready;
use v1::helpers::errors;
use v1::traits::ParitySet;
use v1::types::{Bytes, H160, H256, U256};
/// Parity-specific rpc interface for operations altering the settings.
pub struct ParitySetClient<C, M, F=FetchClient> where
C: MiningBlockChainClient,
M: MinerService
M: MinerService,
F: Fetch,
{
client: Weak<C>,
miner: Weak<M>,
net: Weak<ManageNetwork>,
fetch: Mutex<F>,
}
impl<C, M> EthcoreSetClient<C, M> where
impl<C, M> ParitySetClient<C, M, FetchClient> where
C: MiningBlockChainClient,
M: MinerService {
/// Creates new `EthcoreSetClient`.
M: MinerService
{
/// Creates new `ParitySetClient` with default `FetchClient`.
pub fn new(client: &Arc<C>, miner: &Arc<M>, net: &Arc<ManageNetwork>) -> Self {
EthcoreSetClient {
Self::with_fetch(client, miner, net)
}
}
impl<C, M, F> ParitySetClient<C, M, F> where
C: MiningBlockChainClient,
M: MinerService,
F: Fetch,
{
/// Creates new `ParitySetClient` with default `FetchClient`.
pub fn with_fetch(client: &Arc<C>, miner: &Arc<M>, net: &Arc<ManageNetwork>) -> Self {
ParitySetClient {
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
net: Arc::downgrade(net),
fetch: Mutex::new(F::default()),
}
}
@ -54,9 +75,11 @@ impl<C, M> EthcoreSetClient<C, M> where
}
}
impl<C, M> EthcoreSet for EthcoreSetClient<C, M> where
impl<C, M, F> ParitySet for ParitySetClient<C, M, F> where
C: MiningBlockChainClient + 'static,
M: MinerService + 'static {
M: MinerService + 'static,
F: Fetch + 'static,
{
fn set_min_gas_price(&self, gas_price: U256) -> Result<bool, Error> {
try!(self.active());
@ -159,4 +182,46 @@ impl<C, M> EthcoreSet for EthcoreSetClient<C, M> where
});
Ok(true)
}
fn hash_content(&self, ready: Ready<H256>, url: String) {
let res = self.active();
let hash_content = |result| {
let path = try!(result);
let mut file = io::BufReader::new(try!(fs::File::open(&path)));
// Try to hash
let result = sha3(&mut file);
// Remove file (always)
try!(fs::remove_file(&path));
// Return the result
Ok(try!(result))
};
match res {
Err(e) => ready.ready(Err(e)),
Ok(()) => {
let (tx, rx) = mpsc::channel();
let res = self.fetch.lock().request_async(&url, Default::default(), Box::new(move |result| {
let result = hash_content(result)
.map_err(errors::from_fetch_error)
.map(Into::into);
// Receive ready and invoke with result.
let ready: Ready<H256> = rx.recv().expect(
"recv() fails when `tx` has been dropped, if this closure is invoked `tx` is not dropped (`res == Ok()`); qed"
);
ready.ready(result);
}));
// Either invoke ready right away or transfer it to the closure.
if let Err(e) = res {
ready.ready(Err(errors::from_fetch_error(e)));
} else {
tx.send(ready).expect(
"send() fails when `rx` end is dropped, if `res == Ok()`: `rx` is moved to the closure; qed"
);
}
}
}
}
}

View File

@ -16,26 +16,34 @@
//! Account management (personal) rpc implementation
use std::sync::{Arc, Weak};
use std::collections::{BTreeMap};
use jsonrpc_core::*;
use v1::traits::Personal;
use v1::types::{H160 as RpcH160};
use v1::helpers::errors;
use ethcore::account_provider::AccountProvider;
use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService;
use util::Address;
use jsonrpc_core::Error;
use v1::traits::Personal;
use v1::types::{H160 as RpcH160, H256 as RpcH256, TransactionRequest};
use v1::helpers::errors;
use v1::helpers::dispatch::sign_and_dispatch;
/// Account management (personal) rpc implementation.
pub struct PersonalClient<C> where C: MiningBlockChainClient {
pub struct PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService {
accounts: Weak<AccountProvider>,
client: Weak<C>,
miner: Weak<M>,
allow_perm_unlock: bool,
}
impl<C> PersonalClient<C> where C: MiningBlockChainClient {
impl<C, M> PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService {
/// Creates new PersonalClient
pub fn new(store: &Arc<AccountProvider>, client: &Arc<C>) -> Self {
pub fn new(store: &Arc<AccountProvider>, client: &Arc<C>, miner: &Arc<M>, allow_perm_unlock: bool) -> Self {
PersonalClient {
accounts: Arc::downgrade(store),
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
allow_perm_unlock: allow_perm_unlock,
}
}
@ -46,8 +54,7 @@ impl<C> PersonalClient<C> where C: MiningBlockChainClient {
}
}
impl<C: 'static> Personal for PersonalClient<C> where C: MiningBlockChainClient {
impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService {
fn accounts(&self) -> Result<Vec<RpcH160>, Error> {
try!(self.active());
@ -56,23 +63,42 @@ impl<C: 'static> Personal for PersonalClient<C> where C: MiningBlockChainClient
Ok(accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
}
fn accounts_info(&self) -> Result<BTreeMap<String, Value>, Error> {
fn new_account(&self, pass: String) -> Result<RpcH160, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
let info = try!(store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e)));
let other = store.addresses_info().expect("addresses_info always returns Ok; qed");
Ok(info.into_iter().chain(other.into_iter()).map(|(a, v)| {
let m = map![
"name".to_owned() => to_value(&v.name),
"meta".to_owned() => to_value(&v.meta),
"uuid".to_owned() => if let &Some(ref uuid) = &v.uuid {
to_value(uuid)
} else {
Value::Null
}
];
(format!("0x{}", a.hex()), Value::Object(m))
}).collect())
store.new_account(&pass)
.map(Into::into)
.map_err(|e| errors::account("Could not create account.", e))
}
fn unlock_account(&self, account: RpcH160, account_pass: String, duration: Option<u64>) -> Result<bool, Error> {
try!(self.active());
let account: Address = account.into();
let store = take_weak!(self.accounts);
let r = match (self.allow_perm_unlock, duration) {
(false, _) => store.unlock_account_temporarily(account, account_pass),
(true, Some(0)) => store.unlock_account_permanently(account, account_pass),
(true, Some(d)) => store.unlock_account_timed(account, account_pass, d as u32 * 1000),
(true, None) => store.unlock_account_timed(account, account_pass, 300_000),
};
match r {
Ok(_) => Ok(true),
// TODO [ToDr] Proper error here?
Err(_) => Ok(false),
}
}
fn sign_and_send_transaction(&self, request: TransactionRequest, password: String) -> Result<RpcH256, Error> {
try!(self.active());
sign_and_dispatch(
&*take_weak!(self.client),
&*take_weak!(self.miner),
&*take_weak!(self.accounts),
request.into(),
Some(password)
)
}
}

View File

@ -14,14 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Transactions Confirmations (personal) rpc implementation
//! Transactions Confirmations rpc implementation
use std::sync::{Arc, Weak};
use jsonrpc_core::*;
use ethcore::account_provider::AccountProvider;
use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService;
use v1::traits::PersonalSigner;
use v1::traits::Signer;
use v1::types::{TransactionModification, ConfirmationRequest, U256};
use v1::helpers::{errors, SignerService, SigningQueue, ConfirmationPayload};
use v1::helpers::dispatch::{sign_and_dispatch, sign, decrypt};
@ -58,7 +58,7 @@ impl<C: 'static, M: 'static> SignerClient<C, M> where C: MiningBlockChainClient,
}
}
impl<C: 'static, M: 'static> PersonalSigner for SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
fn requests_to_confirm(&self) -> Result<Vec<ConfirmationRequest>, Error> {
try!(self.active());

View File

@ -14,43 +14,22 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Eth Signing RPC implementation.
//! Signing RPC implementation.
use std::sync::{Arc, Weak};
use jsonrpc_core::*;
use ethcore::account_provider::AccountProvider;
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
use util::{U256, Address, H256, Mutex};
use transient_hashmap::TransientHashMap;
use ethcore::account_provider::AccountProvider;
use util::{U256, Address, H256, Mutex};
use jsonrpc_core::*;
use v1::helpers::{errors, SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest, SignerService};
use v1::helpers::dispatch::{default_gas_price, sign_and_dispatch, sign, decrypt};
use v1::traits::EthSigning;
use v1::traits::{EthSigning, ParitySigning};
use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, U256 as RpcU256, Bytes as RpcBytes};
fn fill_optional_fields<C, M>(request: TRequest, client: &C, miner: &M) -> FilledRequest
where C: MiningBlockChainClient, M: MinerService {
FilledRequest {
from: request.from,
to: request.to,
nonce: request.nonce,
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
value: request.value.unwrap_or_else(|| 0.into()),
data: request.data.unwrap_or_else(Vec::new),
}
}
/// Implementation of functions that require signing when no trusted signer is used.
pub struct EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
signer: Weak<SignerService>,
accounts: Weak<AccountProvider>,
client: Weak<C>,
miner: Weak<M>,
pending: Mutex<TransientHashMap<U256, ConfirmationPromise>>,
}
const MAX_PENDING_DURATION: u64 = 60 * 60;
pub enum DispatchResult {
@ -58,10 +37,23 @@ pub enum DispatchResult {
Value(Value),
}
impl<C, M> EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
/// Implementation of functions that require signing when no trusted signer is used.
pub struct SigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
signer: Weak<SignerService>,
accounts: Weak<AccountProvider>,
client: Weak<C>,
miner: Weak<M>,
pending: Mutex<TransientHashMap<U256, ConfirmationPromise>>,
}
impl<C, M> SigningQueueClient<C, M> where
C: MiningBlockChainClient,
M: MinerService,
{
/// Creates a new signing queue client given shared signing queue.
pub fn new(signer: &Arc<SignerService>, client: &Arc<C>, miner: &Arc<M>, accounts: &Arc<AccountProvider>) -> Self {
EthSigningQueueClient {
SigningQueueClient {
signer: Arc::downgrade(signer),
accounts: Arc::downgrade(accounts),
client: Arc::downgrade(client),
@ -132,10 +124,10 @@ impl<C, M> EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: Miner
}
}
impl<C, M> EthSigning for EthSigningQueueClient<C, M>
where C: MiningBlockChainClient + 'static, M: MinerService + 'static
impl<C: 'static, M: 'static> ParitySigning for SigningQueueClient<C, M> where
C: MiningBlockChainClient,
M: MinerService,
{
fn post_sign(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
self.dispatch_sign(params).map(|result| match result {
@ -178,16 +170,6 @@ impl<C, M> EthSigning for EthSigningQueueClient<C, M>
})
}
fn sign(&self, params: Params, ready: Ready) {
let res = self.active().and_then(|_| self.dispatch_sign(params));
self.handle_dispatch(res, ready);
}
fn send_transaction(&self, params: Params, ready: Ready) {
let res = self.active().and_then(|_| self.dispatch_transaction(params));
self.handle_dispatch(res, ready);
}
fn decrypt_message(&self, params: Params, ready: Ready) {
let res = self.active()
.and_then(|_| from_params::<(RpcH160, RpcBytes)>(params))
@ -205,76 +187,30 @@ impl<C, M> EthSigning for EthSigningQueueClient<C, M>
}
}
/// Implementation of functions that require signing when no trusted signer is used.
pub struct EthSigningUnsafeClient<C, M> where
impl<C: 'static, M: 'static> EthSigning for SigningQueueClient<C, M> where
C: MiningBlockChainClient,
M: MinerService {
client: Weak<C>,
accounts: Weak<AccountProvider>,
miner: Weak<M>,
}
impl<C, M> EthSigningUnsafeClient<C, M> where
C: MiningBlockChainClient,
M: MinerService {
/// Creates new EthClient.
pub fn new(client: &Arc<C>, accounts: &Arc<AccountProvider>, miner: &Arc<M>)
-> Self {
EthSigningUnsafeClient {
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
accounts: Arc::downgrade(accounts),
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
impl<C, M> EthSigning for EthSigningUnsafeClient<C, M> where
C: MiningBlockChainClient + 'static,
M: MinerService + 'static {
M: MinerService,
{
fn sign(&self, params: Params, ready: Ready) {
ready.ready(self.active()
.and_then(|_| from_params::<(RpcH160, RpcH256)>(params))
.and_then(|(address, msg)| {
sign(&*take_weak!(self.accounts), address.into(), None, msg.into())
}))
let res = self.active().and_then(|_| self.dispatch_sign(params));
self.handle_dispatch(res, ready);
}
fn send_transaction(&self, params: Params, ready: Ready) {
ready.ready(self.active()
.and_then(|_| from_params::<(TransactionRequest, )>(params))
.and_then(|(request, )| {
sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), &*take_weak!(self.accounts), request.into(), None).map(to_value)
}))
}
fn decrypt_message(&self, params: Params, ready: Ready) {
ready.ready(self.active()
.and_then(|_| from_params::<(RpcH160, RpcBytes)>(params))
.and_then(|(address, ciphertext)| {
decrypt(&*take_weak!(self.accounts), address.into(), None, ciphertext.0)
}))
}
fn post_sign(&self, _: Params) -> Result<Value, Error> {
// We don't support this in non-signer mode.
Err(errors::signer_disabled())
}
fn post_transaction(&self, _: Params) -> Result<Value, Error> {
// We don't support this in non-signer mode.
Err(errors::signer_disabled())
}
fn check_request(&self, _: Params) -> Result<Value, Error> {
// We don't support this in non-signer mode.
Err(errors::signer_disabled())
let res = self.active().and_then(|_| self.dispatch_transaction(params));
self.handle_dispatch(res, ready);
}
}
fn fill_optional_fields<C, M>(request: TRequest, client: &C, miner: &M) -> FilledRequest
where C: MiningBlockChainClient, M: MinerService {
FilledRequest {
from: request.from,
to: request.to,
nonce: request.nonce,
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
value: request.value.unwrap_or_else(|| 0.into()),
data: request.data.unwrap_or_else(Vec::new),
}
}

View File

@ -0,0 +1,110 @@
// 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 <http://www.gnu.org/licenses/>.
//! Unsafe Signing RPC implementation.
use std::sync::{Arc, Weak};
use ethcore::account_provider::AccountProvider;
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
use jsonrpc_core::*;
use v1::helpers::errors;
use v1::helpers::dispatch::{sign_and_dispatch, sign, decrypt};
use v1::traits::{EthSigning, ParitySigning};
use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, Bytes as RpcBytes};
/// Implementation of functions that require signing when no trusted signer is used.
pub struct SigningUnsafeClient<C, M> where
C: MiningBlockChainClient,
M: MinerService,
{
accounts: Weak<AccountProvider>,
client: Weak<C>,
miner: Weak<M>,
}
impl<C, M> SigningUnsafeClient<C, M> where
C: MiningBlockChainClient,
M: MinerService,
{
/// Creates new SigningUnsafeClient.
pub fn new(client: &Arc<C>, accounts: &Arc<AccountProvider>, miner: &Arc<M>)
-> Self {
SigningUnsafeClient {
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
accounts: Arc::downgrade(accounts),
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
impl<C: 'static, M: 'static> EthSigning for SigningUnsafeClient<C, M> where
C: MiningBlockChainClient,
M: MinerService,
{
fn sign(&self, params: Params, ready: Ready) {
ready.ready(self.active()
.and_then(|_| from_params::<(RpcH160, RpcH256)>(params))
.and_then(|(address, msg)| {
sign(&*take_weak!(self.accounts), address.into(), None, msg.into())
}))
}
fn send_transaction(&self, params: Params, ready: Ready) {
ready.ready(self.active()
.and_then(|_| from_params::<(TransactionRequest, )>(params))
.and_then(|(request, )| {
sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), &*take_weak!(self.accounts), request.into(), None).map(to_value)
}))
}
}
impl<C: 'static, M: 'static> ParitySigning for SigningUnsafeClient<C, M> where
C: MiningBlockChainClient,
M: MinerService,
{
fn decrypt_message(&self, params: Params, ready: Ready) {
ready.ready(self.active()
.and_then(|_| from_params::<(RpcH160, RpcBytes)>(params))
.and_then(|(address, ciphertext)| {
decrypt(&*take_weak!(self.accounts), address.into(), None, ciphertext.0)
}))
}
fn post_sign(&self, _: Params) -> Result<Value, Error> {
// We don't support this in non-signer mode.
Err(errors::signer_disabled())
}
fn post_transaction(&self, _: Params) -> Result<Value, Error> {
// We don't support this in non-signer mode.
Err(errors::signer_disabled())
}
fn check_request(&self, _: Params) -> Result<Value, Error> {
// We don't support this in non-signer mode.
Err(errors::signer_disabled())
}
}

View File

@ -26,6 +26,6 @@ pub mod traits;
pub mod tests;
pub mod types;
pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Personal, PersonalAccounts, PersonalSigner, Net, Ethcore, EthcoreSet, Traces, Rpc};
pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Net, Parity, ParityAccounts, ParitySet, ParitySigning, Signer, Personal, Traces, Rpc};
pub use self::impls::*;
pub use self::helpers::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, block_import};

View File

@ -33,7 +33,7 @@ use util::{U256, H256, Uint, Address};
use jsonrpc_core::IoHandler;
use ethjson::blockchain::BlockChain;
use v1::impls::{EthClient, EthSigningUnsafeClient};
use v1::impls::{EthClient, SigningUnsafeClient};
use v1::types::U256 as NU256;
use v1::traits::eth::Eth;
use v1::traits::eth_signing::EthSigning;
@ -140,7 +140,7 @@ impl EthTester {
&external_miner,
Default::default(),
);
let eth_sign = EthSigningUnsafeClient::new(
let eth_sign = SigningUnsafeClient::new(
&client,
&account_provider,
&miner_service

View File

@ -27,7 +27,7 @@ use ethcore::receipt::LocalizedReceipt;
use ethcore::transaction::{Transaction, Action};
use ethcore::miner::{ExternalMiner, MinerService};
use ethsync::SyncState;
use v1::{Eth, EthClient, EthClientOptions, EthFilter, EthFilterClient, EthSigning, EthSigningUnsafeClient};
use v1::{Eth, EthClient, EthClientOptions, EthFilter, EthFilterClient, EthSigning, SigningUnsafeClient};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestSnapshotService};
use rustc_serialize::hex::ToHex;
use time::get_time;
@ -83,7 +83,7 @@ impl EthTester {
let external_miner = Arc::new(ExternalMiner::new(hashrates.clone()));
let eth = EthClient::new(&client, &snapshot, &sync, &ap, &miner, &external_miner, options).to_delegate();
let filter = EthFilterClient::new(&client, &miner).to_delegate();
let sign = EthSigningUnsafeClient::new(&client, &ap, &miner).to_delegate();
let sign = SigningUnsafeClient::new(&client, &ap, &miner).to_delegate();
let io = IoHandler::new();
io.add_delegate(eth);
io.add_delegate(sign);

View File

@ -18,12 +18,13 @@
//! method calls properly.
mod eth;
mod eth_signing;
mod net;
mod web3;
mod personal;
mod personal_signer;
mod ethcore;
mod ethcore_set;
mod parity;
mod parity_accounts;
mod parity_set;
mod rpc;
mod signer;
mod signing;
mod manage_network;

View File

@ -16,19 +16,19 @@
use std::sync::Arc;
use util::log::RotatingLogger;
use util::{Address};
use util::Address;
use ethsync::ManageNetwork;
use ethcore::client::{TestBlockChainClient};
use ethcore::account_provider::AccountProvider;
use ethstore::ethkey::{Generator, Random};
use jsonrpc_core::IoHandler;
use v1::{Ethcore, EthcoreClient};
use v1::{Parity, ParityClient};
use v1::helpers::{SignerService, NetworkSettings};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestFetch};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService};
use super::manage_network::TestManageNetwork;
pub type TestEthcoreClient = EthcoreClient<TestBlockChainClient, TestMinerService, TestSyncProvider, TestFetch>;
pub type TestParityClient = ParityClient<TestBlockChainClient, TestMinerService, TestSyncProvider>;
pub struct Dependencies {
pub miner: Arc<TestMinerService>,
@ -37,6 +37,7 @@ pub struct Dependencies {
pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>,
pub network: Arc<ManageNetwork>,
pub accounts: Arc<AccountProvider>,
pub dapps_port: Option<u16>,
}
@ -59,16 +60,18 @@ impl Dependencies {
rpc_port: 8545,
}),
network: Arc::new(TestManageNetwork),
accounts: Arc::new(AccountProvider::transient_provider()),
dapps_port: Some(18080),
}
}
pub fn client(&self, signer: Option<Arc<SignerService>>) -> TestEthcoreClient {
EthcoreClient::with_fetch(
pub fn client(&self, signer: Option<Arc<SignerService>>) -> TestParityClient {
ParityClient::new(
&self.client,
&self.miner,
&self.sync,
&self.network,
&self.accounts,
self.logger.clone(),
self.settings.clone(),
signer,
@ -90,105 +93,105 @@ impl Dependencies {
}
#[test]
fn rpc_ethcore_extra_data() {
fn rpc_parity_extra_data() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_extraData", "params": [], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_extraData", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x01020304","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_default_extra_data() {
fn rpc_parity_default_extra_data() {
use util::misc;
use util::ToPretty;
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_defaultExtraData", "params": [], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_defaultExtraData", "params": [], "id": 1}"#;
let response = format!(r#"{{"jsonrpc":"2.0","result":"0x{}","id":1}}"#, misc::version_data().to_hex());
assert_eq!(io.handle_request_sync(request), Some(response));
}
#[test]
fn rpc_ethcore_gas_floor_target() {
fn rpc_parity_gas_floor_target() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_gasFloorTarget", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x3039","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_min_gas_price() {
fn rpc_parity_min_gas_price() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_minGasPrice", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x1312d00","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_dev_logs() {
fn rpc_parity_dev_logs() {
let deps = Dependencies::new();
deps.logger.append("a".to_owned());
deps.logger.append("b".to_owned());
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogs", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_devLogs", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":["b","a"],"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_dev_logs_levels() {
fn rpc_parity_dev_logs_levels() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogsLevels", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_devLogsLevels", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"rpc=trace","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_transactions_limit() {
fn rpc_parity_transactions_limit() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_transactionsLimit", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":1024,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_net_chain() {
fn rpc_parity_net_chain() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_netChain", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"testchain","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_net_peers() {
fn rpc_parity_net_peers() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPeers", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_netPeers", "params":[], "id": 1}"#;
let response = "{\"jsonrpc\":\"2.0\",\"result\":{\"active\":0,\"connected\":120,\"max\":50,\"peers\":[{\"caps\":[\"eth/62\",\"eth/63\"],\
\"id\":\"node1\",\"name\":\"Parity/1\",\"network\":{\"localAddress\":\"127.0.0.1:8888\",\"remoteAddress\":\"127.0.0.1:7777\"}\
,\"protocols\":{\"eth\":{\"difficulty\":\"0x28\",\"head\":\"0000000000000000000000000000000000000000000000000000000000000032\"\
@ -200,101 +203,90 @@ fn rpc_ethcore_net_peers() {
}
#[test]
fn rpc_ethcore_net_port() {
fn rpc_parity_net_port() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_netPort", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":30303,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_rpc_settings() {
fn rpc_parity_rpc_settings() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_rpcSettings", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_rpcSettings", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"enabled":true,"interface":"all","port":8545},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_node_name() {
fn rpc_parity_node_name() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_nodeName", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"mynode","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_unsigned_transactions_count() {
fn rpc_parity_unsigned_transactions_count() {
let deps = Dependencies::new();
let io = deps.with_signer(SignerService::new_test(Some(18180)));
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_unsignedTransactionsCount", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":0,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_unsigned_transactions_count_when_signer_disabled() {
fn rpc_parity_unsigned_transactions_count_when_signer_disabled() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_unsignedTransactionsCount", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32030,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_hash_content() {
fn rpc_parity_pending_transactions() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_hashContent", "params":["https://ethcore.io/assets/images/ethcore-black-horizontal.png"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_pending_transactions() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_pendingTransactions", "params":[], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_pendingTransactions", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":[],"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_ethcore_encrypt() {
fn rpc_parity_encrypt() {
let deps = Dependencies::new();
let io = deps.default_client();
let key = format!("{:?}", Random.generate().unwrap().public());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_encryptMessage", "params":["0x"#.to_owned() + &key + r#"", "0x01"], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_encryptMessage", "params":["0x"#.to_owned() + &key + r#"", "0x01"], "id": 1}"#;
assert!(io.handle_request_sync(&request).unwrap().contains("result"), "Should return success.");
}
#[test]
fn rpc_ethcore_signer_port() {
fn rpc_parity_signer_port() {
// given
let deps = Dependencies::new();
let io1 = deps.with_signer(SignerService::new_test(Some(18180)));
let io2 = deps.default_client();
// when
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_signerPort", "params": [], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_signerPort", "params": [], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":18180,"id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32030,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#;
@ -304,7 +296,7 @@ fn rpc_ethcore_signer_port() {
}
#[test]
fn rpc_ethcore_dapps_port() {
fn rpc_parity_dapps_port() {
// given
let mut deps = Dependencies::new();
let io1 = deps.default_client();
@ -312,7 +304,7 @@ fn rpc_ethcore_dapps_port() {
let io2 = deps.default_client();
// when
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_dappsPort", "params": [], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsPort", "params": [], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":18080,"id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32031,"message":"Dapps Server is disabled. This API is not available.","data":null},"id":1}"#;
@ -322,7 +314,7 @@ fn rpc_ethcore_dapps_port() {
}
#[test]
fn rpc_ethcore_next_nonce() {
fn rpc_parity_next_nonce() {
let deps = Dependencies::new();
let address = Address::default();
let io1 = deps.default_client();
@ -332,7 +324,7 @@ fn rpc_ethcore_next_nonce() {
let request = r#"{
"jsonrpc": "2.0",
"method": "ethcore_nextNonce",
"method": "parity_nextNonce",
"params": [""#.to_owned() + &format!("0x{:?}", address) + r#""],
"id": 1
}"#;

View File

@ -0,0 +1,118 @@
// 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 <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use ethcore::account_provider::AccountProvider;
use ethcore::client::TestBlockChainClient;
use jsonrpc_core::IoHandler;
use v1::{ParityAccounts, ParityAccountsClient};
struct ParityAccountsTester {
accounts: Arc<AccountProvider>,
io: IoHandler,
// these unused fields are necessary to keep the data alive
// as the handler has only weak pointers.
_client: Arc<TestBlockChainClient>,
}
fn blockchain_client() -> Arc<TestBlockChainClient> {
let client = TestBlockChainClient::new();
Arc::new(client)
}
fn accounts_provider() -> Arc<AccountProvider> {
Arc::new(AccountProvider::transient_provider())
}
fn setup() -> ParityAccountsTester {
let accounts = accounts_provider();
let client = blockchain_client();
let parity_accounts = ParityAccountsClient::new(&accounts, &client);
let io = IoHandler::new();
io.add_delegate(parity_accounts.to_delegate());
let tester = ParityAccountsTester {
accounts: accounts,
io: io,
_client: client,
};
tester
}
#[test]
fn should_be_able_to_get_account_info() {
let tester = setup();
tester.accounts.new_account("").unwrap();
let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1);
let address = accounts[0];
let uuid = tester.accounts.accounts_info().unwrap().get(&address).unwrap().uuid.as_ref().unwrap().clone();
tester.accounts.set_account_name(address.clone(), "Test".to_owned()).unwrap();
tester.accounts.set_account_meta(address.clone(), "{foo: 69}".to_owned()).unwrap();
let request = r#"{"jsonrpc": "2.0", "method": "parity_accountsInfo", "params": [], "id": 1}"#;
let res = tester.io.handle_request_sync(request);
let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"meta\":\"{{foo: 69}}\",\"name\":\"Test\",\"uuid\":\"{}\"}}}},\"id\":1}}", address.hex(), uuid);
assert_eq!(res, Some(response));
}
#[test]
fn should_be_able_to_set_name() {
let tester = setup();
tester.accounts.new_account("").unwrap();
let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1);
let address = accounts[0];
let request = format!(r#"{{"jsonrpc": "2.0", "method": "parity_setAccountName", "params": ["0x{}", "Test"], "id": 1}}"#, address.hex());
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
let res = tester.io.handle_request_sync(&request);
assert_eq!(res, Some(response.into()));
let uuid = tester.accounts.accounts_info().unwrap().get(&address).unwrap().uuid.as_ref().unwrap().clone();
let request = r#"{"jsonrpc": "2.0", "method": "parity_accountsInfo", "params": [], "id": 1}"#;
let res = tester.io.handle_request_sync(request);
let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"meta\":\"{{}}\",\"name\":\"Test\",\"uuid\":\"{}\"}}}},\"id\":1}}", address.hex(), uuid);
assert_eq!(res, Some(response));
}
#[test]
fn should_be_able_to_set_meta() {
let tester = setup();
tester.accounts.new_account("").unwrap();
let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1);
let address = accounts[0];
let request = format!(r#"{{"jsonrpc": "2.0", "method": "parity_setAccountMeta", "params": ["0x{}", "{{foo: 69}}"], "id": 1}}"#, address.hex());
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
let res = tester.io.handle_request_sync(&request);
assert_eq!(res, Some(response.into()));
let uuid = tester.accounts.accounts_info().unwrap().get(&address).unwrap().uuid.as_ref().unwrap().clone();
let request = r#"{"jsonrpc": "2.0", "method": "parity_accountsInfo", "params": [], "id": 1}"#;
let res = tester.io.handle_request_sync(request);
let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"meta\":\"{{foo: 69}}\",\"name\":\"{}\",\"uuid\":\"{}\"}}}},\"id\":1}}", address.hex(), uuid, uuid);
assert_eq!(res, Some(response));
}

View File

@ -16,16 +16,18 @@
use std::sync::Arc;
use std::str::FromStr;
use jsonrpc_core::IoHandler;
use v1::{EthcoreSet, EthcoreSetClient};
use rustc_serialize::hex::FromHex;
use util::{U256, Address};
use ethcore::miner::MinerService;
use ethcore::client::TestBlockChainClient;
use v1::tests::helpers::TestMinerService;
use util::{U256, Address};
use rustc_serialize::hex::FromHex;
use super::manage_network::TestManageNetwork;
use ethsync::ManageNetwork;
use jsonrpc_core::IoHandler;
use v1::{ParitySet, ParitySetClient};
use v1::tests::helpers::{TestMinerService, TestFetch};
use super::manage_network::TestManageNetwork;
fn miner_service() -> Arc<TestMinerService> {
Arc::new(TestMinerService::default())
}
@ -38,19 +40,21 @@ fn network_service() -> Arc<TestManageNetwork> {
Arc::new(TestManageNetwork)
}
fn ethcore_set_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>, net: &Arc<TestManageNetwork>) -> EthcoreSetClient<TestBlockChainClient, TestMinerService> {
EthcoreSetClient::new(client, miner, &(net.clone() as Arc<ManageNetwork>))
pub type TestParitySetClient = ParitySetClient<TestBlockChainClient, TestMinerService, TestFetch>;
fn parity_set_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>, net: &Arc<TestManageNetwork>) -> TestParitySetClient {
ParitySetClient::with_fetch(client, miner, &(net.clone() as Arc<ManageNetwork>))
}
#[test]
fn rpc_ethcore_set_min_gas_price() {
fn rpc_parity_set_min_gas_price() {
let miner = miner_service();
let client = client_service();
let network = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_set_client(&client, &miner, &network).to_delegate());
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
@ -58,14 +62,14 @@ fn rpc_ethcore_set_min_gas_price() {
}
#[test]
fn rpc_ethcore_set_gas_floor_target() {
fn rpc_parity_set_gas_floor_target() {
let miner = miner_service();
let client = client_service();
let network = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_set_client(&client, &miner, &network).to_delegate());
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
@ -73,14 +77,14 @@ fn rpc_ethcore_set_gas_floor_target() {
}
#[test]
fn rpc_ethcore_set_extra_data() {
fn rpc_parity_set_extra_data() {
let miner = miner_service();
let client = client_service();
let network = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_set_client(&client, &miner, &network).to_delegate());
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
@ -88,14 +92,14 @@ fn rpc_ethcore_set_extra_data() {
}
#[test]
fn rpc_ethcore_set_author() {
fn rpc_parity_set_author() {
let miner = miner_service();
let client = client_service();
let network = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_set_client(&client, &miner, &network).to_delegate());
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
@ -103,16 +107,31 @@ fn rpc_ethcore_set_author() {
}
#[test]
fn rpc_ethcore_set_transactions_limit() {
fn rpc_parity_set_transactions_limit() {
let miner = miner_service();
let client = client_service();
let network = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_set_client(&client, &miner, &network).to_delegate());
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setTransactionsLimit", "params":[10240240], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_setTransactionsLimit", "params":[10240240], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
assert_eq!(miner.transactions_limit(), 10_240_240);
}
}
#[test]
fn rpc_parity_set_hash_content() {
let miner = miner_service();
let client = client_service();
let network = network_service();
let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_hashContent", "params":["https://ethcore.io/assets/images/ethcore-black-horizontal.png"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}

View File

@ -19,7 +19,7 @@ use std::str::FromStr;
use jsonrpc_core::IoHandler;
use util::{U256, Uint, Address};
use ethcore::account_provider::AccountProvider;
use v1::{PersonalClient, PersonalAccountsClient, PersonalAccounts, Personal};
use v1::{PersonalClient, Personal};
use v1::tests::helpers::TestMinerService;
use ethcore::client::TestBlockChainClient;
use ethcore::transaction::{Action, Transaction};
@ -50,12 +50,10 @@ fn setup() -> PersonalTester {
let accounts = accounts_provider();
let client = blockchain_client();
let miner = miner_service();
let personal = PersonalClient::new(&accounts, &client);
let personal_accounts = PersonalAccountsClient::new(&accounts, &client, &miner, false);
let personal = PersonalClient::new(&accounts, &client, &miner, false);
let io = IoHandler::new();
io.add_delegate(personal.to_delegate());
io.add_delegate(personal_accounts.to_delegate());
let tester = PersonalTester {
accounts: accounts,
@ -92,66 +90,6 @@ fn new_account() {
assert_eq!(res, Some(response));
}
#[test]
fn should_be_able_to_get_account_info() {
let tester = setup();
tester.accounts.new_account("").unwrap();
let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1);
let address = accounts[0];
let uuid = tester.accounts.accounts_info().unwrap().get(&address).unwrap().uuid.as_ref().unwrap().clone();
tester.accounts.set_account_name(address.clone(), "Test".to_owned()).unwrap();
tester.accounts.set_account_meta(address.clone(), "{foo: 69}".to_owned()).unwrap();
let request = r#"{"jsonrpc": "2.0", "method": "personal_accountsInfo", "params": [], "id": 1}"#;
let res = tester.io.handle_request_sync(request);
let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"meta\":\"{{foo: 69}}\",\"name\":\"Test\",\"uuid\":\"{}\"}}}},\"id\":1}}", address.hex(), uuid);
assert_eq!(res, Some(response));
}
#[test]
fn should_be_able_to_set_name() {
let tester = setup();
tester.accounts.new_account("").unwrap();
let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1);
let address = accounts[0];
let request = format!(r#"{{"jsonrpc": "2.0", "method": "personal_setAccountName", "params": ["0x{}", "Test"], "id": 1}}"#, address.hex());
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
let res = tester.io.handle_request_sync(&request);
assert_eq!(res, Some(response.into()));
let uuid = tester.accounts.accounts_info().unwrap().get(&address).unwrap().uuid.as_ref().unwrap().clone();
let request = r#"{"jsonrpc": "2.0", "method": "personal_accountsInfo", "params": [], "id": 1}"#;
let res = tester.io.handle_request_sync(request);
let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"meta\":\"{{}}\",\"name\":\"Test\",\"uuid\":\"{}\"}}}},\"id\":1}}", address.hex(), uuid);
assert_eq!(res, Some(response));
}
#[test]
fn should_be_able_to_set_meta() {
let tester = setup();
tester.accounts.new_account("").unwrap();
let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1);
let address = accounts[0];
let request = format!(r#"{{"jsonrpc": "2.0", "method": "personal_setAccountMeta", "params": ["0x{}", "{{foo: 69}}"], "id": 1}}"#, address.hex());
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
let res = tester.io.handle_request_sync(&request);
assert_eq!(res, Some(response.into()));
let uuid = tester.accounts.accounts_info().unwrap().get(&address).unwrap().uuid.as_ref().unwrap().clone();
let request = r#"{"jsonrpc": "2.0", "method": "personal_accountsInfo", "params": [], "id": 1}"#;
let res = tester.io.handle_request_sync(request);
let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"meta\":\"{{foo: 69}}\",\"name\":\"{}\",\"uuid\":\"{}\"}}}},\"id\":1}}", address.hex(), uuid, uuid);
assert_eq!(res, Some(response));
}
#[test]
fn sign_and_send_transaction_with_invalid_password() {
let tester = setup();

View File

@ -21,11 +21,11 @@ use util::{U256, Uint, Address};
use ethcore::account_provider::AccountProvider;
use ethcore::client::TestBlockChainClient;
use ethcore::transaction::{Transaction, Action};
use v1::{SignerClient, PersonalSigner};
use v1::{SignerClient, Signer};
use v1::tests::helpers::TestMinerService;
use v1::helpers::{SigningQueue, SignerService, FilledTransactionRequest, ConfirmationPayload};
struct PersonalSignerTester {
struct SignerTester {
signer: Arc<SignerService>,
accounts: Arc<AccountProvider>,
io: IoHandler,
@ -48,7 +48,7 @@ fn miner_service() -> Arc<TestMinerService> {
Arc::new(TestMinerService::default())
}
fn signer_tester() -> PersonalSignerTester {
fn signer_tester() -> SignerTester {
let signer = Arc::new(SignerService::new_test(None));
let accounts = accounts_provider();
let client = blockchain_client();
@ -57,7 +57,7 @@ fn signer_tester() -> PersonalSignerTester {
let io = IoHandler::new();
io.add_delegate(SignerClient::new(&accounts, &client, &miner, &signer).to_delegate());
PersonalSignerTester {
SignerTester {
signer: signer,
accounts: accounts,
io: io,
@ -83,7 +83,7 @@ fn should_return_list_of_items_to_confirm() {
tester.signer.add_request(ConfirmationPayload::Sign(1.into(), 5.into())).unwrap();
// when
let request = r#"{"jsonrpc":"2.0","method":"personal_requestsToConfirm","params":[],"id":1}"#;
let request = r#"{"jsonrpc":"2.0","method":"signer_requestsToConfirm","params":[],"id":1}"#;
let response = concat!(
r#"{"jsonrpc":"2.0","result":["#,
r#"{"id":"0x1","payload":{"transaction":{"data":"0x","from":"0x0000000000000000000000000000000000000001","gas":"0x989680","gasPrice":"0x2710","nonce":null,"to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","value":"0x1"}}},"#,
@ -112,7 +112,7 @@ fn should_reject_transaction_from_queue_without_dispatching() {
assert_eq!(tester.signer.requests().len(), 1);
// when
let request = r#"{"jsonrpc":"2.0","method":"personal_rejectRequest","params":["0x1"],"id":1}"#;
let request = r#"{"jsonrpc":"2.0","method":"signer_rejectRequest","params":["0x1"],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
// then
@ -137,7 +137,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
assert_eq!(tester.signer.requests().len(), 1);
// when
let request = r#"{"jsonrpc":"2.0","method":"personal_confirmRequest","params":["0x1",{},"xxx"],"id":1}"#;
let request = r#"{"jsonrpc":"2.0","method":"signer_confirmRequest","params":["0x1",{},"xxx"],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32021,"message":"Account password is invalid or account does not exist.","data":"SStore(InvalidAccount)"},"id":1}"#;
// then
@ -153,7 +153,7 @@ fn should_not_remove_sign_if_password_is_invalid() {
assert_eq!(tester.signer.requests().len(), 1);
// when
let request = r#"{"jsonrpc":"2.0","method":"personal_confirmRequest","params":["0x1",{},"xxx"],"id":1}"#;
let request = r#"{"jsonrpc":"2.0","method":"signer_confirmRequest","params":["0x1",{},"xxx"],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32021,"message":"Account password is invalid or account does not exist.","data":"SStore(InvalidAccount)"},"id":1}"#;
// then
@ -194,7 +194,7 @@ fn should_confirm_transaction_and_dispatch() {
// when
let request = r#"{
"jsonrpc":"2.0",
"method":"personal_confirmRequest",
"method":"signer_confirmRequest",
"params":["0x1", {"gasPrice":"0x1000"}, "test"],
"id":1
}"#;
@ -214,7 +214,7 @@ fn should_generate_new_token() {
// when
let request = r#"{
"jsonrpc":"2.0",
"method":"personal_generateAuthorizationToken",
"method":"signer_generateAuthorizationToken",
"params":[],
"id":1
}"#;

View File

@ -17,12 +17,12 @@
use std::str::FromStr;
use std::sync::Arc;
use jsonrpc_core::{IoHandler, to_value, Success};
use v1::impls::EthSigningQueueClient;
use v1::traits::{EthSigning, Ethcore};
use v1::impls::SigningQueueClient;
use v1::traits::{EthSigning, ParitySigning, Parity};
use v1::helpers::{SignerService, SigningQueue};
use v1::types::{H256 as RpcH256, H520 as RpcH520, Bytes};
use v1::tests::helpers::TestMinerService;
use v1::tests::mocked::ethcore;
use v1::tests::mocked::parity;
use util::{Address, FixedHash, Uint, U256, H256, H520};
use ethcore::account_provider::AccountProvider;
@ -31,7 +31,7 @@ use ethcore::transaction::{Transaction, Action};
use ethstore::ethkey::{Generator, Random};
use serde_json;
struct EthSigningTester {
struct SigningTester {
pub signer: Arc<SignerService>,
pub client: Arc<TestBlockChainClient>,
pub miner: Arc<TestMinerService>,
@ -39,16 +39,19 @@ struct EthSigningTester {
pub io: IoHandler,
}
impl Default for EthSigningTester {
impl Default for SigningTester {
fn default() -> Self {
let signer = Arc::new(SignerService::new_test(None));
let client = Arc::new(TestBlockChainClient::default());
let miner = Arc::new(TestMinerService::default());
let accounts = Arc::new(AccountProvider::transient_provider());
let io = IoHandler::new();
io.add_delegate(EthSigningQueueClient::new(&signer, &client, &miner, &accounts).to_delegate());
let rpc = SigningQueueClient::new(&signer, &client, &miner, &accounts);
io.add_delegate(EthSigning::to_delegate(rpc));
let rpc = SigningQueueClient::new(&signer, &client, &miner, &accounts);
io.add_delegate(ParitySigning::to_delegate(rpc));
EthSigningTester {
SigningTester {
signer: signer,
client: client,
miner: miner,
@ -58,8 +61,8 @@ impl Default for EthSigningTester {
}
}
fn eth_signing() -> EthSigningTester {
EthSigningTester::default()
fn eth_signing() -> SigningTester {
SigningTester::default()
}
#[test]
@ -101,7 +104,7 @@ fn should_post_sign_to_queue() {
// when
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_postSign",
"method": "parity_postSign",
"params": [
""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
"0x0000000000000000000000000000000000000000000000000000000000000005"
@ -122,7 +125,7 @@ fn should_check_status_of_request() {
let address = Address::random();
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_postSign",
"method": "parity_postSign",
"params": [
""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
"0x0000000000000000000000000000000000000000000000000000000000000005"
@ -134,7 +137,7 @@ fn should_check_status_of_request() {
// when
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_checkRequest",
"method": "parity_checkRequest",
"params": ["0x1"],
"id": 1
}"#;
@ -151,7 +154,7 @@ fn should_check_status_of_request_when_its_resolved() {
let address = Address::random();
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_postSign",
"method": "parity_postSign",
"params": [
""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
"0x0000000000000000000000000000000000000000000000000000000000000005"
@ -164,7 +167,7 @@ fn should_check_status_of_request_when_its_resolved() {
// when
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_checkRequest",
"method": "parity_checkRequest",
"params": ["0x1"],
"id": 1
}"#;
@ -272,15 +275,15 @@ fn should_dispatch_transaction_if_account_is_unlock() {
fn should_decrypt_message_if_account_is_unlocked() {
// given
let tester = eth_signing();
let ethcore = ethcore::Dependencies::new();
tester.io.add_delegate(ethcore.client(None).to_delegate());
let parity = parity::Dependencies::new();
tester.io.add_delegate(parity.client(None).to_delegate());
let (address, public) = tester.accounts.new_account_and_public("test").unwrap();
tester.accounts.unlock_account_permanently(address, "test".into()).unwrap();
// First encrypt message
let request = format!("{}0x{:?}{}",
r#"{"jsonrpc": "2.0", "method": "ethcore_encryptMessage", "params":[""#,
r#"{"jsonrpc": "2.0", "method": "parity_encryptMessage", "params":[""#,
public,
r#"", "0x01020304"], "id": 1}"#
);
@ -288,7 +291,7 @@ fn should_decrypt_message_if_account_is_unlocked() {
// then call decrypt
let request = format!("{}{:?}{}{:?}{}",
r#"{"jsonrpc": "2.0", "method": "ethcore_decryptMessage", "params":["0x"#,
r#"{"jsonrpc": "2.0", "method": "parity_decryptMessage", "params":["0x"#,
address,
r#"","#,
encrypted.result,
@ -311,7 +314,7 @@ fn should_add_decryption_to_the_queue() {
// when
let request = r#"{
"jsonrpc": "2.0",
"method": "ethcore_decryptMessage",
"method": "parity_decryptMessage",
"params": ["0x"#.to_owned() + &format!("{:?}", acc.address()) + r#"",
"0x012345"],
"id": 1

View File

@ -23,41 +23,18 @@ pub trait EthSigning: Sized + Send + Sync + 'static {
/// Signs the data with given address signature.
fn sign(&self, _: Params, _: Ready);
/// Posts sign request asynchronously.
/// Will return a confirmation ID for later use with check_transaction.
fn post_sign(&self, _: Params) -> Result<Value, Error>;
/// Sends transaction; will block for 20s to try to return the
/// transaction hash.
/// If it cannot yet be signed, it will return a transaction ID for
/// later use with check_transaction.
fn send_transaction(&self, _: Params, _: Ready);
/// Posts transaction asynchronously.
/// Will return a transaction ID for later use with check_transaction.
fn post_transaction(&self, _: Params) -> Result<Value, Error>;
/// Checks the progress of a previously posted request (transaction/sign).
/// Should be given a valid send_transaction ID.
/// Returns the transaction hash, the zero hash (not yet available),
/// or the signature,
/// or an error.
fn check_request(&self, _: Params) -> Result<Value, Error>;
/// Decrypt some ECIES-encrypted message.
/// First parameter is the address with which it is encrypted, second is the ciphertext.
fn decrypt_message(&self, _: Params, _: Ready);
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {
let mut delegate = IoDelegate::new(Arc::new(self));
delegate.add_async_method("eth_sign", EthSigning::sign);
delegate.add_async_method("eth_sendTransaction", EthSigning::send_transaction);
delegate.add_async_method("ethcore_decryptMessage", EthSigning::decrypt_message);
delegate.add_method("eth_postSign", EthSigning::post_sign);
delegate.add_method("eth_postTransaction", EthSigning::post_transaction);
delegate.add_method("eth_checkRequest", EthSigning::check_request);
delegate
}
}

View File

@ -20,9 +20,12 @@ pub mod web3;
pub mod eth;
pub mod eth_signing;
pub mod net;
pub mod parity;
pub mod parity_accounts;
pub mod parity_set;
pub mod parity_signing;
pub mod personal;
pub mod ethcore;
pub mod ethcore_set;
pub mod signer;
pub mod traces;
pub mod rpc;
@ -30,9 +33,12 @@ pub use self::web3::Web3;
pub use self::eth::{Eth, EthFilter};
pub use self::eth_signing::EthSigning;
pub use self::net::Net;
pub use self::personal::{Personal, PersonalAccounts, PersonalSigner};
pub use self::ethcore::Ethcore;
pub use self::ethcore_set::EthcoreSet;
pub use self::parity::Parity;
pub use self::parity_accounts::ParityAccounts;
pub use self::parity_set::ParitySet;
pub use self::parity_signing::ParitySigning;
pub use self::personal::Personal;
pub use self::signer::Signer;
pub use self::traces::Traces;
pub use self::rpc::Rpc;

Some files were not shown because too many files have changed in this diff Show More