Merge pull request #5304 from paritytech/mh-webserver
Public node with accounts and signing in Frontend
This commit is contained in:
commit
ab2c3468d5
@ -29,7 +29,7 @@ impl Brain {
|
|||||||
impl Generator for Brain {
|
impl Generator for Brain {
|
||||||
fn generate(self) -> Result<KeyPair, Error> {
|
fn generate(self) -> Result<KeyPair, Error> {
|
||||||
let seed = self.0;
|
let seed = self.0;
|
||||||
let mut secret = seed.bytes().collect::<Vec<u8>>().keccak256();
|
let mut secret = seed.into_bytes().keccak256();
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop {
|
loop {
|
||||||
|
@ -171,6 +171,7 @@
|
|||||||
"geopattern": "1.2.3",
|
"geopattern": "1.2.3",
|
||||||
"isomorphic-fetch": "2.2.1",
|
"isomorphic-fetch": "2.2.1",
|
||||||
"js-sha3": "0.5.5",
|
"js-sha3": "0.5.5",
|
||||||
|
"keythereum": "0.4.3",
|
||||||
"lodash": "4.17.2",
|
"lodash": "4.17.2",
|
||||||
"loglevel": "1.4.1",
|
"loglevel": "1.4.1",
|
||||||
"marked": "0.3.6",
|
"marked": "0.3.6",
|
||||||
@ -207,6 +208,7 @@
|
|||||||
"redux-thunk": "2.1.0",
|
"redux-thunk": "2.1.0",
|
||||||
"rlp": "2.0.0",
|
"rlp": "2.0.0",
|
||||||
"scryptsy": "2.0.0",
|
"scryptsy": "2.0.0",
|
||||||
|
"secp256k1": "3.2.5",
|
||||||
"solc": "ngotchac/solc-js",
|
"solc": "ngotchac/solc-js",
|
||||||
"store": "1.3.20",
|
"store": "1.3.20",
|
||||||
"sw-toolbox": "^3.6.0",
|
"sw-toolbox": "^3.6.0",
|
||||||
|
@ -23,6 +23,7 @@ import { Db, Eth, Parity, Net, Personal, Shh, Signer, Trace, Web3 } from './rpc'
|
|||||||
import Subscriptions from './subscriptions';
|
import Subscriptions from './subscriptions';
|
||||||
import util from './util';
|
import util from './util';
|
||||||
import { isFunction } from './util/types';
|
import { isFunction } from './util/types';
|
||||||
|
import { LocalAccountsMiddleware } from './local';
|
||||||
|
|
||||||
export default class Api extends EventEmitter {
|
export default class Api extends EventEmitter {
|
||||||
constructor (transport) {
|
constructor (transport) {
|
||||||
@ -45,6 +46,21 @@ export default class Api extends EventEmitter {
|
|||||||
this._web3 = new Web3(transport);
|
this._web3 = new Web3(transport);
|
||||||
|
|
||||||
this._subscriptions = new Subscriptions(this);
|
this._subscriptions = new Subscriptions(this);
|
||||||
|
|
||||||
|
// Doing a request here in test env would cause an error
|
||||||
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
|
const middleware = this.parity
|
||||||
|
.nodeKind()
|
||||||
|
.then((nodeKind) => {
|
||||||
|
if (nodeKind.availability === 'public') {
|
||||||
|
return new LocalAccountsMiddleware(transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
transport.addMiddleware(middleware);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get db () {
|
get db () {
|
||||||
|
95
js/src/api/local/accounts/account.js
Normal file
95
js/src/api/local/accounts/account.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { keythereum } from '../ethkey';
|
||||||
|
|
||||||
|
export default class Account {
|
||||||
|
constructor (persist, data) {
|
||||||
|
const {
|
||||||
|
keyObject,
|
||||||
|
meta = {},
|
||||||
|
name = ''
|
||||||
|
} = data;
|
||||||
|
|
||||||
|
this._persist = persist;
|
||||||
|
this._keyObject = keyObject;
|
||||||
|
this._name = name;
|
||||||
|
this._meta = meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidPassword (password) {
|
||||||
|
try {
|
||||||
|
keythereum.recover(Buffer.from(password), this._keyObject);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get address () {
|
||||||
|
return `0x${this._keyObject.address.toLowerCase()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name () {
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
set name (name) {
|
||||||
|
this._name = name;
|
||||||
|
|
||||||
|
this._persist();
|
||||||
|
}
|
||||||
|
|
||||||
|
get meta () {
|
||||||
|
return JSON.stringify(this._meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
set meta (meta) {
|
||||||
|
this._meta = JSON.parse(meta);
|
||||||
|
|
||||||
|
this._persist();
|
||||||
|
}
|
||||||
|
|
||||||
|
get uuid () {
|
||||||
|
return this._keyObject.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptPrivateKey (password) {
|
||||||
|
return keythereum.recover(Buffer.from(password), this._keyObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromPrivateKey (persist, key, password) {
|
||||||
|
const iv = keythereum.crypto.randomBytes(16);
|
||||||
|
const salt = keythereum.crypto.randomBytes(32);
|
||||||
|
|
||||||
|
// Keythereum will fail if `password` is an empty string
|
||||||
|
password = Buffer.from(password);
|
||||||
|
|
||||||
|
const keyObject = keythereum.dump(password, key, salt, iv);
|
||||||
|
|
||||||
|
const account = new Account(persist, { keyObject });
|
||||||
|
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON () {
|
||||||
|
return {
|
||||||
|
keyObject: this._keyObject,
|
||||||
|
name: this._name,
|
||||||
|
meta: this._meta
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
120
js/src/api/local/accounts/accounts.js
Normal file
120
js/src/api/local/accounts/accounts.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import Account from './account';
|
||||||
|
import localStore from 'store';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
|
|
||||||
|
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||||
|
const LS_STORE_KEY = '_parity::localAccounts';
|
||||||
|
|
||||||
|
export default class Accounts {
|
||||||
|
constructor (data = localStore.get(LS_STORE_KEY) || {}) {
|
||||||
|
const {
|
||||||
|
last = NULL_ADDRESS,
|
||||||
|
store = []
|
||||||
|
} = data;
|
||||||
|
|
||||||
|
this.persist = debounce(() => {
|
||||||
|
localStore.set(LS_STORE_KEY, this);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
this._last = last;
|
||||||
|
this._store = store.map((data) => new Account(this.persist, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
create (secret, password) {
|
||||||
|
const privateKey = Buffer.from(secret.slice(2), 'hex');
|
||||||
|
const account = Account.fromPrivateKey(this.persist, privateKey, password);
|
||||||
|
|
||||||
|
this._store.push(account);
|
||||||
|
this.lastAddress = account.address;
|
||||||
|
|
||||||
|
this.persist();
|
||||||
|
|
||||||
|
return account.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
set lastAddress (value) {
|
||||||
|
this._last = value.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
get lastAddress () {
|
||||||
|
return this._last;
|
||||||
|
}
|
||||||
|
|
||||||
|
get (address) {
|
||||||
|
address = address.toLowerCase();
|
||||||
|
|
||||||
|
this.lastAddress = address;
|
||||||
|
|
||||||
|
const account = this._store.find((account) => account.address === address);
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
throw new Error(`Account not found: ${address}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove (address, password) {
|
||||||
|
address = address.toLowerCase();
|
||||||
|
|
||||||
|
const index = this._store.findIndex((account) => account.address === address);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = this._store[index];
|
||||||
|
|
||||||
|
if (!account.isValidPassword(password)) {
|
||||||
|
console.log('invalid password');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address === this.lastAddress) {
|
||||||
|
this.lastAddress = NULL_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._store.splice(index, 1);
|
||||||
|
|
||||||
|
this.persist();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapArray (mapper) {
|
||||||
|
return this._store.map(mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapObject (mapper) {
|
||||||
|
const result = {};
|
||||||
|
|
||||||
|
this._store.forEach((account) => {
|
||||||
|
result[account.address] = mapper(account);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON () {
|
||||||
|
return {
|
||||||
|
last: this._last,
|
||||||
|
store: this._store
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
21
js/src/api/local/accounts/index.js
Normal file
21
js/src/api/local/accounts/index.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import Accounts from './accounts';
|
||||||
|
|
||||||
|
const accounts = new Accounts();
|
||||||
|
|
||||||
|
export default accounts;
|
7778
js/src/api/local/ethkey/dictionary.js
Normal file
7778
js/src/api/local/ethkey/dictionary.js
Normal file
File diff suppressed because it is too large
Load Diff
87
js/src/api/local/ethkey/index.js
Normal file
87
js/src/api/local/ethkey/index.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import dictionary from './dictionary';
|
||||||
|
|
||||||
|
// Allow a web worker in the browser, with a fallback for Node.js
|
||||||
|
const hasWebWorkers = typeof Worker !== 'undefined';
|
||||||
|
const KeyWorker = hasWebWorkers ? require('worker-loader!./worker')
|
||||||
|
: require('./worker').KeyWorker;
|
||||||
|
|
||||||
|
// Local accounts should never be used outside of the browser
|
||||||
|
export let keythereum = null;
|
||||||
|
|
||||||
|
if (hasWebWorkers) {
|
||||||
|
require('keythereum/dist/keythereum');
|
||||||
|
|
||||||
|
keythereum = window.keythereum;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function phraseToAddress (phrase) {
|
||||||
|
return phraseToWallet(phrase).then((wallet) => wallet.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function phraseToWallet (phrase) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const worker = new KeyWorker();
|
||||||
|
|
||||||
|
worker.postMessage(phrase);
|
||||||
|
worker.onmessage = ({ data }) => {
|
||||||
|
resolve(data);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function randomBytes (length) {
|
||||||
|
if (keythereum) {
|
||||||
|
return keythereum.crypto.randomBytes(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buf = Buffer.alloc(length);
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
buf[i] = Math.random() * 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function randomNumber (max) {
|
||||||
|
// Use 24 bits to avoid the integer becoming signed via bitshifts
|
||||||
|
const rand = randomBytes(3);
|
||||||
|
|
||||||
|
const integer = (rand[0] << 16) | (rand[1] << 8) | rand[2];
|
||||||
|
|
||||||
|
// floor to integer value via bitor 0
|
||||||
|
return ((integer / 0xFFFFFF) * max) | 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function randomWord () {
|
||||||
|
// TODO mh: use better entropy
|
||||||
|
const index = randomNumber(dictionary.length);
|
||||||
|
|
||||||
|
return dictionary[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function randomPhrase (length) {
|
||||||
|
const words = [];
|
||||||
|
|
||||||
|
while (length--) {
|
||||||
|
words.push(randomWord());
|
||||||
|
}
|
||||||
|
|
||||||
|
return words.join(' ');
|
||||||
|
}
|
95
js/src/api/local/ethkey/index.spec.js
Normal file
95
js/src/api/local/ethkey/index.spec.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import dictionary from './dictionary';
|
||||||
|
import {
|
||||||
|
phraseToAddress,
|
||||||
|
phraseToWallet,
|
||||||
|
randomNumber,
|
||||||
|
randomWord,
|
||||||
|
randomPhrase
|
||||||
|
} from './';
|
||||||
|
|
||||||
|
describe('api/local/ethkey', () => {
|
||||||
|
describe('randomNumber', () => {
|
||||||
|
it('generates numbers in range', () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
const number = randomNumber(7777);
|
||||||
|
|
||||||
|
expect(number).to.be.at.least(0);
|
||||||
|
expect(number).to.be.below(7777);
|
||||||
|
expect(number % 1).to.be.equal(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('randomWord', () => {
|
||||||
|
it('generates a random word from the dictionary', () => {
|
||||||
|
const word = randomWord();
|
||||||
|
|
||||||
|
expect(dictionary.includes(word)).to.be.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('randomPhrase', () => {
|
||||||
|
it('generates a random phrase from the dictionary', () => {
|
||||||
|
const phrase = randomPhrase(7).split(' ');
|
||||||
|
|
||||||
|
expect(phrase.length).to.be.equal(7);
|
||||||
|
|
||||||
|
phrase.forEach((word) => {
|
||||||
|
expect(dictionary.includes(word)).to.be.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skip('phraseToAddress', function () {
|
||||||
|
this.timeout(10000);
|
||||||
|
|
||||||
|
it('generates a valid address', () => {
|
||||||
|
const phrase = randomPhrase(12);
|
||||||
|
|
||||||
|
return phraseToAddress(phrase).then((address) => {
|
||||||
|
expect(address.length).to.be.equal(42);
|
||||||
|
expect(address.slice(0, 4)).to.be.equal('0x00');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates valid address for empty phrase', () => {
|
||||||
|
return phraseToAddress('').then((address) => {
|
||||||
|
expect(address).to.be.equal('0x00a329c0648769a73afac7f9381e08fb43dbea72');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skip('phraseToWallet', function () {
|
||||||
|
this.timeout(10000);
|
||||||
|
|
||||||
|
it('generates a valid wallet object', () => {
|
||||||
|
const phrase = randomPhrase(12);
|
||||||
|
|
||||||
|
return phraseToWallet(phrase).then((wallet) => {
|
||||||
|
expect(wallet.address.length).to.be.equal(42);
|
||||||
|
expect(wallet.secret.length).to.be.equal(66);
|
||||||
|
expect(wallet.public.length).to.be.equal(130);
|
||||||
|
|
||||||
|
expect(wallet.address.slice(0, 4)).to.be.equal('0x00');
|
||||||
|
expect(wallet.secret.slice(0, 2)).to.be.equal('0x');
|
||||||
|
expect(wallet.public.slice(0, 2)).to.be.equal('0x');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
89
js/src/api/local/ethkey/worker.js
Normal file
89
js/src/api/local/ethkey/worker.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { keccak_256 as keccak256 } from 'js-sha3';
|
||||||
|
import secp256k1 from 'secp256k1/js';
|
||||||
|
|
||||||
|
// Stay compatible between environments
|
||||||
|
if (typeof self !== 'object') {
|
||||||
|
const scope = typeof global === 'undefined' ? window : global;
|
||||||
|
|
||||||
|
scope.self = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bytesToHex (bytes) {
|
||||||
|
return '0x' + Array.from(bytes).map(n => ('0' + n.toString(16)).slice(-2)).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logic ported from /ethkey/src/brain.rs
|
||||||
|
function phraseToWallet (phrase) {
|
||||||
|
let secret = keccak256.array(phrase);
|
||||||
|
|
||||||
|
for (let i = 0; i < 16384; i++) {
|
||||||
|
secret = keccak256.array(secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
secret = keccak256.array(secret);
|
||||||
|
|
||||||
|
const secretBuf = Buffer.from(secret);
|
||||||
|
|
||||||
|
if (secp256k1.privateKeyVerify(secretBuf)) {
|
||||||
|
// No compression, slice out last 64 bytes
|
||||||
|
const publicBuf = secp256k1.publicKeyCreate(secretBuf, false).slice(-64);
|
||||||
|
const address = keccak256.array(publicBuf).slice(12);
|
||||||
|
|
||||||
|
if (address[0] !== 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wallet = {
|
||||||
|
secret: bytesToHex(secretBuf),
|
||||||
|
public: bytesToHex(publicBuf),
|
||||||
|
address: bytesToHex(address)
|
||||||
|
};
|
||||||
|
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.onmessage = function ({ data }) {
|
||||||
|
const wallet = phraseToWallet(data);
|
||||||
|
|
||||||
|
postMessage(wallet);
|
||||||
|
close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Emulate a web worker in Node.js
|
||||||
|
class KeyWorker {
|
||||||
|
postMessage (data) {
|
||||||
|
// Force async
|
||||||
|
setTimeout(() => {
|
||||||
|
const wallet = phraseToWallet(data);
|
||||||
|
|
||||||
|
this.onmessage({ data: wallet });
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
onmessage (event) {
|
||||||
|
// no-op to be overriden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exports != null) {
|
||||||
|
exports.KeyWorker = KeyWorker;
|
||||||
|
}
|
17
js/src/api/local/index.js
Normal file
17
js/src/api/local/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export LocalAccountsMiddleware from './middleware';
|
173
js/src/api/local/middleware.js
Normal file
173
js/src/api/local/middleware.js
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import EthereumTx from 'ethereumjs-tx';
|
||||||
|
import accounts from './accounts';
|
||||||
|
import transactions from './transactions';
|
||||||
|
import { Middleware } from '../transport';
|
||||||
|
import { inNumber16 } from '../format/input';
|
||||||
|
import { phraseToWallet, phraseToAddress, randomPhrase } from './ethkey';
|
||||||
|
|
||||||
|
export default class LocalAccountsMiddleware extends Middleware {
|
||||||
|
// Maps transaction requests to transaction hashes.
|
||||||
|
// This allows the locally-signed transactions to emulate the signer.
|
||||||
|
transactionHashes = {};
|
||||||
|
transactions = {};
|
||||||
|
|
||||||
|
// Current transaction id. This doesn't need to be stored, as it's
|
||||||
|
// only relevant for the current the session.
|
||||||
|
transactionId = 1;
|
||||||
|
|
||||||
|
constructor (transport) {
|
||||||
|
super(transport);
|
||||||
|
|
||||||
|
const register = this.register.bind(this);
|
||||||
|
|
||||||
|
register('eth_accounts', () => {
|
||||||
|
return accounts.mapArray((account) => account.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
register('eth_coinbase', () => {
|
||||||
|
return accounts.lastAddress;
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_accountsInfo', () => {
|
||||||
|
return accounts.mapObject(({ name }) => {
|
||||||
|
return { name };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_allAccountsInfo', () => {
|
||||||
|
return accounts.mapObject(({ name, meta, uuid }) => {
|
||||||
|
return { name, meta, uuid };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_checkRequest', ([id]) => {
|
||||||
|
return transactions.hash(id) || Promise.resolve(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_defaultAccount', () => {
|
||||||
|
return accounts.lastAddress;
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_generateSecretPhrase', () => {
|
||||||
|
return randomPhrase(12);
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_getNewDappsAddresses', () => {
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_hardwareAccountsInfo', () => {
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_newAccountFromPhrase', ([phrase, password]) => {
|
||||||
|
return phraseToWallet(phrase)
|
||||||
|
.then((wallet) => {
|
||||||
|
return accounts.create(wallet.secret, password);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_setAccountMeta', ([address, meta]) => {
|
||||||
|
accounts.get(address).meta = meta;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_setAccountName', ([address, name]) => {
|
||||||
|
accounts.get(address).name = name;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_postTransaction', ([tx]) => {
|
||||||
|
if (!tx.from) {
|
||||||
|
tx.from = accounts.lastAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.nonce = null;
|
||||||
|
tx.condition = null;
|
||||||
|
|
||||||
|
return transactions.add(tx);
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_phraseToAddress', ([phrase]) => {
|
||||||
|
return phraseToAddress(phrase);
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_useLocalAccounts', () => {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_listGethAccounts', () => {
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_listRecentDapps', () => {
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
|
register('parity_killAccount', ([address, password]) => {
|
||||||
|
return accounts.remove(address, password);
|
||||||
|
});
|
||||||
|
|
||||||
|
register('signer_confirmRequest', ([id, modify, password]) => {
|
||||||
|
const {
|
||||||
|
gasPrice,
|
||||||
|
gas: gasLimit,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
value,
|
||||||
|
data
|
||||||
|
} = Object.assign(transactions.get(id), modify);
|
||||||
|
|
||||||
|
return this
|
||||||
|
.rpcRequest('parity_nextNonce', [from])
|
||||||
|
.then((nonce) => {
|
||||||
|
const tx = new EthereumTx({
|
||||||
|
nonce,
|
||||||
|
to,
|
||||||
|
data,
|
||||||
|
gasLimit: inNumber16(gasLimit),
|
||||||
|
gasPrice: inNumber16(gasPrice),
|
||||||
|
value: inNumber16(value)
|
||||||
|
});
|
||||||
|
const account = accounts.get(from);
|
||||||
|
|
||||||
|
tx.sign(account.decryptPrivateKey(password));
|
||||||
|
|
||||||
|
const serializedTx = `0x${tx.serialize().toString('hex')}`;
|
||||||
|
|
||||||
|
return this.rpcRequest('eth_sendRawTransaction', [serializedTx]);
|
||||||
|
})
|
||||||
|
.then((hash) => {
|
||||||
|
transactions.confirm(id, hash);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
register('signer_rejectRequest', ([id]) => {
|
||||||
|
return transactions.reject(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
register('signer_requestsToConfirm', () => {
|
||||||
|
return transactions.requestsToConfirm();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
123
js/src/api/local/transactions.js
Normal file
123
js/src/api/local/transactions.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { toHex } from '../util/format';
|
||||||
|
import { TransportError } from '../transport';
|
||||||
|
|
||||||
|
const AWAITING = Symbol('awaiting');
|
||||||
|
const CONFIRMED = Symbol('confirmed');
|
||||||
|
const REJECTED = Symbol('rejected');
|
||||||
|
|
||||||
|
class Transactions {
|
||||||
|
constructor () {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// should only really be needed in the constructor and tests
|
||||||
|
reset () {
|
||||||
|
this._id = 1;
|
||||||
|
this._states = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
nextId () {
|
||||||
|
return toHex(this._id++);
|
||||||
|
}
|
||||||
|
|
||||||
|
add (tx) {
|
||||||
|
const id = this.nextId();
|
||||||
|
|
||||||
|
this._states[id] = {
|
||||||
|
status: AWAITING,
|
||||||
|
transaction: tx
|
||||||
|
};
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get (id) {
|
||||||
|
const state = this._states[id];
|
||||||
|
|
||||||
|
if (!state || state.status !== AWAITING) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash (id) {
|
||||||
|
const state = this._states[id];
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state.status) {
|
||||||
|
case REJECTED:
|
||||||
|
throw TransportError.requestRejected();
|
||||||
|
case CONFIRMED:
|
||||||
|
return state.hash;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm (id, hash) {
|
||||||
|
const state = this._states[id];
|
||||||
|
|
||||||
|
if (!state || state.status !== AWAITING) {
|
||||||
|
throw new Error('Trying to confirm an invalid transaction');
|
||||||
|
}
|
||||||
|
|
||||||
|
state.hash = hash;
|
||||||
|
state.status = CONFIRMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
reject (id) {
|
||||||
|
const state = this._states[id];
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.status = REJECTED;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestsToConfirm () {
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
Object.keys(this._states).forEach((id) => {
|
||||||
|
const state = this._states[id];
|
||||||
|
|
||||||
|
if (state.status === AWAITING) {
|
||||||
|
result.push({
|
||||||
|
id,
|
||||||
|
origin: {
|
||||||
|
signer: '0x0'
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
sendTransaction: state.transaction
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Transactions();
|
68
js/src/api/local/transactions.spec.js
Normal file
68
js/src/api/local/transactions.spec.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import transactions from './transactions';
|
||||||
|
import { TransportError } from '../transport/error';
|
||||||
|
|
||||||
|
const DUMMY_TX = 'dummy';
|
||||||
|
|
||||||
|
describe('api/local/transactions', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
transactions.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can store transactions', () => {
|
||||||
|
const id1 = transactions.add(DUMMY_TX);
|
||||||
|
const id2 = transactions.add(DUMMY_TX);
|
||||||
|
const requests = transactions.requestsToConfirm();
|
||||||
|
|
||||||
|
expect(id1).to.be.equal('0x1');
|
||||||
|
expect(id2).to.be.equal('0x2');
|
||||||
|
expect(requests.length).to.be.equal(2);
|
||||||
|
expect(requests[0].id).to.be.equal(id1);
|
||||||
|
expect(requests[1].id).to.be.equal(id2);
|
||||||
|
expect(requests[0].payload.sendTransaction).to.be.equal(DUMMY_TX);
|
||||||
|
expect(requests[1].payload.sendTransaction).to.be.equal(DUMMY_TX);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can confirm transactions', () => {
|
||||||
|
const id1 = transactions.add(DUMMY_TX);
|
||||||
|
const id2 = transactions.add(DUMMY_TX);
|
||||||
|
|
||||||
|
const hash1 = '0x1111111111111111111111111111111111111111';
|
||||||
|
const hash2 = '0x2222222222222222222222222222222222222222';
|
||||||
|
|
||||||
|
transactions.confirm(id1, hash1);
|
||||||
|
transactions.confirm(id2, hash2);
|
||||||
|
|
||||||
|
const requests = transactions.requestsToConfirm();
|
||||||
|
|
||||||
|
expect(requests.length).to.be.equal(0);
|
||||||
|
expect(transactions.hash(id1)).to.be.equal(hash1);
|
||||||
|
expect(transactions.hash(id2)).to.be.equal(hash2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can reject transactions', () => {
|
||||||
|
const id = transactions.add(DUMMY_TX);
|
||||||
|
|
||||||
|
transactions.reject(id);
|
||||||
|
|
||||||
|
const requests = transactions.requestsToConfirm();
|
||||||
|
|
||||||
|
expect(requests.length).to.be.equal(0);
|
||||||
|
expect(() => transactions.hash(id)).to.throw(TransportError);
|
||||||
|
});
|
||||||
|
});
|
@ -42,6 +42,10 @@ export const ERROR_CODES = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default class TransportError extends ExtendableError {
|
export default class TransportError extends ExtendableError {
|
||||||
|
static requestRejected (method = null) {
|
||||||
|
return new TransportError(method, ERROR_CODES.REQUEST_REJECTED, 'Request has been rejected.');
|
||||||
|
}
|
||||||
|
|
||||||
constructor (method, code, message) {
|
constructor (method, code, message) {
|
||||||
const m = `${method}: ${code}: ${message}`;
|
const m = `${method}: ${code}: ${message}`;
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export default class Http extends JsonRpcBase {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
execute (method, ...params) {
|
_execute (method, params) {
|
||||||
const request = this._encodeOptions(method, params);
|
const request = this._encodeOptions(method, params);
|
||||||
|
|
||||||
return fetch(this._url, request)
|
return fetch(this._url, request)
|
||||||
|
@ -16,4 +16,5 @@
|
|||||||
|
|
||||||
export Http from './http';
|
export Http from './http';
|
||||||
export Ws from './ws';
|
export Ws from './ws';
|
||||||
export TransportError from './error.js';
|
export TransportError from './error';
|
||||||
|
export Middleware from './middleware';
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
|
import { Logging } from '../subscriptions';
|
||||||
|
|
||||||
export default class JsonRpcBase extends EventEmitter {
|
export default class JsonRpcBase extends EventEmitter {
|
||||||
constructor () {
|
constructor () {
|
||||||
@ -23,6 +24,7 @@ export default class JsonRpcBase extends EventEmitter {
|
|||||||
this._id = 1;
|
this._id = 1;
|
||||||
this._debug = false;
|
this._debug = false;
|
||||||
this._connected = false;
|
this._connected = false;
|
||||||
|
this._middlewareList = Promise.resolve([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
encode (method, params) {
|
encode (method, params) {
|
||||||
@ -36,6 +38,65 @@ export default class JsonRpcBase extends EventEmitter {
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addMiddleware (middleware) {
|
||||||
|
this._middlewareList = Promise
|
||||||
|
.all([
|
||||||
|
middleware,
|
||||||
|
this._middlewareList
|
||||||
|
])
|
||||||
|
.then(([middleware, middlewareList]) => {
|
||||||
|
// Do nothing if `handlerPromise` resolves to a null-y value.
|
||||||
|
if (middleware == null) {
|
||||||
|
return middlewareList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't mutate the original array
|
||||||
|
return middlewareList.concat([middleware]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_wrapSuccessResult (result) {
|
||||||
|
return {
|
||||||
|
id: this._id,
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
result
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_wrapErrorResult (error) {
|
||||||
|
return {
|
||||||
|
id: this._id,
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: {
|
||||||
|
code: error.code,
|
||||||
|
message: error.text
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
execute (method, ...params) {
|
||||||
|
return this._middlewareList.then((middlewareList) => {
|
||||||
|
for (const middleware of middlewareList) {
|
||||||
|
const res = middleware.handle(method, params);
|
||||||
|
|
||||||
|
if (res != null) {
|
||||||
|
const result = this._wrapSuccessResult(res);
|
||||||
|
const json = this.encode(method, params);
|
||||||
|
|
||||||
|
Logging.send(method, params, { json, result });
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._execute(method, params);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_execute () {
|
||||||
|
throw new Error('Missing implementation of JsonRpcBase#_execute');
|
||||||
|
}
|
||||||
|
|
||||||
_setConnected () {
|
_setConnected () {
|
||||||
if (!this._connected) {
|
if (!this._connected) {
|
||||||
this._connected = true;
|
this._connected = true;
|
||||||
|
42
js/src/api/transport/middleware.js
Normal file
42
js/src/api/transport/middleware.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default class Middleware {
|
||||||
|
constructor (transport) {
|
||||||
|
this._transport = transport;
|
||||||
|
this._handlers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
register (method, handler) {
|
||||||
|
this._handlers[method] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle (method, params) {
|
||||||
|
const handler = this._handlers[method];
|
||||||
|
|
||||||
|
if (handler != null) {
|
||||||
|
const response = handler(params);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcRequest (method, params) {
|
||||||
|
return this._transport._execute(method, params);
|
||||||
|
}
|
||||||
|
}
|
58
js/src/api/transport/middleware.spec.js
Normal file
58
js/src/api/transport/middleware.spec.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import Middleware from './middleware';
|
||||||
|
import JsonRpcBase from './jsonRpcBase';
|
||||||
|
|
||||||
|
const MOCKED = 'mocked!';
|
||||||
|
|
||||||
|
class MockTransport extends JsonRpcBase {
|
||||||
|
_execute () {
|
||||||
|
return Promise.resolve(MOCKED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('api/transport/Middleware', () => {
|
||||||
|
let middleware;
|
||||||
|
let transport;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
transport = new MockTransport();
|
||||||
|
middleware = new Middleware(transport);
|
||||||
|
|
||||||
|
middleware.register('mock_rpc', ([num]) => num);
|
||||||
|
middleware.register('mock_null', () => null);
|
||||||
|
transport.addMiddleware(middleware);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Routes requests to middleware', () => {
|
||||||
|
return transport.execute('mock_rpc', 100).then((num) => {
|
||||||
|
expect(num).to.be.equal(100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Passes non-mocked requests through', () => {
|
||||||
|
return transport.execute('not_moced', 200).then((result) => {
|
||||||
|
expect(result).to.be.equal(MOCKED);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Passes mocked requests through, if middleware returns null', () => {
|
||||||
|
return transport.execute('mock_null', 300).then((result) => {
|
||||||
|
expect(result).to.be.equal(MOCKED);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -244,7 +244,7 @@ export default class Ws extends JsonRpcBase {
|
|||||||
message.timestamp = Date.now();
|
message.timestamp = Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
execute (method, ...params) {
|
_execute (method, params) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const id = this.id;
|
const id = this.id;
|
||||||
const json = this.encode(method, params);
|
const json = this.encode(method, params);
|
||||||
|
@ -56,6 +56,11 @@ module.exports = {
|
|||||||
'babel-loader?cacheDirectory=true'
|
'babel-loader?cacheDirectory=true'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
include: /node_modules\/ethereumjs-tx/,
|
||||||
|
use: 'babel-loader'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.json$/,
|
test: /\.json$/,
|
||||||
use: [ 'json-loader' ]
|
use: [ 'json-loader' ]
|
||||||
|
@ -4,6 +4,7 @@ mode_timeout = 300
|
|||||||
mode_alarm = 3600
|
mode_alarm = 3600
|
||||||
auto_update = "none"
|
auto_update = "none"
|
||||||
release_track = "current"
|
release_track = "current"
|
||||||
|
public_node = false
|
||||||
no_download = false
|
no_download = false
|
||||||
no_consensus = false
|
no_consensus = false
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ usage! {
|
|||||||
flag_mode_alarm: u64 = 3600u64, or |c: &Config| otry!(c.parity).mode_alarm.clone(),
|
flag_mode_alarm: u64 = 3600u64, or |c: &Config| otry!(c.parity).mode_alarm.clone(),
|
||||||
flag_auto_update: String = "critical", or |c: &Config| otry!(c.parity).auto_update.clone(),
|
flag_auto_update: String = "critical", or |c: &Config| otry!(c.parity).auto_update.clone(),
|
||||||
flag_release_track: String = "current", or |c: &Config| otry!(c.parity).release_track.clone(),
|
flag_release_track: String = "current", or |c: &Config| otry!(c.parity).release_track.clone(),
|
||||||
|
flag_public_node: bool = false, or |c: &Config| otry!(c.parity).public_node.clone(),
|
||||||
flag_no_download: bool = false, or |c: &Config| otry!(c.parity).no_download.clone(),
|
flag_no_download: bool = false, or |c: &Config| otry!(c.parity).no_download.clone(),
|
||||||
flag_no_consensus: bool = false, or |c: &Config| otry!(c.parity).no_consensus.clone(),
|
flag_no_consensus: bool = false, or |c: &Config| otry!(c.parity).no_consensus.clone(),
|
||||||
flag_chain: String = "foundation", or |c: &Config| otry!(c.parity).chain.clone(),
|
flag_chain: String = "foundation", or |c: &Config| otry!(c.parity).chain.clone(),
|
||||||
@ -365,6 +366,7 @@ struct Operating {
|
|||||||
mode_alarm: Option<u64>,
|
mode_alarm: Option<u64>,
|
||||||
auto_update: Option<String>,
|
auto_update: Option<String>,
|
||||||
release_track: Option<String>,
|
release_track: Option<String>,
|
||||||
|
public_node: Option<bool>,
|
||||||
no_download: Option<bool>,
|
no_download: Option<bool>,
|
||||||
no_consensus: Option<bool>,
|
no_consensus: Option<bool>,
|
||||||
chain: Option<String>,
|
chain: Option<String>,
|
||||||
@ -623,6 +625,7 @@ mod tests {
|
|||||||
flag_mode_alarm: 3600u64,
|
flag_mode_alarm: 3600u64,
|
||||||
flag_auto_update: "none".into(),
|
flag_auto_update: "none".into(),
|
||||||
flag_release_track: "current".into(),
|
flag_release_track: "current".into(),
|
||||||
|
flag_public_node: false,
|
||||||
flag_no_download: false,
|
flag_no_download: false,
|
||||||
flag_no_consensus: false,
|
flag_no_consensus: false,
|
||||||
flag_chain: "xyz".into(),
|
flag_chain: "xyz".into(),
|
||||||
@ -825,6 +828,7 @@ mod tests {
|
|||||||
mode_alarm: Some(10u64),
|
mode_alarm: Some(10u64),
|
||||||
auto_update: None,
|
auto_update: None,
|
||||||
release_track: None,
|
release_track: None,
|
||||||
|
public_node: None,
|
||||||
no_download: None,
|
no_download: None,
|
||||||
no_consensus: None,
|
no_consensus: None,
|
||||||
chain: Some("./chain.json".into()),
|
chain: Some("./chain.json".into()),
|
||||||
|
@ -48,6 +48,9 @@ Operating Options:
|
|||||||
testing - Testing releases (do not use).
|
testing - Testing releases (do not use).
|
||||||
current - Whatever track this executable was
|
current - Whatever track this executable was
|
||||||
released on (default: {flag_release_track}).
|
released on (default: {flag_release_track}).
|
||||||
|
--public-node Start Parity as a public web server. Account storage
|
||||||
|
and transaction signing will be delegated to the UI.
|
||||||
|
(default: {flag_public_node}).
|
||||||
--no-download Normally new releases will be downloaded ready for
|
--no-download Normally new releases will be downloaded ready for
|
||||||
updating. This disables it. Not recommended.
|
updating. This disables it. Not recommended.
|
||||||
(default: {flag_no_download}).
|
(default: {flag_no_download}).
|
||||||
|
@ -128,6 +128,7 @@ impl Configuration {
|
|||||||
Some(true) if pruning == Pruning::Specific(Algorithm::Archive) => writeln!(&mut stderr(), "Warning: Warp Sync is disabled because pruning mode is set to archive").expect("Error writing to stderr"),
|
Some(true) if pruning == Pruning::Specific(Algorithm::Archive) => writeln!(&mut stderr(), "Warning: Warp Sync is disabled because pruning mode is set to archive").expect("Error writing to stderr"),
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
|
let public_node = self.args.flag_public_node;
|
||||||
let warp_sync = !self.args.flag_no_warp && fat_db != Switch::On && tracing != Switch::On && pruning != Pruning::Specific(Algorithm::Archive);
|
let warp_sync = !self.args.flag_no_warp && fat_db != Switch::On && tracing != Switch::On && pruning != Pruning::Specific(Algorithm::Archive);
|
||||||
let geth_compatibility = self.args.flag_geth;
|
let geth_compatibility = self.args.flag_geth;
|
||||||
let ui_address = self.ui_port().map(|port| (self.ui_interface(), port));
|
let ui_address = self.ui_port().map(|port| (self.ui_interface(), port));
|
||||||
@ -360,6 +361,7 @@ impl Configuration {
|
|||||||
wal: wal,
|
wal: wal,
|
||||||
vm_type: vm_type,
|
vm_type: vm_type,
|
||||||
warp_sync: warp_sync,
|
warp_sync: warp_sync,
|
||||||
|
public_node: public_node,
|
||||||
geth_compatibility: geth_compatibility,
|
geth_compatibility: geth_compatibility,
|
||||||
ui_address: ui_address,
|
ui_address: ui_address,
|
||||||
net_settings: self.network_settings(),
|
net_settings: self.network_settings(),
|
||||||
@ -709,14 +711,26 @@ impl Configuration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rpc_apis(&self) -> String {
|
fn rpc_apis(&self) -> String {
|
||||||
let mut apis = self.args.flag_rpcapi.clone().unwrap_or(self.args.flag_jsonrpc_apis.clone());
|
let mut apis: Vec<&str> = self.args.flag_rpcapi
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&self.args.flag_jsonrpc_apis)
|
||||||
|
.split(",")
|
||||||
|
.collect();
|
||||||
|
|
||||||
if self.args.flag_geth {
|
if self.args.flag_geth {
|
||||||
if !apis.is_empty() {
|
apis.push("personal");
|
||||||
apis.push_str(",");
|
|
||||||
}
|
|
||||||
apis.push_str("personal");
|
|
||||||
}
|
}
|
||||||
apis
|
|
||||||
|
if self.args.flag_public_node {
|
||||||
|
apis.retain(|api| {
|
||||||
|
match *api {
|
||||||
|
"eth" | "net" | "parity" | "rpc" | "web3" => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
apis.join(",")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cors(cors: Option<&String>) -> Option<Vec<String>> {
|
fn cors(cors: Option<&String>) -> Option<Vec<String>> {
|
||||||
@ -1167,6 +1181,7 @@ mod tests {
|
|||||||
ipc_conf: Default::default(),
|
ipc_conf: Default::default(),
|
||||||
net_conf: default_network_config(),
|
net_conf: default_network_config(),
|
||||||
network_id: None,
|
network_id: None,
|
||||||
|
public_node: false,
|
||||||
warp_sync: true,
|
warp_sync: true,
|
||||||
acc_conf: Default::default(),
|
acc_conf: Default::default(),
|
||||||
gas_pricer: Default::default(),
|
gas_pricer: Default::default(),
|
||||||
|
@ -118,7 +118,7 @@ pub struct Dependencies {
|
|||||||
pub snapshot: Arc<SnapshotService>,
|
pub snapshot: Arc<SnapshotService>,
|
||||||
pub sync: Arc<SyncProvider>,
|
pub sync: Arc<SyncProvider>,
|
||||||
pub net: Arc<ManageNetwork>,
|
pub net: Arc<ManageNetwork>,
|
||||||
pub secret_store: Arc<AccountProvider>,
|
pub secret_store: Option<Arc<AccountProvider>>,
|
||||||
pub miner: Arc<Miner>,
|
pub miner: Arc<Miner>,
|
||||||
pub external_miner: Arc<ExternalMiner>,
|
pub external_miner: Arc<ExternalMiner>,
|
||||||
pub logger: Arc<RotatingLogger>,
|
pub logger: Arc<RotatingLogger>,
|
||||||
|
@ -81,6 +81,7 @@ pub struct RunCmd {
|
|||||||
pub net_conf: NetworkConfiguration,
|
pub net_conf: NetworkConfiguration,
|
||||||
pub network_id: Option<u64>,
|
pub network_id: Option<u64>,
|
||||||
pub warp_sync: bool,
|
pub warp_sync: bool,
|
||||||
|
pub public_node: bool,
|
||||||
pub acc_conf: AccountsConfig,
|
pub acc_conf: AccountsConfig,
|
||||||
pub gas_pricer: GasPricerConfig,
|
pub gas_pricer: GasPricerConfig,
|
||||||
pub miner_extras: MinerExtras,
|
pub miner_extras: MinerExtras,
|
||||||
@ -407,6 +408,10 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
|||||||
// set up dependencies for rpc servers
|
// set up dependencies for rpc servers
|
||||||
let rpc_stats = Arc::new(informant::RpcStats::default());
|
let rpc_stats = Arc::new(informant::RpcStats::default());
|
||||||
let signer_path = cmd.signer_conf.signer_path.clone();
|
let signer_path = cmd.signer_conf.signer_path.clone();
|
||||||
|
let secret_store = match cmd.public_node {
|
||||||
|
true => None,
|
||||||
|
false => Some(account_provider.clone())
|
||||||
|
};
|
||||||
let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies {
|
let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies {
|
||||||
signer_service: Arc::new(rpc_apis::SignerService::new(move || {
|
signer_service: Arc::new(rpc_apis::SignerService::new(move || {
|
||||||
signer::generate_new_token(signer_path.clone()).map_err(|e| format!("{:?}", e))
|
signer::generate_new_token(signer_path.clone()).map_err(|e| format!("{:?}", e))
|
||||||
@ -415,7 +420,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
|||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
sync: sync_provider.clone(),
|
sync: sync_provider.clone(),
|
||||||
net: manage_network.clone(),
|
net: manage_network.clone(),
|
||||||
secret_store: account_provider.clone(),
|
secret_store: secret_store,
|
||||||
miner: miner.clone(),
|
miner: miner.clone(),
|
||||||
external_miner: external_miner.clone(),
|
external_miner: external_miner.clone(),
|
||||||
logger: logger.clone(),
|
logger: logger.clone(),
|
||||||
|
27
rpc/src/v1/helpers/accounts.rs
Normal file
27
rpc/src/v1/helpers/accounts.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
use ethcore::account_provider::AccountProvider;
|
||||||
|
use jsonrpc_core::Error;
|
||||||
|
use v1::helpers::errors;
|
||||||
|
|
||||||
|
pub fn unwrap_provider(provider: &Option<Weak<AccountProvider>>) -> Result<Arc<AccountProvider>, Error> {
|
||||||
|
match *provider {
|
||||||
|
Some(ref weak) => weak.upgrade().ok_or_else(Error::internal_error),
|
||||||
|
None => Err(errors::public_unsupported(None)),
|
||||||
|
}
|
||||||
|
}
|
@ -65,6 +65,14 @@ pub fn light_unimplemented(details: Option<String>) -> Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn public_unsupported(details: Option<String>) -> Error {
|
||||||
|
Error {
|
||||||
|
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||||
|
message: "Method disallowed when running parity as a public node.".into(),
|
||||||
|
data: details.map(Value::String),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn request_not_found() -> Error {
|
pub fn request_not_found() -> Error {
|
||||||
Error {
|
Error {
|
||||||
code: ErrorCode::ServerError(codes::REQUEST_NOT_FOUND),
|
code: ErrorCode::ServerError(codes::REQUEST_NOT_FOUND),
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
|
||||||
|
pub mod accounts;
|
||||||
pub mod block_import;
|
pub mod block_import;
|
||||||
pub mod dispatch;
|
pub mod dispatch;
|
||||||
pub mod fake_sign;
|
pub mod fake_sign;
|
||||||
|
@ -46,6 +46,7 @@ use jsonrpc_macros::Trailing;
|
|||||||
use v1::helpers::{errors, limit_logs, fake_sign};
|
use v1::helpers::{errors, limit_logs, fake_sign};
|
||||||
use v1::helpers::dispatch::{Dispatcher, FullDispatcher, default_gas_price};
|
use v1::helpers::dispatch::{Dispatcher, FullDispatcher, default_gas_price};
|
||||||
use v1::helpers::block_import::is_major_importing;
|
use v1::helpers::block_import::is_major_importing;
|
||||||
|
use v1::helpers::accounts::unwrap_provider;
|
||||||
use v1::traits::Eth;
|
use v1::traits::Eth;
|
||||||
use v1::types::{
|
use v1::types::{
|
||||||
RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
|
RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
|
||||||
@ -97,7 +98,7 @@ pub struct EthClient<C, SN: ?Sized, S: ?Sized, M, EM> where
|
|||||||
client: Weak<C>,
|
client: Weak<C>,
|
||||||
snapshot: Weak<SN>,
|
snapshot: Weak<SN>,
|
||||||
sync: Weak<S>,
|
sync: Weak<S>,
|
||||||
accounts: Weak<AccountProvider>,
|
accounts: Option<Weak<AccountProvider>>,
|
||||||
miner: Weak<M>,
|
miner: Weak<M>,
|
||||||
external_miner: Arc<EM>,
|
external_miner: Arc<EM>,
|
||||||
seed_compute: Mutex<SeedHashCompute>,
|
seed_compute: Mutex<SeedHashCompute>,
|
||||||
@ -116,7 +117,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
|
|||||||
client: &Arc<C>,
|
client: &Arc<C>,
|
||||||
snapshot: &Arc<SN>,
|
snapshot: &Arc<SN>,
|
||||||
sync: &Arc<S>,
|
sync: &Arc<S>,
|
||||||
accounts: &Arc<AccountProvider>,
|
accounts: &Option<Arc<AccountProvider>>,
|
||||||
miner: &Arc<M>,
|
miner: &Arc<M>,
|
||||||
em: &Arc<EM>,
|
em: &Arc<EM>,
|
||||||
options: EthClientOptions
|
options: EthClientOptions
|
||||||
@ -126,13 +127,19 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
|
|||||||
snapshot: Arc::downgrade(snapshot),
|
snapshot: Arc::downgrade(snapshot),
|
||||||
sync: Arc::downgrade(sync),
|
sync: Arc::downgrade(sync),
|
||||||
miner: Arc::downgrade(miner),
|
miner: Arc::downgrade(miner),
|
||||||
accounts: Arc::downgrade(accounts),
|
accounts: accounts.as_ref().map(Arc::downgrade),
|
||||||
external_miner: em.clone(),
|
external_miner: em.clone(),
|
||||||
seed_compute: Mutex::new(SeedHashCompute::new()),
|
seed_compute: Mutex::new(SeedHashCompute::new()),
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempt to get the `Arc<AccountProvider>`, errors if provider was not
|
||||||
|
/// set, or if upgrading the weak reference failed.
|
||||||
|
fn account_provider(&self) -> Result<Arc<AccountProvider>, Error> {
|
||||||
|
unwrap_provider(&self.accounts)
|
||||||
|
}
|
||||||
|
|
||||||
fn block(&self, id: BlockId, include_txs: bool) -> Result<Option<RichBlock>, Error> {
|
fn block(&self, id: BlockId, include_txs: bool) -> Result<Option<RichBlock>, Error> {
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
match (client.block(id.clone()), client.block_total_difficulty(id)) {
|
match (client.block(id.clone()), client.block_total_difficulty(id)) {
|
||||||
@ -223,7 +230,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dapp_accounts(&self, dapp: DappId) -> Result<Vec<H160>, Error> {
|
fn dapp_accounts(&self, dapp: DappId) -> Result<Vec<H160>, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
store
|
store
|
||||||
.note_dapp_used(dapp.clone())
|
.note_dapp_used(dapp.clone())
|
||||||
.and_then(|_| store.dapp_addresses(dapp))
|
.and_then(|_| store.dapp_addresses(dapp))
|
||||||
|
@ -40,7 +40,7 @@ use v1::types::{
|
|||||||
TransactionStats, LocalTransactionStatus,
|
TransactionStats, LocalTransactionStatus,
|
||||||
BlockNumber, ConsensusCapability, VersionInfo,
|
BlockNumber, ConsensusCapability, VersionInfo,
|
||||||
OperationsInfo, DappId, ChainStatus,
|
OperationsInfo, DappId, ChainStatus,
|
||||||
AccountInfo, HwAccountInfo
|
AccountInfo, HwAccountInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parity implementation for light client.
|
/// Parity implementation for light client.
|
||||||
|
@ -37,6 +37,7 @@ use updater::{Service as UpdateService};
|
|||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use jsonrpc_macros::Trailing;
|
use jsonrpc_macros::Trailing;
|
||||||
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings};
|
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings};
|
||||||
|
use v1::helpers::accounts::unwrap_provider;
|
||||||
use v1::helpers::dispatch::DEFAULT_MAC;
|
use v1::helpers::dispatch::DEFAULT_MAC;
|
||||||
use v1::metadata::Metadata;
|
use v1::metadata::Metadata;
|
||||||
use v1::traits::Parity;
|
use v1::traits::Parity;
|
||||||
@ -46,7 +47,7 @@ use v1::types::{
|
|||||||
TransactionStats, LocalTransactionStatus,
|
TransactionStats, LocalTransactionStatus,
|
||||||
BlockNumber, ConsensusCapability, VersionInfo,
|
BlockNumber, ConsensusCapability, VersionInfo,
|
||||||
OperationsInfo, DappId, ChainStatus,
|
OperationsInfo, DappId, ChainStatus,
|
||||||
AccountInfo, HwAccountInfo
|
AccountInfo, HwAccountInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parity implementation.
|
/// Parity implementation.
|
||||||
@ -61,7 +62,7 @@ pub struct ParityClient<C, M, S: ?Sized, U> where
|
|||||||
sync: Weak<S>,
|
sync: Weak<S>,
|
||||||
updater: Weak<U>,
|
updater: Weak<U>,
|
||||||
net: Weak<ManageNetwork>,
|
net: Weak<ManageNetwork>,
|
||||||
accounts: Weak<AccountProvider>,
|
accounts: Option<Weak<AccountProvider>>,
|
||||||
logger: Arc<RotatingLogger>,
|
logger: Arc<RotatingLogger>,
|
||||||
settings: Arc<NetworkSettings>,
|
settings: Arc<NetworkSettings>,
|
||||||
signer: Option<Arc<SignerService>>,
|
signer: Option<Arc<SignerService>>,
|
||||||
@ -82,7 +83,7 @@ impl<C, M, S: ?Sized, U> ParityClient<C, M, S, U> where
|
|||||||
sync: &Arc<S>,
|
sync: &Arc<S>,
|
||||||
updater: &Arc<U>,
|
updater: &Arc<U>,
|
||||||
net: &Arc<ManageNetwork>,
|
net: &Arc<ManageNetwork>,
|
||||||
store: &Arc<AccountProvider>,
|
store: &Option<Arc<AccountProvider>>,
|
||||||
logger: Arc<RotatingLogger>,
|
logger: Arc<RotatingLogger>,
|
||||||
settings: Arc<NetworkSettings>,
|
settings: Arc<NetworkSettings>,
|
||||||
signer: Option<Arc<SignerService>>,
|
signer: Option<Arc<SignerService>>,
|
||||||
@ -95,7 +96,7 @@ impl<C, M, S: ?Sized, U> ParityClient<C, M, S, U> where
|
|||||||
sync: Arc::downgrade(sync),
|
sync: Arc::downgrade(sync),
|
||||||
updater: Arc::downgrade(updater),
|
updater: Arc::downgrade(updater),
|
||||||
net: Arc::downgrade(net),
|
net: Arc::downgrade(net),
|
||||||
accounts: Arc::downgrade(store),
|
accounts: store.as_ref().map(Arc::downgrade),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
settings: settings,
|
settings: settings,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
@ -103,6 +104,12 @@ impl<C, M, S: ?Sized, U> ParityClient<C, M, S, U> where
|
|||||||
dapps_port: dapps_port,
|
dapps_port: dapps_port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempt to get the `Arc<AccountProvider>`, errors if provider was not
|
||||||
|
/// set, or if upgrading the weak reference failed.
|
||||||
|
fn account_provider(&self) -> Result<Arc<AccountProvider>, Error> {
|
||||||
|
unwrap_provider(&self.accounts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
||||||
@ -116,7 +123,7 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
|||||||
fn accounts_info(&self, dapp: Trailing<DappId>) -> Result<BTreeMap<H160, AccountInfo>, Error> {
|
fn accounts_info(&self, dapp: Trailing<DappId>) -> Result<BTreeMap<H160, AccountInfo>, Error> {
|
||||||
let dapp = dapp.0;
|
let dapp = dapp.0;
|
||||||
|
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
let dapp_accounts = store
|
let dapp_accounts = store
|
||||||
.note_dapp_used(dapp.clone().into())
|
.note_dapp_used(dapp.clone().into())
|
||||||
.and_then(|_| store.dapp_addresses(dapp.into()))
|
.and_then(|_| store.dapp_addresses(dapp.into()))
|
||||||
@ -136,7 +143,7 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn hardware_accounts_info(&self) -> Result<BTreeMap<H160, HwAccountInfo>, Error> {
|
fn hardware_accounts_info(&self) -> Result<BTreeMap<H160, HwAccountInfo>, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
let info = store.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?;
|
let info = store.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?;
|
||||||
Ok(info
|
Ok(info
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -148,7 +155,7 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
|||||||
fn default_account(&self, meta: Self::Metadata) -> BoxFuture<H160, Error> {
|
fn default_account(&self, meta: Self::Metadata) -> BoxFuture<H160, Error> {
|
||||||
let dapp_id = meta.dapp_id();
|
let dapp_id = meta.dapp_id();
|
||||||
future::ok(
|
future::ok(
|
||||||
take_weakf!(self.accounts)
|
try_bf!(self.account_provider())
|
||||||
.dapp_default_address(dapp_id.into())
|
.dapp_default_address(dapp_id.into())
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.ok()
|
.ok()
|
||||||
@ -376,9 +383,13 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
|||||||
fn node_kind(&self) -> Result<::v1::types::NodeKind, Error> {
|
fn node_kind(&self) -> Result<::v1::types::NodeKind, Error> {
|
||||||
use ::v1::types::{NodeKind, Availability, Capability};
|
use ::v1::types::{NodeKind, Availability, Capability};
|
||||||
|
|
||||||
// TODO [maciej]: public availability flag.
|
let availability = match self.accounts {
|
||||||
|
Some(_) => Availability::Personal,
|
||||||
|
None => Availability::Public
|
||||||
|
};
|
||||||
|
|
||||||
Ok(NodeKind {
|
Ok(NodeKind {
|
||||||
availability: Availability::Personal,
|
availability: availability,
|
||||||
capability: Capability::Full,
|
capability: Capability::Full,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -25,26 +25,33 @@ use ethcore::account_provider::AccountProvider;
|
|||||||
|
|
||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use v1::helpers::errors;
|
use v1::helpers::errors;
|
||||||
|
use v1::helpers::accounts::unwrap_provider;
|
||||||
use v1::traits::ParityAccounts;
|
use v1::traits::ParityAccounts;
|
||||||
use v1::types::{H160 as RpcH160, H256 as RpcH256, DappId, Derive, DeriveHierarchical, DeriveHash};
|
use v1::types::{H160 as RpcH160, H256 as RpcH256, DappId, Derive, DeriveHierarchical, DeriveHash};
|
||||||
|
|
||||||
/// Account management (personal) rpc implementation.
|
/// Account management (personal) rpc implementation.
|
||||||
pub struct ParityAccountsClient {
|
pub struct ParityAccountsClient {
|
||||||
accounts: Weak<AccountProvider>,
|
accounts: Option<Weak<AccountProvider>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParityAccountsClient {
|
impl ParityAccountsClient {
|
||||||
/// Creates new PersonalClient
|
/// Creates new PersonalClient
|
||||||
pub fn new(store: &Arc<AccountProvider>) -> Self {
|
pub fn new(store: &Option<Arc<AccountProvider>>) -> Self {
|
||||||
ParityAccountsClient {
|
ParityAccountsClient {
|
||||||
accounts: Arc::downgrade(store),
|
accounts: store.as_ref().map(Arc::downgrade),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempt to get the `Arc<AccountProvider>`, errors if provider was not
|
||||||
|
/// set, or if upgrading the weak reference failed.
|
||||||
|
fn account_provider(&self) -> Result<Arc<AccountProvider>, Error> {
|
||||||
|
unwrap_provider(&self.accounts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParityAccounts for ParityAccountsClient {
|
impl ParityAccounts for ParityAccountsClient {
|
||||||
fn all_accounts_info(&self) -> Result<BTreeMap<RpcH160, BTreeMap<String, String>>, Error> {
|
fn all_accounts_info(&self) -> Result<BTreeMap<RpcH160, BTreeMap<String, String>>, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
let info = store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?;
|
let info = store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?;
|
||||||
let other = store.addresses_info();
|
let other = store.addresses_info();
|
||||||
|
|
||||||
@ -66,7 +73,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_account_from_phrase(&self, phrase: String, pass: String) -> Result<RpcH160, Error> {
|
fn new_account_from_phrase(&self, phrase: String, pass: String) -> Result<RpcH160, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
let brain = Brain::new(phrase).generate().unwrap();
|
let brain = Brain::new(phrase).generate().unwrap();
|
||||||
store.insert_account(brain.secret().clone(), &pass)
|
store.insert_account(brain.secret().clone(), &pass)
|
||||||
@ -75,7 +82,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_account_from_wallet(&self, json: String, pass: String) -> Result<RpcH160, Error> {
|
fn new_account_from_wallet(&self, json: String, pass: String) -> Result<RpcH160, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.import_presale(json.as_bytes(), &pass)
|
store.import_presale(json.as_bytes(), &pass)
|
||||||
.or_else(|_| store.import_wallet(json.as_bytes(), &pass))
|
.or_else(|_| store.import_wallet(json.as_bytes(), &pass))
|
||||||
@ -84,7 +91,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_account_from_secret(&self, secret: RpcH256, pass: String) -> Result<RpcH160, Error> {
|
fn new_account_from_secret(&self, secret: RpcH256, pass: String) -> Result<RpcH160, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
let secret = Secret::from_slice(&secret.0)
|
let secret = Secret::from_slice(&secret.0)
|
||||||
.map_err(|e| errors::account("Could not create account.", e))?;
|
.map_err(|e| errors::account("Could not create account.", e))?;
|
||||||
@ -96,14 +103,14 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
fn test_password(&self, account: RpcH160, password: String) -> Result<bool, Error> {
|
fn test_password(&self, account: RpcH160, password: String) -> Result<bool, Error> {
|
||||||
let account: Address = account.into();
|
let account: Address = account.into();
|
||||||
|
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.test_password(&account, &password)
|
.test_password(&account, &password)
|
||||||
.map_err(|e| errors::account("Could not fetch account info.", e))
|
.map_err(|e| errors::account("Could not fetch account info.", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_password(&self, account: RpcH160, password: String, new_password: String) -> Result<bool, Error> {
|
fn change_password(&self, account: RpcH160, password: String, new_password: String) -> Result<bool, Error> {
|
||||||
let account: Address = account.into();
|
let account: Address = account.into();
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.change_password(&account, password, new_password)
|
.change_password(&account, password, new_password)
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
.map_err(|e| errors::account("Could not fetch account info.", e))
|
.map_err(|e| errors::account("Could not fetch account info.", e))
|
||||||
@ -111,14 +118,14 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
|
|
||||||
fn kill_account(&self, account: RpcH160, password: String) -> Result<bool, Error> {
|
fn kill_account(&self, account: RpcH160, password: String) -> Result<bool, Error> {
|
||||||
let account: Address = account.into();
|
let account: Address = account.into();
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.kill_account(&account, &password)
|
.kill_account(&account, &password)
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
.map_err(|e| errors::account("Could not delete account.", e))
|
.map_err(|e| errors::account("Could not delete account.", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_address(&self, addr: RpcH160) -> Result<bool, Error> {
|
fn remove_address(&self, addr: RpcH160) -> Result<bool, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
let addr: Address = addr.into();
|
let addr: Address = addr.into();
|
||||||
|
|
||||||
store.remove_address(addr);
|
store.remove_address(addr);
|
||||||
@ -126,7 +133,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_account_name(&self, addr: RpcH160, name: String) -> Result<bool, Error> {
|
fn set_account_name(&self, addr: RpcH160, name: String) -> Result<bool, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
let addr: Address = addr.into();
|
let addr: Address = addr.into();
|
||||||
|
|
||||||
store.set_account_name(addr.clone(), name.clone())
|
store.set_account_name(addr.clone(), name.clone())
|
||||||
@ -135,7 +142,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_account_meta(&self, addr: RpcH160, meta: String) -> Result<bool, Error> {
|
fn set_account_meta(&self, addr: RpcH160, meta: String) -> Result<bool, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
let addr: Address = addr.into();
|
let addr: Address = addr.into();
|
||||||
|
|
||||||
store.set_account_meta(addr.clone(), meta.clone())
|
store.set_account_meta(addr.clone(), meta.clone())
|
||||||
@ -144,7 +151,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_dapp_addresses(&self, dapp: DappId, addresses: Option<Vec<RpcH160>>) -> Result<bool, Error> {
|
fn set_dapp_addresses(&self, dapp: DappId, addresses: Option<Vec<RpcH160>>) -> Result<bool, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.set_dapp_addresses(dapp.into(), addresses.map(into_vec))
|
store.set_dapp_addresses(dapp.into(), addresses.map(into_vec))
|
||||||
.map_err(|e| errors::account("Couldn't set dapp addresses.", e))
|
.map_err(|e| errors::account("Couldn't set dapp addresses.", e))
|
||||||
@ -152,7 +159,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dapp_addresses(&self, dapp: DappId) -> Result<Vec<RpcH160>, Error> {
|
fn dapp_addresses(&self, dapp: DappId) -> Result<Vec<RpcH160>, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.dapp_addresses(dapp.into())
|
store.dapp_addresses(dapp.into())
|
||||||
.map_err(|e| errors::account("Couldn't get dapp addresses.", e))
|
.map_err(|e| errors::account("Couldn't get dapp addresses.", e))
|
||||||
@ -160,7 +167,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_dapp_default_address(&self, dapp: DappId, address: RpcH160) -> Result<bool, Error> {
|
fn set_dapp_default_address(&self, dapp: DappId, address: RpcH160) -> Result<bool, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.set_dapp_default_address(dapp.into(), address.into())
|
store.set_dapp_default_address(dapp.into(), address.into())
|
||||||
.map_err(|e| errors::account("Couldn't set dapp default address.", e))
|
.map_err(|e| errors::account("Couldn't set dapp default address.", e))
|
||||||
@ -168,7 +175,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dapp_default_address(&self, dapp: DappId) -> Result<RpcH160, Error> {
|
fn dapp_default_address(&self, dapp: DappId) -> Result<RpcH160, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.dapp_default_address(dapp.into())
|
store.dapp_default_address(dapp.into())
|
||||||
.map_err(|e| errors::account("Couldn't get dapp default address.", e))
|
.map_err(|e| errors::account("Couldn't get dapp default address.", e))
|
||||||
@ -176,7 +183,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_new_dapps_addresses(&self, addresses: Option<Vec<RpcH160>>) -> Result<bool, Error> {
|
fn set_new_dapps_addresses(&self, addresses: Option<Vec<RpcH160>>) -> Result<bool, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store
|
store
|
||||||
.set_new_dapps_addresses(addresses.map(into_vec))
|
.set_new_dapps_addresses(addresses.map(into_vec))
|
||||||
@ -185,7 +192,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_dapps_addresses(&self) -> Result<Option<Vec<RpcH160>>, Error> {
|
fn new_dapps_addresses(&self) -> Result<Option<Vec<RpcH160>>, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.new_dapps_addresses()
|
store.new_dapps_addresses()
|
||||||
.map_err(|e| errors::account("Couldn't get dapps addresses.", e))
|
.map_err(|e| errors::account("Couldn't get dapps addresses.", e))
|
||||||
@ -193,7 +200,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_new_dapps_default_address(&self, address: RpcH160) -> Result<bool, Error> {
|
fn set_new_dapps_default_address(&self, address: RpcH160) -> Result<bool, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.set_new_dapps_default_address(address.into())
|
store.set_new_dapps_default_address(address.into())
|
||||||
.map_err(|e| errors::account("Couldn't set new dapps default address.", e))
|
.map_err(|e| errors::account("Couldn't set new dapps default address.", e))
|
||||||
@ -201,7 +208,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_dapps_default_address(&self) -> Result<RpcH160, Error> {
|
fn new_dapps_default_address(&self) -> Result<RpcH160, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.new_dapps_default_address()
|
store.new_dapps_default_address()
|
||||||
.map_err(|e| errors::account("Couldn't get new dapps default address.", e))
|
.map_err(|e| errors::account("Couldn't get new dapps default address.", e))
|
||||||
@ -209,7 +216,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn recent_dapps(&self) -> Result<BTreeMap<DappId, u64>, Error> {
|
fn recent_dapps(&self) -> Result<BTreeMap<DappId, u64>, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.recent_dapps()
|
store.recent_dapps()
|
||||||
.map_err(|e| errors::account("Couldn't get recent dapps.", e))
|
.map_err(|e| errors::account("Couldn't get recent dapps.", e))
|
||||||
@ -217,7 +224,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn import_geth_accounts(&self, addresses: Vec<RpcH160>) -> Result<Vec<RpcH160>, Error> {
|
fn import_geth_accounts(&self, addresses: Vec<RpcH160>) -> Result<Vec<RpcH160>, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store
|
store
|
||||||
.import_geth_accounts(into_vec(addresses), false)
|
.import_geth_accounts(into_vec(addresses), false)
|
||||||
@ -226,66 +233,66 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn geth_accounts(&self) -> Result<Vec<RpcH160>, Error> {
|
fn geth_accounts(&self) -> Result<Vec<RpcH160>, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
Ok(into_vec(store.list_geth_accounts(false)))
|
Ok(into_vec(store.list_geth_accounts(false)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_vault(&self, name: String, password: String) -> Result<bool, Error> {
|
fn create_vault(&self, name: String, password: String) -> Result<bool, Error> {
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.create_vault(&name, &password)
|
.create_vault(&name, &password)
|
||||||
.map_err(|e| errors::account("Could not create vault.", e))
|
.map_err(|e| errors::account("Could not create vault.", e))
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_vault(&self, name: String, password: String) -> Result<bool, Error> {
|
fn open_vault(&self, name: String, password: String) -> Result<bool, Error> {
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.open_vault(&name, &password)
|
.open_vault(&name, &password)
|
||||||
.map_err(|e| errors::account("Could not open vault.", e))
|
.map_err(|e| errors::account("Could not open vault.", e))
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_vault(&self, name: String) -> Result<bool, Error> {
|
fn close_vault(&self, name: String) -> Result<bool, Error> {
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.close_vault(&name)
|
.close_vault(&name)
|
||||||
.map_err(|e| errors::account("Could not close vault.", e))
|
.map_err(|e| errors::account("Could not close vault.", e))
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_vaults(&self) -> Result<Vec<String>, Error> {
|
fn list_vaults(&self) -> Result<Vec<String>, Error> {
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.list_vaults()
|
.list_vaults()
|
||||||
.map_err(|e| errors::account("Could not list vaults.", e))
|
.map_err(|e| errors::account("Could not list vaults.", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_opened_vaults(&self) -> Result<Vec<String>, Error> {
|
fn list_opened_vaults(&self) -> Result<Vec<String>, Error> {
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.list_opened_vaults()
|
.list_opened_vaults()
|
||||||
.map_err(|e| errors::account("Could not list vaults.", e))
|
.map_err(|e| errors::account("Could not list vaults.", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_vault_password(&self, name: String, new_password: String) -> Result<bool, Error> {
|
fn change_vault_password(&self, name: String, new_password: String) -> Result<bool, Error> {
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.change_vault_password(&name, &new_password)
|
.change_vault_password(&name, &new_password)
|
||||||
.map_err(|e| errors::account("Could not change vault password.", e))
|
.map_err(|e| errors::account("Could not change vault password.", e))
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_vault(&self, address: RpcH160, new_vault: String) -> Result<bool, Error> {
|
fn change_vault(&self, address: RpcH160, new_vault: String) -> Result<bool, Error> {
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.change_vault(address.into(), &new_vault)
|
.change_vault(address.into(), &new_vault)
|
||||||
.map_err(|e| errors::account("Could not change vault.", e))
|
.map_err(|e| errors::account("Could not change vault.", e))
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_vault_meta(&self, name: String) -> Result<String, Error> {
|
fn get_vault_meta(&self, name: String) -> Result<String, Error> {
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.get_vault_meta(&name)
|
.get_vault_meta(&name)
|
||||||
.map_err(|e| errors::account("Could not get vault metadata.", e))
|
.map_err(|e| errors::account("Could not get vault metadata.", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_vault_meta(&self, name: String, meta: String) -> Result<bool, Error> {
|
fn set_vault_meta(&self, name: String, meta: String) -> Result<bool, Error> {
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.set_vault_meta(&name, &meta)
|
.set_vault_meta(&name, &meta)
|
||||||
.map_err(|e| errors::account("Could not update vault metadata.", e))
|
.map_err(|e| errors::account("Could not update vault metadata.", e))
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
@ -293,7 +300,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
|
|
||||||
fn derive_key_index(&self, addr: RpcH160, password: String, derivation: DeriveHierarchical, save_as_account: bool) -> Result<RpcH160, Error> {
|
fn derive_key_index(&self, addr: RpcH160, password: String, derivation: DeriveHierarchical, save_as_account: bool) -> Result<RpcH160, Error> {
|
||||||
let addr: Address = addr.into();
|
let addr: Address = addr.into();
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.derive_account(
|
.derive_account(
|
||||||
&addr,
|
&addr,
|
||||||
Some(password),
|
Some(password),
|
||||||
@ -306,7 +313,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
|
|
||||||
fn derive_key_hash(&self, addr: RpcH160, password: String, derivation: DeriveHash, save_as_account: bool) -> Result<RpcH160, Error> {
|
fn derive_key_hash(&self, addr: RpcH160, password: String, derivation: DeriveHash, save_as_account: bool) -> Result<RpcH160, Error> {
|
||||||
let addr: Address = addr.into();
|
let addr: Address = addr.into();
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.derive_account(
|
.derive_account(
|
||||||
&addr,
|
&addr,
|
||||||
Some(password),
|
Some(password),
|
||||||
@ -319,7 +326,7 @@ impl ParityAccounts for ParityAccountsClient {
|
|||||||
|
|
||||||
fn export_account(&self, addr: RpcH160, password: String) -> Result<KeyFile, Error> {
|
fn export_account(&self, addr: RpcH160, password: String) -> Result<KeyFile, Error> {
|
||||||
let addr = addr.into();
|
let addr = addr.into();
|
||||||
take_weak!(self.accounts)
|
self.account_provider()?
|
||||||
.export_account(
|
.export_account(
|
||||||
&addr,
|
&addr,
|
||||||
password,
|
password,
|
||||||
|
@ -26,39 +26,44 @@ use futures::{future, Future, BoxFuture};
|
|||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use v1::helpers::errors;
|
use v1::helpers::errors;
|
||||||
use v1::helpers::dispatch::{Dispatcher, SignWith};
|
use v1::helpers::dispatch::{Dispatcher, SignWith};
|
||||||
|
use v1::helpers::accounts::unwrap_provider;
|
||||||
use v1::traits::Personal;
|
use v1::traits::Personal;
|
||||||
use v1::types::{H160 as RpcH160, H256 as RpcH256, U128 as RpcU128, TransactionRequest};
|
use v1::types::{H160 as RpcH160, H256 as RpcH256, U128 as RpcU128, TransactionRequest};
|
||||||
use v1::metadata::Metadata;
|
use v1::metadata::Metadata;
|
||||||
|
|
||||||
/// Account management (personal) rpc implementation.
|
/// Account management (personal) rpc implementation.
|
||||||
pub struct PersonalClient<D: Dispatcher> {
|
pub struct PersonalClient<D: Dispatcher> {
|
||||||
accounts: Weak<AccountProvider>,
|
accounts: Option<Weak<AccountProvider>>,
|
||||||
dispatcher: D,
|
dispatcher: D,
|
||||||
allow_perm_unlock: bool,
|
allow_perm_unlock: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Dispatcher> PersonalClient<D> {
|
impl<D: Dispatcher> PersonalClient<D> {
|
||||||
/// Creates new PersonalClient
|
/// Creates new PersonalClient
|
||||||
pub fn new(store: &Arc<AccountProvider>, dispatcher: D, allow_perm_unlock: bool) -> Self {
|
pub fn new(store: &Option<Arc<AccountProvider>>, dispatcher: D, allow_perm_unlock: bool) -> Self {
|
||||||
PersonalClient {
|
PersonalClient {
|
||||||
accounts: Arc::downgrade(store),
|
accounts: store.as_ref().map(Arc::downgrade),
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
allow_perm_unlock: allow_perm_unlock,
|
allow_perm_unlock: allow_perm_unlock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn account_provider(&self) -> Result<Arc<AccountProvider>, Error> {
|
||||||
|
unwrap_provider(&self.accounts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
|
impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
|
||||||
type Metadata = Metadata;
|
type Metadata = Metadata;
|
||||||
|
|
||||||
fn accounts(&self) -> Result<Vec<RpcH160>, Error> {
|
fn accounts(&self) -> Result<Vec<RpcH160>, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
let accounts = store.accounts().map_err(|e| errors::account("Could not fetch accounts.", e))?;
|
let accounts = store.accounts().map_err(|e| errors::account("Could not fetch accounts.", e))?;
|
||||||
Ok(accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
|
Ok(accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_account(&self, pass: String) -> Result<RpcH160, Error> {
|
fn new_account(&self, pass: String) -> Result<RpcH160, Error> {
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
|
|
||||||
store.new_account(&pass)
|
store.new_account(&pass)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
@ -67,7 +72,7 @@ impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
|
|||||||
|
|
||||||
fn unlock_account(&self, account: RpcH160, account_pass: String, duration: Option<RpcU128>) -> Result<bool, Error> {
|
fn unlock_account(&self, account: RpcH160, account_pass: String, duration: Option<RpcU128>) -> Result<bool, Error> {
|
||||||
let account: Address = account.into();
|
let account: Address = account.into();
|
||||||
let store = take_weak!(self.accounts);
|
let store = self.account_provider()?;
|
||||||
let duration = match duration {
|
let duration = match duration {
|
||||||
None => None,
|
None => None,
|
||||||
Some(duration) => {
|
Some(duration) => {
|
||||||
@ -96,7 +101,7 @@ impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
|
|||||||
|
|
||||||
fn send_transaction(&self, meta: Metadata, request: TransactionRequest, password: String) -> BoxFuture<RpcH256, Error> {
|
fn send_transaction(&self, meta: Metadata, request: TransactionRequest, password: String) -> BoxFuture<RpcH256, Error> {
|
||||||
let dispatcher = self.dispatcher.clone();
|
let dispatcher = self.dispatcher.clone();
|
||||||
let accounts = take_weakf!(self.accounts);
|
let accounts = try_bf!(self.account_provider());
|
||||||
|
|
||||||
let default = match request.from.as_ref() {
|
let default = match request.from.as_ref() {
|
||||||
Some(account) => Ok(account.clone().into()),
|
Some(account) => Ok(account.clone().into()),
|
||||||
|
@ -26,13 +26,14 @@ use futures::{future, BoxFuture, Future, IntoFuture};
|
|||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use v1::helpers::{errors, SignerService, SigningQueue, ConfirmationPayload};
|
use v1::helpers::{errors, SignerService, SigningQueue, ConfirmationPayload};
|
||||||
use v1::helpers::dispatch::{self, Dispatcher, WithToken};
|
use v1::helpers::dispatch::{self, Dispatcher, WithToken};
|
||||||
|
use v1::helpers::accounts::unwrap_provider;
|
||||||
use v1::traits::Signer;
|
use v1::traits::Signer;
|
||||||
use v1::types::{TransactionModification, ConfirmationRequest, ConfirmationResponse, ConfirmationResponseWithToken, U256, Bytes};
|
use v1::types::{TransactionModification, ConfirmationRequest, ConfirmationResponse, ConfirmationResponseWithToken, U256, Bytes};
|
||||||
|
|
||||||
/// Transactions confirmation (personal) rpc implementation.
|
/// Transactions confirmation (personal) rpc implementation.
|
||||||
pub struct SignerClient<D: Dispatcher> {
|
pub struct SignerClient<D: Dispatcher> {
|
||||||
signer: Weak<SignerService>,
|
signer: Weak<SignerService>,
|
||||||
accounts: Weak<AccountProvider>,
|
accounts: Option<Weak<AccountProvider>>,
|
||||||
dispatcher: D
|
dispatcher: D
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,17 +41,21 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
|
|||||||
|
|
||||||
/// Create new instance of signer client.
|
/// Create new instance of signer client.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
store: &Arc<AccountProvider>,
|
store: &Option<Arc<AccountProvider>>,
|
||||||
dispatcher: D,
|
dispatcher: D,
|
||||||
signer: &Arc<SignerService>,
|
signer: &Arc<SignerService>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
SignerClient {
|
SignerClient {
|
||||||
signer: Arc::downgrade(signer),
|
signer: Arc::downgrade(signer),
|
||||||
accounts: Arc::downgrade(store),
|
accounts: store.as_ref().map(Arc::downgrade),
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn account_provider(&self) -> Result<Arc<AccountProvider>, Error> {
|
||||||
|
unwrap_provider(&self.accounts)
|
||||||
|
}
|
||||||
|
|
||||||
fn confirm_internal<F, T>(&self, id: U256, modification: TransactionModification, f: F) -> BoxFuture<WithToken<ConfirmationResponse>, Error> where
|
fn confirm_internal<F, T>(&self, id: U256, modification: TransactionModification, f: F) -> BoxFuture<WithToken<ConfirmationResponse>, Error> where
|
||||||
F: FnOnce(D, Arc<AccountProvider>, ConfirmationPayload) -> T,
|
F: FnOnce(D, Arc<AccountProvider>, ConfirmationPayload) -> T,
|
||||||
T: IntoFuture<Item=WithToken<ConfirmationResponse>, Error=Error>,
|
T: IntoFuture<Item=WithToken<ConfirmationResponse>, Error=Error>,
|
||||||
@ -60,7 +65,7 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
|
|||||||
let dispatcher = self.dispatcher.clone();
|
let dispatcher = self.dispatcher.clone();
|
||||||
|
|
||||||
let setup = || {
|
let setup = || {
|
||||||
Ok((take_weak!(self.accounts), take_weak!(self.signer)))
|
Ok((self.account_provider()?, take_weak!(self.signer)))
|
||||||
};
|
};
|
||||||
|
|
||||||
let (accounts, signer) = match setup() {
|
let (accounts, signer) = match setup() {
|
||||||
|
@ -30,6 +30,7 @@ use v1::helpers::{
|
|||||||
SIGNING_QUEUE_LIMIT, SigningQueue, ConfirmationPromise, ConfirmationResult, SignerService
|
SIGNING_QUEUE_LIMIT, SigningQueue, ConfirmationPromise, ConfirmationResult, SignerService
|
||||||
};
|
};
|
||||||
use v1::helpers::dispatch::{self, Dispatcher};
|
use v1::helpers::dispatch::{self, Dispatcher};
|
||||||
|
use v1::helpers::accounts::unwrap_provider;
|
||||||
use v1::metadata::Metadata;
|
use v1::metadata::Metadata;
|
||||||
use v1::traits::{EthSigning, ParitySigning};
|
use v1::traits::{EthSigning, ParitySigning};
|
||||||
use v1::types::{
|
use v1::types::{
|
||||||
@ -55,7 +56,7 @@ enum DispatchResult {
|
|||||||
/// Implementation of functions that require signing when no trusted signer is used.
|
/// Implementation of functions that require signing when no trusted signer is used.
|
||||||
pub struct SigningQueueClient<D> {
|
pub struct SigningQueueClient<D> {
|
||||||
signer: Weak<SignerService>,
|
signer: Weak<SignerService>,
|
||||||
accounts: Weak<AccountProvider>,
|
accounts: Option<Weak<AccountProvider>>,
|
||||||
dispatcher: D,
|
dispatcher: D,
|
||||||
pending: Arc<Mutex<TransientHashMap<U256, ConfirmationPromise>>>,
|
pending: Arc<Mutex<TransientHashMap<U256, ConfirmationPromise>>>,
|
||||||
}
|
}
|
||||||
@ -91,17 +92,21 @@ fn collect_garbage(map: &mut TransientHashMap<U256, ConfirmationPromise>) {
|
|||||||
|
|
||||||
impl<D: Dispatcher + 'static> SigningQueueClient<D> {
|
impl<D: Dispatcher + 'static> SigningQueueClient<D> {
|
||||||
/// Creates a new signing queue client given shared signing queue.
|
/// Creates a new signing queue client given shared signing queue.
|
||||||
pub fn new(signer: &Arc<SignerService>, dispatcher: D, accounts: &Arc<AccountProvider>) -> Self {
|
pub fn new(signer: &Arc<SignerService>, dispatcher: D, accounts: &Option<Arc<AccountProvider>>) -> Self {
|
||||||
SigningQueueClient {
|
SigningQueueClient {
|
||||||
signer: Arc::downgrade(signer),
|
signer: Arc::downgrade(signer),
|
||||||
accounts: Arc::downgrade(accounts),
|
accounts: accounts.as_ref().map(Arc::downgrade),
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
pending: Arc::new(Mutex::new(TransientHashMap::new(MAX_PENDING_DURATION_SEC))),
|
pending: Arc::new(Mutex::new(TransientHashMap::new(MAX_PENDING_DURATION_SEC))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn account_provider(&self) -> Result<Arc<AccountProvider>, Error> {
|
||||||
|
unwrap_provider(&self.accounts)
|
||||||
|
}
|
||||||
|
|
||||||
fn dispatch(&self, payload: RpcConfirmationPayload, default_account: DefaultAccount, origin: Origin) -> BoxFuture<DispatchResult, Error> {
|
fn dispatch(&self, payload: RpcConfirmationPayload, default_account: DefaultAccount, origin: Origin) -> BoxFuture<DispatchResult, Error> {
|
||||||
let accounts = take_weakf!(self.accounts);
|
let accounts = try_bf!(self.account_provider());
|
||||||
let default_account = match default_account {
|
let default_account = match default_account {
|
||||||
DefaultAccount::Provided(acc) => acc,
|
DefaultAccount::Provided(acc) => acc,
|
||||||
DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(),
|
DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(),
|
||||||
|
@ -24,6 +24,7 @@ use futures::{future, BoxFuture, Future};
|
|||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use v1::helpers::{errors, DefaultAccount};
|
use v1::helpers::{errors, DefaultAccount};
|
||||||
use v1::helpers::dispatch::{self, Dispatcher};
|
use v1::helpers::dispatch::{self, Dispatcher};
|
||||||
|
use v1::helpers::accounts::unwrap_provider;
|
||||||
use v1::metadata::Metadata;
|
use v1::metadata::Metadata;
|
||||||
use v1::traits::{EthSigning, ParitySigning};
|
use v1::traits::{EthSigning, ParitySigning};
|
||||||
use v1::types::{
|
use v1::types::{
|
||||||
@ -38,21 +39,25 @@ use v1::types::{
|
|||||||
|
|
||||||
/// Implementation of functions that require signing when no trusted signer is used.
|
/// Implementation of functions that require signing when no trusted signer is used.
|
||||||
pub struct SigningUnsafeClient<D> {
|
pub struct SigningUnsafeClient<D> {
|
||||||
accounts: Weak<AccountProvider>,
|
accounts: Option<Weak<AccountProvider>>,
|
||||||
dispatcher: D,
|
dispatcher: D,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Dispatcher + 'static> SigningUnsafeClient<D> {
|
impl<D: Dispatcher + 'static> SigningUnsafeClient<D> {
|
||||||
/// Creates new SigningUnsafeClient.
|
/// Creates new SigningUnsafeClient.
|
||||||
pub fn new(accounts: &Arc<AccountProvider>, dispatcher: D) -> Self {
|
pub fn new(accounts: &Option<Arc<AccountProvider>>, dispatcher: D) -> Self {
|
||||||
SigningUnsafeClient {
|
SigningUnsafeClient {
|
||||||
accounts: Arc::downgrade(accounts),
|
accounts: accounts.as_ref().map(Arc::downgrade),
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn account_provider(&self) -> Result<Arc<AccountProvider>, Error> {
|
||||||
|
unwrap_provider(&self.accounts)
|
||||||
|
}
|
||||||
|
|
||||||
fn handle(&self, payload: RpcConfirmationPayload, account: DefaultAccount) -> BoxFuture<RpcConfirmationResponse, Error> {
|
fn handle(&self, payload: RpcConfirmationPayload, account: DefaultAccount) -> BoxFuture<RpcConfirmationResponse, Error> {
|
||||||
let accounts = take_weakf!(self.accounts);
|
let accounts = try_bf!(self.account_provider());
|
||||||
let default = match account {
|
let default = match account {
|
||||||
DefaultAccount::Provided(acc) => acc,
|
DefaultAccount::Provided(acc) => acc,
|
||||||
DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(),
|
DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(),
|
||||||
|
@ -84,15 +84,16 @@ impl EthTester {
|
|||||||
let client = blockchain_client();
|
let client = blockchain_client();
|
||||||
let sync = sync_provider();
|
let sync = sync_provider();
|
||||||
let ap = accounts_provider();
|
let ap = accounts_provider();
|
||||||
|
let opt_ap = Some(ap.clone());
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let snapshot = snapshot_service();
|
let snapshot = snapshot_service();
|
||||||
let hashrates = Arc::new(Mutex::new(HashMap::new()));
|
let hashrates = Arc::new(Mutex::new(HashMap::new()));
|
||||||
let external_miner = Arc::new(ExternalMiner::new(hashrates.clone()));
|
let external_miner = Arc::new(ExternalMiner::new(hashrates.clone()));
|
||||||
let eth = EthClient::new(&client, &snapshot, &sync, &ap, &miner, &external_miner, options).to_delegate();
|
let eth = EthClient::new(&client, &snapshot, &sync, &opt_ap, &miner, &external_miner, options).to_delegate();
|
||||||
let filter = EthFilterClient::new(&client, &miner).to_delegate();
|
let filter = EthFilterClient::new(&client, &miner).to_delegate();
|
||||||
|
|
||||||
let dispatcher = FullDispatcher::new(Arc::downgrade(&client), Arc::downgrade(&miner));
|
let dispatcher = FullDispatcher::new(Arc::downgrade(&client), Arc::downgrade(&miner));
|
||||||
let sign = SigningUnsafeClient::new(&ap, dispatcher).to_delegate();
|
let sign = SigningUnsafeClient::new(&opt_ap, dispatcher).to_delegate();
|
||||||
let mut io: IoHandler<Metadata> = IoHandler::default();
|
let mut io: IoHandler<Metadata> = IoHandler::default();
|
||||||
io.extend_with(eth);
|
io.extend_with(eth);
|
||||||
io.extend_with(sign);
|
io.extend_with(sign);
|
||||||
|
@ -72,13 +72,15 @@ impl Dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn client(&self, signer: Option<Arc<SignerService>>) -> TestParityClient {
|
pub fn client(&self, signer: Option<Arc<SignerService>>) -> TestParityClient {
|
||||||
|
let opt_accounts = Some(self.accounts.clone());
|
||||||
|
|
||||||
ParityClient::new(
|
ParityClient::new(
|
||||||
&self.client,
|
&self.client,
|
||||||
&self.miner,
|
&self.miner,
|
||||||
&self.sync,
|
&self.sync,
|
||||||
&self.updater,
|
&self.updater,
|
||||||
&self.network,
|
&self.network,
|
||||||
&self.accounts,
|
&opt_accounts,
|
||||||
self.logger.clone(),
|
self.logger.clone(),
|
||||||
self.settings.clone(),
|
self.settings.clone(),
|
||||||
signer,
|
signer,
|
||||||
|
@ -40,7 +40,8 @@ fn accounts_provider_with_vaults_support(temp_path: &str) -> Arc<AccountProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_with_accounts_provider(accounts_provider: Arc<AccountProvider>) -> ParityAccountsTester {
|
fn setup_with_accounts_provider(accounts_provider: Arc<AccountProvider>) -> ParityAccountsTester {
|
||||||
let parity_accounts = ParityAccountsClient::new(&accounts_provider);
|
let opt_ap = Some(accounts_provider.clone());
|
||||||
|
let parity_accounts = ParityAccountsClient::new(&opt_ap);
|
||||||
let mut io = IoHandler::default();
|
let mut io = IoHandler::default();
|
||||||
io.extend_with(parity_accounts.to_delegate());
|
io.extend_with(parity_accounts.to_delegate());
|
||||||
|
|
||||||
|
@ -51,11 +51,12 @@ fn miner_service() -> Arc<TestMinerService> {
|
|||||||
|
|
||||||
fn setup() -> PersonalTester {
|
fn setup() -> PersonalTester {
|
||||||
let accounts = accounts_provider();
|
let accounts = accounts_provider();
|
||||||
|
let opt_accounts = Some(accounts.clone());
|
||||||
let client = blockchain_client();
|
let client = blockchain_client();
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
|
||||||
let dispatcher = FullDispatcher::new(Arc::downgrade(&client), Arc::downgrade(&miner));
|
let dispatcher = FullDispatcher::new(Arc::downgrade(&client), Arc::downgrade(&miner));
|
||||||
let personal = PersonalClient::new(&accounts, dispatcher, false);
|
let personal = PersonalClient::new(&opt_accounts, dispatcher, false);
|
||||||
|
|
||||||
let mut io = IoHandler::default();
|
let mut io = IoHandler::default();
|
||||||
io.extend_with(personal.to_delegate());
|
io.extend_with(personal.to_delegate());
|
||||||
|
@ -57,12 +57,13 @@ fn miner_service() -> Arc<TestMinerService> {
|
|||||||
fn signer_tester() -> SignerTester {
|
fn signer_tester() -> SignerTester {
|
||||||
let signer = Arc::new(SignerService::new_test(None));
|
let signer = Arc::new(SignerService::new_test(None));
|
||||||
let accounts = accounts_provider();
|
let accounts = accounts_provider();
|
||||||
|
let opt_accounts = Some(accounts.clone());
|
||||||
let client = blockchain_client();
|
let client = blockchain_client();
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
|
||||||
let dispatcher = FullDispatcher::new(Arc::downgrade(&client), Arc::downgrade(&miner));
|
let dispatcher = FullDispatcher::new(Arc::downgrade(&client), Arc::downgrade(&miner));
|
||||||
let mut io = IoHandler::default();
|
let mut io = IoHandler::default();
|
||||||
io.extend_with(SignerClient::new(&accounts, dispatcher, &signer).to_delegate());
|
io.extend_with(SignerClient::new(&opt_accounts, dispatcher, &signer).to_delegate());
|
||||||
|
|
||||||
SignerTester {
|
SignerTester {
|
||||||
signer: signer,
|
signer: signer,
|
||||||
|
@ -51,13 +51,14 @@ impl Default for SigningTester {
|
|||||||
let client = Arc::new(TestBlockChainClient::default());
|
let client = Arc::new(TestBlockChainClient::default());
|
||||||
let miner = Arc::new(TestMinerService::default());
|
let miner = Arc::new(TestMinerService::default());
|
||||||
let accounts = Arc::new(AccountProvider::transient_provider());
|
let accounts = Arc::new(AccountProvider::transient_provider());
|
||||||
|
let opt_accounts = Some(accounts.clone());
|
||||||
let mut io = IoHandler::default();
|
let mut io = IoHandler::default();
|
||||||
|
|
||||||
let dispatcher = FullDispatcher::new(Arc::downgrade(&client), Arc::downgrade(&miner));
|
let dispatcher = FullDispatcher::new(Arc::downgrade(&client), Arc::downgrade(&miner));
|
||||||
|
|
||||||
let rpc = SigningQueueClient::new(&signer, dispatcher.clone(), &accounts);
|
let rpc = SigningQueueClient::new(&signer, dispatcher.clone(), &opt_accounts);
|
||||||
io.extend_with(EthSigning::to_delegate(rpc));
|
io.extend_with(EthSigning::to_delegate(rpc));
|
||||||
let rpc = SigningQueueClient::new(&signer, dispatcher, &accounts);
|
let rpc = SigningQueueClient::new(&signer, dispatcher, &opt_accounts);
|
||||||
io.extend_with(ParitySigning::to_delegate(rpc));
|
io.extend_with(ParitySigning::to_delegate(rpc));
|
||||||
|
|
||||||
SigningTester {
|
SigningTester {
|
||||||
|
Loading…
Reference in New Issue
Block a user