Public node WASM, performance and fixes (#5734)
This commit is contained in:
committed by
Arkadiy Paronyan
parent
edea41d35e
commit
b2a42f03eb
@@ -23,7 +23,7 @@ import { Db, Eth, Parity, Net, Personal, Shh, Signer, Trace, Web3 } from './rpc'
|
||||
import Subscriptions from './subscriptions';
|
||||
import util from './util';
|
||||
import { isFunction } from './util/types';
|
||||
// import { LocalAccountsMiddleware } from './local';
|
||||
import { LocalAccountsMiddleware } from './local';
|
||||
|
||||
export default class Api extends EventEmitter {
|
||||
constructor (transport, allowSubscriptions = true) {
|
||||
@@ -54,9 +54,9 @@ export default class Api extends EventEmitter {
|
||||
const middleware = this.parity
|
||||
.nodeKind()
|
||||
.then((nodeKind) => {
|
||||
// if (nodeKind.availability === 'public') {
|
||||
// return LocalAccountsMiddleware;
|
||||
// }
|
||||
if (nodeKind.availability === 'public') {
|
||||
return LocalAccountsMiddleware;
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
import { createKeyObject, decryptPrivateKey } from '../ethkey';
|
||||
|
||||
export default class Account {
|
||||
constructor (persist, data) {
|
||||
constructor (persist, data = {}) {
|
||||
const {
|
||||
keyObject,
|
||||
keyObject = null,
|
||||
meta = {},
|
||||
name = ''
|
||||
} = data;
|
||||
@@ -41,6 +41,15 @@ export default class Account {
|
||||
});
|
||||
}
|
||||
|
||||
export () {
|
||||
const exported = Object.assign({}, this._keyObject);
|
||||
|
||||
exported.meta = JSON.stringify(this._meta);
|
||||
exported.name = this._name;
|
||||
|
||||
return exported;
|
||||
}
|
||||
|
||||
get address () {
|
||||
return `0x${this._keyObject.address.toLowerCase()}`;
|
||||
}
|
||||
@@ -66,6 +75,10 @@ export default class Account {
|
||||
}
|
||||
|
||||
get uuid () {
|
||||
if (!this._keyObject) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._keyObject.id;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,23 +17,74 @@
|
||||
import Account from './account';
|
||||
import localStore from 'store';
|
||||
import { debounce } from 'lodash';
|
||||
import { decryptPrivateKey } from '../ethkey';
|
||||
|
||||
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||
const LS_STORE_KEY = '_parity::localAccounts';
|
||||
|
||||
export default class Accounts {
|
||||
persist = debounce(() => {
|
||||
this._lastState = JSON.stringify(this);
|
||||
|
||||
localStore.set(LS_STORE_KEY, this);
|
||||
}, 100);
|
||||
|
||||
constructor (data = localStore.get(LS_STORE_KEY) || {}) {
|
||||
this._lastState = JSON.stringify(data);
|
||||
|
||||
window.addEventListener('storage', ({ key, newValue }) => {
|
||||
if (key !== LS_STORE_KEY) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue !== this._lastState) {
|
||||
console.log('Data changed in a second tab, syncing state');
|
||||
|
||||
this.restore(JSON.parse(newValue));
|
||||
}
|
||||
});
|
||||
|
||||
this.restore(data);
|
||||
}
|
||||
|
||||
restore (data) {
|
||||
const {
|
||||
last = NULL_ADDRESS,
|
||||
store = []
|
||||
dappsDefault = 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));
|
||||
this._dappsDefaultAddress = dappsDefault;
|
||||
this._store = {};
|
||||
|
||||
if (Array.isArray(store)) {
|
||||
// Recover older version that stored accounts as an array
|
||||
store.forEach((data) => {
|
||||
const account = new Account(this.persist, data);
|
||||
|
||||
this._store[account.address] = account;
|
||||
});
|
||||
} else {
|
||||
Object.keys(store).forEach((key) => {
|
||||
this._store[key] = new Account(this.persist, store[key]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_addAccount = (account) => {
|
||||
const { address } = account;
|
||||
|
||||
if (address in this._store && this._store[address].uuid) {
|
||||
throw new Error(`Account ${address} already exists!`);
|
||||
}
|
||||
|
||||
this._store[address] = account;
|
||||
this.lastAddress = address;
|
||||
|
||||
this.persist();
|
||||
|
||||
return account.address;
|
||||
}
|
||||
|
||||
create (secret, password) {
|
||||
@@ -41,20 +92,19 @@ export default class Accounts {
|
||||
|
||||
return Account
|
||||
.fromPrivateKey(this.persist, privateKey, password)
|
||||
.then((account) => {
|
||||
const { address } = account;
|
||||
.then(this._addAccount);
|
||||
}
|
||||
|
||||
if (this._store.find((account) => account.address === address)) {
|
||||
throw new Error(`Account ${address} already exists!`);
|
||||
restoreFromWallet (wallet, password) {
|
||||
return decryptPrivateKey(wallet, password)
|
||||
.then((privateKey) => {
|
||||
if (!privateKey) {
|
||||
throw new Error('Invalid password');
|
||||
}
|
||||
|
||||
this._store.push(account);
|
||||
this.lastAddress = address;
|
||||
|
||||
this.persist();
|
||||
|
||||
return account.address;
|
||||
});
|
||||
return Account.fromPrivateKey(this.persist, privateKey, password);
|
||||
})
|
||||
.then(this._addAccount);
|
||||
}
|
||||
|
||||
set lastAddress (value) {
|
||||
@@ -65,20 +115,48 @@ export default class Accounts {
|
||||
return this._last;
|
||||
}
|
||||
|
||||
get dappsDefaultAddress () {
|
||||
if (this._dappsDefaultAddress === NULL_ADDRESS) {
|
||||
return this._last;
|
||||
}
|
||||
|
||||
if (this._dappsDefaultAddress in this._store) {
|
||||
return this._dappsDefaultAddress;
|
||||
}
|
||||
|
||||
return NULL_ADDRESS;
|
||||
}
|
||||
|
||||
set dappsDefaultAddress (value) {
|
||||
this._dappsDefaultAddress = value.toLowerCase();
|
||||
}
|
||||
|
||||
get (address) {
|
||||
address = address.toLowerCase();
|
||||
|
||||
this.lastAddress = address;
|
||||
|
||||
const account = this._store.find((account) => account.address === address);
|
||||
const account = this._store[address];
|
||||
|
||||
if (!account) {
|
||||
throw new Error(`Account not found: ${address}`);
|
||||
}
|
||||
|
||||
this.lastAddress = address;
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
getLazyCreate (address) {
|
||||
address = address.toLowerCase();
|
||||
|
||||
this.lastAddress = address;
|
||||
|
||||
if (!(address in this._store)) {
|
||||
this._store[address] = new Account(this.persist);
|
||||
}
|
||||
|
||||
return this._store[address];
|
||||
}
|
||||
|
||||
remove (address, password) {
|
||||
address = address.toLowerCase();
|
||||
|
||||
@@ -108,26 +186,20 @@ export default class Accounts {
|
||||
removeUnsafe (address) {
|
||||
address = address.toLowerCase();
|
||||
|
||||
const index = this._store.findIndex((account) => account.address === address);
|
||||
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._store.splice(index, 1);
|
||||
delete this._store[address];
|
||||
|
||||
this.persist();
|
||||
}
|
||||
|
||||
mapArray (mapper) {
|
||||
return this._store.map(mapper);
|
||||
addresses () {
|
||||
return Object.keys(this._store);
|
||||
}
|
||||
|
||||
mapObject (mapper) {
|
||||
map (mapper) {
|
||||
const result = {};
|
||||
|
||||
this._store.forEach((account) => {
|
||||
result[account.address] = mapper(account);
|
||||
Object.keys(this._store).forEach((key) => {
|
||||
result[key] = mapper(this._store[key]);
|
||||
});
|
||||
|
||||
return result;
|
||||
@@ -136,6 +208,7 @@ export default class Accounts {
|
||||
toJSON () {
|
||||
return {
|
||||
last: this._last,
|
||||
dappsDefault: this._dappsDefaultAddress,
|
||||
store: this._store
|
||||
};
|
||||
}
|
||||
|
||||
147
js/src/api/local/ethkey/ethkey.js
Normal file
147
js/src/api/local/ethkey/ethkey.js
Normal file
@@ -0,0 +1,147 @@
|
||||
// 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/>.
|
||||
|
||||
/* global WebAssembly */
|
||||
|
||||
import wasmBuffer from './ethkey.wasm.js';
|
||||
|
||||
const NOOP = () => {};
|
||||
|
||||
// WASM memory setup
|
||||
const WASM_PAGE_SIZE = 65536;
|
||||
const STATIC_BASE = 1024;
|
||||
const STATICTOP = STATIC_BASE + WASM_PAGE_SIZE * 2;
|
||||
const STACK_BASE = align(STATICTOP + 16);
|
||||
const STACKTOP = STACK_BASE;
|
||||
const TOTAL_STACK = 5 * 1024 * 1024;
|
||||
const TOTAL_MEMORY = 16777216;
|
||||
const STACK_MAX = STACK_BASE + TOTAL_STACK;
|
||||
const DYNAMIC_BASE = STACK_MAX + 64;
|
||||
const DYNAMICTOP_PTR = STACK_MAX;
|
||||
|
||||
function mockWebAssembly () {
|
||||
function throwWasmError () {
|
||||
throw new Error('Missing WebAssembly support');
|
||||
}
|
||||
|
||||
// Simple mock replacement
|
||||
return {
|
||||
Memory: class { buffer = new ArrayBuffer(2048) },
|
||||
Table: class {},
|
||||
Module: class {},
|
||||
Instance: class {
|
||||
exports = {
|
||||
'_input_ptr': () => 0,
|
||||
'_secret_ptr': () => 0,
|
||||
'_public_ptr': () => 0,
|
||||
'_address_ptr': () => 0,
|
||||
'_ecpointg': NOOP,
|
||||
'_brain': throwWasmError,
|
||||
'_verify_secret': throwWasmError
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const { Memory, Table, Module, Instance } = typeof WebAssembly !== 'undefined' ? WebAssembly : mockWebAssembly();
|
||||
|
||||
const wasmMemory = new Memory({
|
||||
initial: TOTAL_MEMORY / WASM_PAGE_SIZE,
|
||||
maximum: TOTAL_MEMORY / WASM_PAGE_SIZE
|
||||
});
|
||||
|
||||
const wasmTable = new Table({
|
||||
initial: 8,
|
||||
maximum: 8,
|
||||
element: 'anyfunc'
|
||||
});
|
||||
|
||||
// TypedArray views into the memory
|
||||
const wasmMemoryU8 = new Uint8Array(wasmMemory.buffer);
|
||||
const wasmMemoryU32 = new Uint32Array(wasmMemory.buffer);
|
||||
|
||||
// Keep DYNAMIC_BASE in memory
|
||||
wasmMemoryU32[DYNAMICTOP_PTR >> 2] = align(DYNAMIC_BASE);
|
||||
|
||||
function align (mem) {
|
||||
const ALIGN_SIZE = 16;
|
||||
|
||||
return (Math.ceil(mem / ALIGN_SIZE) * ALIGN_SIZE) | 0;
|
||||
}
|
||||
|
||||
export function slice (ptr, len) {
|
||||
return wasmMemoryU8.subarray(ptr, ptr + len);
|
||||
}
|
||||
|
||||
// Required by emscripten
|
||||
function abort (what) {
|
||||
throw new Error(what || 'WASM abort');
|
||||
}
|
||||
|
||||
// Required by emscripten
|
||||
function abortOnCannotGrowMemory () {
|
||||
abort(`Cannot enlarge memory arrays.`);
|
||||
}
|
||||
|
||||
// Required by emscripten
|
||||
function enlargeMemory () {
|
||||
abortOnCannotGrowMemory();
|
||||
}
|
||||
|
||||
// Required by emscripten
|
||||
function getTotalMemory () {
|
||||
return TOTAL_MEMORY;
|
||||
}
|
||||
|
||||
// Required by emscripten - used to perform memcpy on large data
|
||||
function memcpy (dest, src, len) {
|
||||
wasmMemoryU8.set(wasmMemoryU8.subarray(src, src + len), dest);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Synchronously compile WASM from the buffer
|
||||
const module = new Module(wasmBuffer);
|
||||
|
||||
// Instantiated WASM module
|
||||
const instance = new Instance(module, {
|
||||
global: {},
|
||||
env: {
|
||||
DYNAMICTOP_PTR,
|
||||
STACKTOP,
|
||||
STACK_MAX,
|
||||
abort,
|
||||
enlargeMemory,
|
||||
getTotalMemory,
|
||||
abortOnCannotGrowMemory,
|
||||
___lock: NOOP,
|
||||
___syscall6: () => 0,
|
||||
___setErrNo: (no) => no,
|
||||
_abort: abort,
|
||||
___syscall140: () => 0,
|
||||
_emscripten_memcpy_big: memcpy,
|
||||
___syscall54: () => 0,
|
||||
___unlock: NOOP,
|
||||
_llvm_trap: abort,
|
||||
___syscall146: () => 0,
|
||||
'memory': wasmMemory,
|
||||
'table': wasmTable,
|
||||
tableBase: 0,
|
||||
memoryBase: STATIC_BASE
|
||||
}
|
||||
});
|
||||
|
||||
export const extern = instance.exports;
|
||||
1
js/src/api/local/ethkey/ethkey.wasm.js
Normal file
1
js/src/api/local/ethkey/ethkey.wasm.js
Normal file
File diff suppressed because one or more lines are too long
@@ -17,13 +17,12 @@
|
||||
import workerPool from './workerPool';
|
||||
|
||||
export function createKeyObject (key, password) {
|
||||
return workerPool.getWorker().action('createKeyObject', { key, password })
|
||||
return workerPool.action('createKeyObject', { key, password })
|
||||
.then((obj) => JSON.parse(obj));
|
||||
}
|
||||
|
||||
export function decryptPrivateKey (keyObject, password) {
|
||||
return workerPool
|
||||
.getWorker()
|
||||
.action('decryptPrivateKey', { keyObject, password })
|
||||
.then((privateKey) => {
|
||||
if (privateKey) {
|
||||
@@ -40,9 +39,9 @@ export function phraseToAddress (phrase) {
|
||||
}
|
||||
|
||||
export function phraseToWallet (phrase) {
|
||||
return workerPool.getWorker().action('phraseToWallet', phrase);
|
||||
return workerPool.action('phraseToWallet', phrase);
|
||||
}
|
||||
|
||||
export function verifySecret (secret) {
|
||||
return workerPool.getWorker().action('verifySecret', secret);
|
||||
return workerPool.action('verifySecret', secret);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
import { randomPhrase } from '@parity/wordlist';
|
||||
import { phraseToAddress, phraseToWallet } from './';
|
||||
|
||||
describe('api/local/ethkey', () => {
|
||||
// TODO: Skipping until Node.js 8.0 comes out and we can test WebAssembly
|
||||
describe.skip('api/local/ethkey', () => {
|
||||
describe('phraseToAddress', function () {
|
||||
this.timeout(30000);
|
||||
|
||||
|
||||
@@ -14,9 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import secp256k1 from 'secp256k1';
|
||||
import { keccak_256 as keccak256 } from 'js-sha3';
|
||||
import { bytesToHex } from '~/api/util/format';
|
||||
import { extern, slice } from './ethkey.js';
|
||||
|
||||
const isWorker = typeof self !== 'undefined';
|
||||
|
||||
@@ -42,43 +41,40 @@ function route ({ action, payload }) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const input = slice(extern._input_ptr(), 1024);
|
||||
const secret = slice(extern._secret_ptr(), 32);
|
||||
const publicKey = slice(extern._public_ptr(), 64);
|
||||
const address = slice(extern._address_ptr(), 20);
|
||||
|
||||
extern._ecpointg();
|
||||
|
||||
const actions = {
|
||||
phraseToWallet (phrase) {
|
||||
let secret = keccak256.array(phrase);
|
||||
const phraseUtf8 = Buffer.from(phrase, 'utf8');
|
||||
|
||||
for (let i = 0; i < 16384; i++) {
|
||||
secret = keccak256.array(secret);
|
||||
if (phraseUtf8.length > input.length) {
|
||||
throw new Error('Phrase is too long!');
|
||||
}
|
||||
|
||||
while (true) {
|
||||
secret = keccak256.array(secret);
|
||||
input.set(phraseUtf8);
|
||||
|
||||
const secretBuf = Buffer.from(secret);
|
||||
extern._brain(phraseUtf8.length);
|
||||
|
||||
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);
|
||||
const wallet = {
|
||||
secret: bytesToHex(secret),
|
||||
public: bytesToHex(publicKey),
|
||||
address: bytesToHex(address)
|
||||
};
|
||||
|
||||
if (address[0] !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const wallet = {
|
||||
secret: bytesToHex(secretBuf),
|
||||
public: bytesToHex(publicBuf),
|
||||
address: bytesToHex(address)
|
||||
};
|
||||
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
return wallet;
|
||||
},
|
||||
|
||||
verifySecret (secret) {
|
||||
const key = Buffer.from(secret.slice(2), 'hex');
|
||||
verifySecret (key) {
|
||||
const keyBuf = Buffer.from(key.slice(2), 'hex');
|
||||
|
||||
return secp256k1.privateKeyVerify(key);
|
||||
secret.set(keyBuf);
|
||||
|
||||
return extern._verify_secret();
|
||||
},
|
||||
|
||||
createKeyObject ({ key, password }) {
|
||||
@@ -112,7 +108,8 @@ self.onmessage = function ({ data }) {
|
||||
|
||||
postMessage([null, result]);
|
||||
} catch (err) {
|
||||
postMessage([err, null]);
|
||||
console.error(err);
|
||||
postMessage([err.toString(), null]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ class WorkerContainer {
|
||||
this.busy = false;
|
||||
|
||||
if (err) {
|
||||
reject(err);
|
||||
// `err` ought to be a String
|
||||
reject(new Error(err));
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
@@ -48,20 +49,56 @@ class WorkerContainer {
|
||||
}
|
||||
|
||||
class WorkerPool {
|
||||
pool = [];
|
||||
pool = [
|
||||
new WorkerContainer(),
|
||||
new WorkerContainer()
|
||||
];
|
||||
|
||||
getWorker () {
|
||||
queue = [];
|
||||
|
||||
_getContainer () {
|
||||
return this.pool.find((container) => !container.busy);
|
||||
}
|
||||
|
||||
action (action, payload) {
|
||||
let container = this.pool.find((container) => !container.busy);
|
||||
|
||||
let promise;
|
||||
|
||||
// const start = Date.now();
|
||||
|
||||
if (container) {
|
||||
return container;
|
||||
promise = container.action(action, payload);
|
||||
} else {
|
||||
promise = new Promise((resolve, reject) => {
|
||||
this.queue.push([action, payload, resolve]);
|
||||
});
|
||||
}
|
||||
|
||||
container = new WorkerContainer();
|
||||
return promise
|
||||
.catch((err) => {
|
||||
this.processQueue();
|
||||
|
||||
this.pool.push(container);
|
||||
throw err;
|
||||
})
|
||||
.then((result) => {
|
||||
this.processQueue();
|
||||
|
||||
return container;
|
||||
// console.log('Work done in ', Date.now() - start);
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
processQueue () {
|
||||
let container = this._getContainer();
|
||||
|
||||
while (container && this.queue.length > 0) {
|
||||
const [action, payload, resolve] = this.queue.shift();
|
||||
|
||||
resolve(container.action(action, payload));
|
||||
container = this._getContainer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class LocalAccountsMiddleware extends Middleware {
|
||||
const register = this.register.bind(this);
|
||||
|
||||
register('eth_accounts', () => {
|
||||
return accounts.mapArray((account) => account.address);
|
||||
return accounts.addresses();
|
||||
});
|
||||
|
||||
register('eth_coinbase', () => {
|
||||
@@ -37,13 +37,13 @@ export default class LocalAccountsMiddleware extends Middleware {
|
||||
});
|
||||
|
||||
register('parity_accountsInfo', () => {
|
||||
return accounts.mapObject(({ name }) => {
|
||||
return accounts.map(({ name }) => {
|
||||
return { name };
|
||||
});
|
||||
});
|
||||
|
||||
register('parity_allAccountsInfo', () => {
|
||||
return accounts.mapObject(({ name, meta, uuid }) => {
|
||||
return accounts.map(({ name, meta, uuid }) => {
|
||||
return { name, meta, uuid };
|
||||
});
|
||||
});
|
||||
@@ -68,10 +68,31 @@ export default class LocalAccountsMiddleware extends Middleware {
|
||||
return transactions.hash(id) || Promise.resolve(null);
|
||||
});
|
||||
|
||||
register('parity_dappsList', () => {
|
||||
return [];
|
||||
});
|
||||
|
||||
register('parity_defaultAccount', () => {
|
||||
return accounts.lastAddress;
|
||||
});
|
||||
|
||||
register('parity_exportAccount', ([address, password]) => {
|
||||
const account = accounts.get(address);
|
||||
|
||||
if (!password) {
|
||||
password = '';
|
||||
}
|
||||
|
||||
return account.isValidPassword(password)
|
||||
.then((isValid) => {
|
||||
if (!isValid) {
|
||||
throw new Error('Invalid password');
|
||||
}
|
||||
|
||||
return account.export();
|
||||
});
|
||||
});
|
||||
|
||||
register('parity_generateSecretPhrase', () => {
|
||||
return randomPhrase(12);
|
||||
});
|
||||
@@ -80,6 +101,10 @@ export default class LocalAccountsMiddleware extends Middleware {
|
||||
return [];
|
||||
});
|
||||
|
||||
register('parity_getNewDappsDefaultAddress', () => {
|
||||
return accounts.lastAddress;
|
||||
});
|
||||
|
||||
register('parity_hardwareAccountsInfo', () => {
|
||||
return {};
|
||||
});
|
||||
@@ -102,18 +127,30 @@ export default class LocalAccountsMiddleware extends Middleware {
|
||||
});
|
||||
});
|
||||
|
||||
register('parity_newAccountFromWallet', ([json, password]) => {
|
||||
if (!password) {
|
||||
password = '';
|
||||
}
|
||||
|
||||
return accounts.restoreFromWallet(JSON.parse(json), password);
|
||||
});
|
||||
|
||||
register('parity_setAccountMeta', ([address, meta]) => {
|
||||
accounts.get(address).meta = meta;
|
||||
accounts.getLazyCreate(address).meta = meta;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
register('parity_setAccountName', ([address, name]) => {
|
||||
accounts.get(address).name = name;
|
||||
accounts.getLazyCreate(address).name = name;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
register('parity_setNewDappsDefaultAddress', ([address]) => {
|
||||
accounts.dappsDefaultAddress = address;
|
||||
});
|
||||
|
||||
register('parity_postTransaction', ([tx]) => {
|
||||
if (!tx.from) {
|
||||
tx.from = accounts.lastAddress;
|
||||
@@ -137,10 +174,32 @@ export default class LocalAccountsMiddleware extends Middleware {
|
||||
return [];
|
||||
});
|
||||
|
||||
register('parity_listOpenedVaults', () => {
|
||||
return [];
|
||||
});
|
||||
|
||||
register('parity_listRecentDapps', () => {
|
||||
return {};
|
||||
});
|
||||
|
||||
register('parity_listVaults', () => {
|
||||
return [];
|
||||
});
|
||||
|
||||
register('parity_wsUrl', () => {
|
||||
// This is a hack, will be replaced by a `hostname` setting on the node itself
|
||||
return `${window.location.hostname}:8546`;
|
||||
});
|
||||
|
||||
register('parity_dappsUrl', () => {
|
||||
// This is a hack, will be replaced by a `hostname` setting on the node itself
|
||||
return `${window.location.hostname}:8545`;
|
||||
});
|
||||
|
||||
register('parity_hashContent', () => {
|
||||
throw new Error('Functionality unavailable on a public wallet.');
|
||||
});
|
||||
|
||||
register('parity_killAccount', ([address, password]) => {
|
||||
return accounts.remove(address, password);
|
||||
});
|
||||
@@ -204,6 +263,10 @@ export default class LocalAccountsMiddleware extends Middleware {
|
||||
});
|
||||
});
|
||||
|
||||
register('signer_generateAuthorizationToken', () => {
|
||||
return '';
|
||||
});
|
||||
|
||||
register('signer_rejectRequest', ([id]) => {
|
||||
return transactions.reject(id);
|
||||
});
|
||||
|
||||
@@ -71,7 +71,9 @@ describe('api/local/LocalAccountsMiddleware', function () {
|
||||
'parity_phraseToAddress',
|
||||
'parity_useLocalAccounts',
|
||||
'parity_listGethAccounts',
|
||||
'parity_listOpenedVaults',
|
||||
'parity_listRecentDapps',
|
||||
'parity_listVaults',
|
||||
'parity_killAccount',
|
||||
'parity_testPassword',
|
||||
'signer_confirmRequest',
|
||||
|
||||
Reference in New Issue
Block a user