Emulate signer pubsub on public node

This commit is contained in:
maciejhirsz 2017-10-11 16:21:44 +02:00
parent 0bb845a05c
commit 0c86357187
8 changed files with 107 additions and 29 deletions

View File

@ -47,13 +47,6 @@ export default class Api extends EventEmitter {
this._trace = new Trace(transport); this._trace = new Trace(transport);
this._web3 = new Web3(transport); this._web3 = new Web3(transport);
if (isFunction(transport.subscribe)) {
this._pubsub = new Pubsub(transport);
}
if (allowSubscriptions) {
this._subscriptions = new Subscriptions(this);
}
// Doing a request here in test env would cause an error // Doing a request here in test env would cause an error
if (LocalAccountsMiddleware && process.env.NODE_ENV !== 'test') { if (LocalAccountsMiddleware && process.env.NODE_ENV !== 'test') {
const middleware = this.parity const middleware = this.parity
@ -69,6 +62,14 @@ export default class Api extends EventEmitter {
transport.addMiddleware(middleware); transport.addMiddleware(middleware);
} }
if (isFunction(transport.subscribe)) {
this._pubsub = new Pubsub(transport);
}
if (allowSubscriptions) {
this._subscriptions = new Subscriptions(this);
}
} }
get isPubSub () { get isPubSub () {

View File

@ -18,11 +18,12 @@ import Account from './account';
import localStore from 'store'; import localStore from 'store';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { decryptPrivateKey } from '../ethkey'; import { decryptPrivateKey } from '../ethkey';
import EventEmitter from 'eventemitter3';
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
const LS_STORE_KEY = '_parity::localAccounts'; const LS_STORE_KEY = '_parity::localAccounts';
export default class Accounts { export default class Accounts extends EventEmitter {
persist = debounce(() => { persist = debounce(() => {
this._lastState = JSON.stringify(this); this._lastState = JSON.stringify(this);
@ -30,6 +31,8 @@ export default class Accounts {
}, 100); }, 100);
constructor (data = localStore.get(LS_STORE_KEY) || {}) { constructor (data = localStore.get(LS_STORE_KEY) || {}) {
super();
this._lastState = JSON.stringify(data); this._lastState = JSON.stringify(data);
window.addEventListener('storage', ({ key, newValue }) => { window.addEventListener('storage', ({ key, newValue }) => {
@ -130,6 +133,8 @@ export default class Accounts {
set dappsDefaultAddress (value) { set dappsDefaultAddress (value) {
this._dappsDefaultAddress = value.toLowerCase(); this._dappsDefaultAddress = value.toLowerCase();
this.emit('dappsDefaultAddressChange', this._dappsDefaultAddress);
this.persist(); this.persist();
} }

View File

@ -26,7 +26,9 @@ export default class LocalAccountsMiddleware extends Middleware {
constructor (transport) { constructor (transport) {
super(transport); super(transport);
const NOOP = () => {};
const register = this.register.bind(this); const register = this.register.bind(this);
const registerSubscribe = this.registerSubscribe.bind(this);
register('eth_accounts', () => { register('eth_accounts', () => {
return accounts.accountAddresses(); return accounts.accountAddresses();
@ -76,6 +78,14 @@ export default class LocalAccountsMiddleware extends Middleware {
return accounts.dappsDefaultAddress; return accounts.dappsDefaultAddress;
}); });
registerSubscribe('parity_defaultAccount', (_, callback) => {
callback(null, accounts.dappsDefaultAddress);
accounts.on('dappsDefaultAddressChange', (address) => {
callback(null, accounts.dappsDefaultAddress);
});
});
register('parity_exportAccount', ([address, password]) => { register('parity_exportAccount', ([address, password]) => {
const account = accounts.get(address); const account = accounts.get(address);
@ -109,6 +119,8 @@ export default class LocalAccountsMiddleware extends Middleware {
return {}; return {};
}); });
registerSubscribe('parity_hardwareAccountsInfo', NOOP);
register('parity_newAccountFromPhrase', ([phrase, password]) => { register('parity_newAccountFromPhrase', ([phrase, password]) => {
return phraseToWallet(phrase) return phraseToWallet(phrase)
.then((wallet) => { .then((wallet) => {
@ -278,5 +290,15 @@ export default class LocalAccountsMiddleware extends Middleware {
register('signer_requestsToConfirm', () => { register('signer_requestsToConfirm', () => {
return transactions.requestsToConfirm(); return transactions.requestsToConfirm();
}); });
registerSubscribe('signer_subscribePending', (_, callback) => {
callback(null, transactions.requestsToConfirm());
transactions.on('update', () => {
callback(null, transactions.requestsToConfirm());
});
return false;
});
} }
} }

View File

@ -16,14 +16,17 @@
import { toHex } from '../util/format'; import { toHex } from '../util/format';
import { TransportError } from '../transport'; import { TransportError } from '../transport';
import EventEmitter from 'eventemitter3';
const AWAITING = Symbol('awaiting'); const AWAITING = Symbol('awaiting');
const LOCKED = Symbol('locked'); const LOCKED = Symbol('locked');
const CONFIRMED = Symbol('confirmed'); const CONFIRMED = Symbol('confirmed');
const REJECTED = Symbol('rejected'); const REJECTED = Symbol('rejected');
class Transactions { class Transactions extends EventEmitter {
constructor () { constructor () {
super();
this.reset(); this.reset();
} }
@ -45,6 +48,8 @@ class Transactions {
transaction: tx transaction: tx
}; };
this.emit('update');
return id; return id;
} }
@ -66,6 +71,8 @@ class Transactions {
} }
state.status = LOCKED; state.status = LOCKED;
this.emit('update');
} }
unlock (id) { unlock (id) {
@ -76,6 +83,8 @@ class Transactions {
} }
state.status = AWAITING; state.status = AWAITING;
this.emit('update');
} }
hash (id) { hash (id) {
@ -107,6 +116,8 @@ class Transactions {
state.hash = hash; state.hash = hash;
state.status = CONFIRMED; state.status = CONFIRMED;
this.emit('update');
} }
reject (id) { reject (id) {
@ -118,6 +129,8 @@ class Transactions {
state.status = REJECTED; state.status = REJECTED;
this.emit('update');
return true; return true;
} }

View File

@ -17,7 +17,7 @@ import PubsubBase from '../pubsubBase';
import { outSignerRequest } from '../../format/output'; import { outSignerRequest } from '../../format/output';
export default class Net extends PubsubBase { export default class Signer extends PubsubBase {
constructor (transport) { constructor (transport) {
super(transport); super(transport);
this._api = { this._api = {

View File

@ -38,6 +38,11 @@ export default class Signer {
start () { start () {
this._started = true; this._started = true;
return this
._api
.transport
.ready
.then(() => {
if (this._api.isPubSub) { if (this._api.isPubSub) {
const subscription = this._api.pubsub const subscription = this._api.pubsub
.subscribeAndGetResult( .subscribeAndGetResult(
@ -58,6 +63,7 @@ export default class Signer {
this._listRequests(true), this._listRequests(true),
this._loggingSubscribe() this._loggingSubscribe()
]); ]);
});
} }
updateSubscriptions (requests) { updateSubscriptions (requests) {

View File

@ -31,6 +31,10 @@ export default class JsonRpcBase extends EventEmitter {
this._middlewareList = Promise.resolve([]); this._middlewareList = Promise.resolve([]);
} }
get ready () {
return this._middlewareList.then(() => true);
}
encode (method, params) { encode (method, params) {
const json = JSON.stringify({ const json = JSON.stringify({
jsonrpc: '2.0', jsonrpc: '2.0',

View File

@ -17,7 +17,20 @@
export default class Middleware { export default class Middleware {
constructor (transport) { constructor (transport) {
this._transport = transport; this._transport = transport;
this._subscribe = transport.subscribe;
transport.subscribe = this.handleSubscribe.bind(this);
this._handlers = {}; this._handlers = {};
this._subHandlers = {};
}
registerSubscribe (method, handler) {
if (method in this._subHandlers) {
throw new Error(`${method} is already defined in the middleware!`);
}
this._subHandlers[method] = handler;
} }
register (method, handler) { register (method, handler) {
@ -28,10 +41,24 @@ export default class Middleware {
this._handlers[method] = handler; this._handlers[method] = handler;
} }
handleSubscribe (api, callback, event) {
// Don't ask
const method = api.subscribe ? api.subscribe : event[0];
const params = event.length === 2 ? event[1] : event;
const handler = this._subHandlers[method];
if (handler) {
return handler(params, callback);
}
this._subscribe.call(this._transport, api, callback, event);
}
handle (method, params) { handle (method, params) {
const handler = this._handlers[method]; const handler = this._handlers[method];
if (handler != null) { if (handler) {
return handler(params); return handler(params);
} }