-
Notifications
You must be signed in to change notification settings - Fork 973
Eth-wallet rebased #14734
Eth-wallet rebased #14734
Changes from all commits
2f69e74
b4ab64b
73c7dbf
899eb72
745ceb8
8160f1f
26dc7c3
95b7170
d489a61
9670596
d41a694
2850d0f
caa4f6b
98fd603
e034b88
60052a8
e8134ef
368a93c
6958d7f
176fc16
5b465ea
c0bb60b
e0ed506
bf5f32e
0dd0297
028797c
ed26efa
d983edb
aa43cfe
ea5ace9
41ecbc5
a762df9
b7d2d79
80fe5db
1831fd3
8cb854d
86f2c46
28063f6
27f3fe0
7ca66e9
3fe408d
abdce2b
c0f022b
478f3eb
b89c75c
2c1c273
62742b2
4bf783a
36e35cf
1727b62
b41f485
cfb127c
7b29237
e795bb4
c781c47
c4e75a1
bf0a030
9c9c76a
6dde942
1b40d47
fa4552c
9360fc5
2c49e26
3e9029f
8481776
812663f
b86d9c4
5168abd
13431f6
ea63f3c
3081293
81b2ff6
87bb9e0
9db01a0
789557c
a24c748
467722a
3a27ad1
d6511eb
585dd5f
fe5f692
4779310
3fbdbd5
ac7b1bc
537b436
91b7680
e4e1bac
c76812a
c623dd5
be48f37
b36ab69
989a6c2
64f6897
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
'use strict' | ||
|
||
const settings = require('../../../js/constants/settings') | ||
const {configureEthWallet} = require('../../extensions') | ||
const appConstants = require('../../../js/constants/appConstants') | ||
const {makeImmutable} = require('../../common/state/immutableUtil') | ||
|
||
const ethWalletReducer = (state, action, immutableAction) => { | ||
action = immutableAction || makeImmutable(action) | ||
|
||
switch (action.get('actionType')) { | ||
case appConstants.APP_CHANGE_SETTING: | ||
{ | ||
const key = action.get('key') | ||
const isEnabled = action.get('value') | ||
|
||
if (isEnabled == null || key !== settings.ETHWALLET_ENABLED) { | ||
break | ||
} | ||
|
||
configureEthWallet(isEnabled) | ||
break | ||
} | ||
} | ||
return state | ||
} | ||
|
||
module.exports = ethWalletReducer |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,303 @@ | ||
const fs = require('fs-extra') | ||
const path = require('path') | ||
const dns = require('dns-then') | ||
const {spawn, spawnSync} = require('child_process') | ||
const portfinder = require('portfinder') | ||
const net = require('net') | ||
const underscore = require('underscore') | ||
|
||
const {app, ipcMain} = require('electron') | ||
const {getExtensionsPath} = require('../js/lib/appUrlUtil') | ||
const appStore = require('../js/stores/appStore') | ||
const ledgerState = require('./common/state/ledgerState') | ||
const {getSetting} = require('../js/settings') | ||
const settings = require('../js/constants/settings') | ||
const appDispatcher = require('../js/dispatcher/appDispatcher') | ||
const appConstants = require('../js/constants/appConstants') | ||
|
||
const gethCache = process.env.GETH_CACHE || '1024' | ||
const envNet = process.env.ETHEREUM_NETWORK || 'mainnet' | ||
const envSubDomain = envNet === 'mainnet' ? 'ethwallet' : 'ethwallet-test' | ||
const gethDataDir = path.join(app.getPath('userData'), 'ethereum', envNet) | ||
|
||
const isWindows = process.platform === 'win32' | ||
const gethProcessKey = isWindows ? 'geth.exe' : 'geth' | ||
|
||
const ipcPath = isWindows ? '\\\\.\\pipe\\geth.ipc' : path.join(gethDataDir, 'geth.ipc') | ||
const pidPath = isWindows ? '\\\\.\\pipe\\geth.pid' : path.join(gethDataDir, 'geth.pid') | ||
const gethProcessPath = path.join(getExtensionsPath('bin'), gethProcessKey) | ||
|
||
const configurePeers = async (dataDir) => { | ||
try { | ||
const discoveryDomain = `_enode._tcp.${envNet}.${envSubDomain}.brave.com` | ||
let newNodes = await dns.resolveSrv(discoveryDomain) | ||
newNodes = underscore.shuffle(newNodes).sort((a, b) => { | ||
const pdiff = a.priority - b.priority | ||
|
||
return ((pdiff !== 0) ? pdiff : (b.weight - a.weight)) | ||
}) | ||
const newNodesNames = newNodes.map(({ name }) => name) | ||
|
||
// start without await to take advantage of async parallelism | ||
const newNodesPublicKeysPromises = Promise.all(newNodesNames.map(name => dns.resolveTxt(name))) | ||
const newNodesIps = await Promise.all(newNodesNames.map(name => dns.resolve4(name))) | ||
const newNodesPublicKeys = await newNodesPublicKeysPromises | ||
|
||
const enodes = newNodes.map(({name, port}, i) => `enode://${newNodesPublicKeys[i]}@${newNodesIps[i]}:${port}`) | ||
|
||
await fs.writeFile(path.join(dataDir, 'geth', 'static-nodes.json'), JSON.stringify(enodes)) | ||
} catch (e) { | ||
console.error('Failed to configure static nodes peers ' + e.message) | ||
} | ||
} | ||
|
||
// needs to be shared to the eth-wallet app over ipc | ||
let wsPort | ||
// needs to be shared to the metamask extension | ||
let rpcPort | ||
|
||
let geth | ||
let gethProcessId | ||
let gethRetryTimeoutId | ||
const gethRetryInterval = 30000 | ||
|
||
const spawnGeth = async () => { | ||
portfinder.basePort = 40400 | ||
const port = await portfinder.getPortPromise() | ||
|
||
portfinder.basePort = 40600 | ||
wsPort = await portfinder.getPortPromise() | ||
|
||
portfinder.basePort = 40800 | ||
rpcPort = await portfinder.getPortPromise() | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do either the RPC or websocket ports accept connections from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the solution is to have the listening service validate the incoming request's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would setting the following options be sufficient?
We should set these after we get more concrete metamask integration? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Slava CORS is unrelated. the latter looks like it should do the right thing but i haven't audited the code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah that flag only applies to HTTP-RPC. the Geth WS-RPC doesn't actually have a way to enforce checks on the Host header. but it looks like there are no additional whitelisted origins (for WS-RPC) added beyond those passed via so I think we are okay as we continue to pass |
||
const gethArgs = [ | ||
'--port', | ||
port, | ||
'--syncmode', | ||
'light', | ||
'--cache', | ||
gethCache, | ||
'--cache.database', | ||
gethCache, | ||
'--trie-cache-gens', | ||
gethCache, | ||
'--rpc', | ||
'--rpcport', | ||
rpcPort, | ||
'--ws', | ||
'--wsorigins', | ||
'chrome-extension://dakeiobolocmlkdebloniehpglcjkgcp', | ||
'--wsport', | ||
wsPort, | ||
'--datadir', | ||
gethDataDir, | ||
'--ipcpath', | ||
ipcPath, | ||
'--maxpeers', | ||
'10' | ||
] | ||
|
||
if (envNet === 'ropsten') { | ||
gethArgs.push('--testnet') | ||
gethArgs.push('--rpcapi', 'admin,eth,web3') | ||
} | ||
|
||
const gethOptions = { | ||
stdio: process.env.GETH_LOG ? 'inherit' : 'ignore' | ||
} | ||
|
||
ensureGethDataDir() | ||
|
||
// If the process from the previous browswer session still lingers, it should be killed | ||
if (await fs.pathExists(pidPath)) { | ||
try { | ||
const pid = await fs.readFile(pidPath) | ||
cleanupGeth(pid) | ||
} catch (ex) { | ||
console.error('Could not read from geth.pid') | ||
} | ||
} | ||
|
||
geth = spawn(gethProcessPath, gethArgs, gethOptions) | ||
|
||
geth.on('exit', handleGethStop.bind(null, 'exit')) | ||
geth.on('close', handleGethStop.bind(null, 'close')) | ||
|
||
await writeGethPid(geth.pid) | ||
|
||
console.warn('GETH: spawned') | ||
} | ||
|
||
const ensureGethDataDir = () => { | ||
if (!isWindows) { | ||
fs.ensureDirSync(gethDataDir) | ||
} else { | ||
spawnSync('mkdir', ['-p', gethDataDir]) | ||
} | ||
configurePeers(gethDataDir) | ||
} | ||
|
||
const handleGethStop = (event, code, signal) => { | ||
console.warn(`GETH ${event}: Code: ${code} | Signal: ${signal}`) | ||
|
||
if (code) { | ||
return | ||
} | ||
|
||
const isEnabled = getSetting(settings.ETHWALLET_ENABLED) | ||
// Restart should occur on close only, else restart | ||
// events can compound. | ||
if (event === 'exit') { | ||
geth = null | ||
} else if (isEnabled && event === 'close') { | ||
restartGeth() | ||
} | ||
} | ||
|
||
const writeGethPid = async (pid) => { | ||
if (!pid) { | ||
return | ||
} | ||
|
||
gethProcessId = pid | ||
|
||
try { | ||
await fs.writeFile(pidPath, gethProcessId) | ||
} catch (ex) { | ||
console.error('Could not write geth.pid') | ||
} | ||
} | ||
|
||
const cleanupGeth = (processId) => { | ||
processId = processId || gethProcessId | ||
|
||
if (processId) { | ||
// Set geth to null to remove bound listeners | ||
// Otherwise, geth will attempt to restart itself | ||
// when killed. | ||
geth = null | ||
|
||
// Kill process | ||
process.kill(processId) | ||
|
||
// Remove in memory process id | ||
gethProcessId = null | ||
|
||
// Named pipes on Windows will get deleted | ||
// automatically once no processes are using them. | ||
if (!isWindows) { | ||
try { | ||
fs.unlinkSync(pidPath) | ||
} catch (ex) { | ||
console.error('Could not delete geth.pid') | ||
} | ||
} | ||
console.warn('GETH: cleanup done') | ||
} | ||
} | ||
|
||
// Attempts to restart geth up to 3 times | ||
const restartGeth = async (tries = 3) => { | ||
if (tries === 0) { | ||
return | ||
} | ||
|
||
await spawnGeth() | ||
|
||
if (gethRetryTimeoutId) { | ||
clearTimeout(gethRetryTimeoutId) | ||
} | ||
|
||
if (geth == null) { | ||
gethRetryTimeoutId = setTimeout(() => { restartGeth(--tries) }, gethRetryInterval) | ||
} | ||
} | ||
|
||
// Geth should be killed on normal process, exit, SIGINT, | ||
// and application crashing exceptions. | ||
process.on('exit', () => { | ||
cleanupGeth(gethProcessId) | ||
}) | ||
process.on('SIGINT', () => { | ||
cleanupGeth(gethProcessId) | ||
process.exit(2) | ||
}) | ||
|
||
ipcMain.on('eth-wallet-create-wallet', (e, pwd) => { | ||
const client = net.createConnection(ipcPath) | ||
|
||
client.on('connect', () => { | ||
client.write(JSON.stringify({ 'method': 'personal_newAccount', 'params': [pwd], 'id': 1, 'jsonrpc': '2.0' })) | ||
}) | ||
|
||
client.on('data', (data) => { | ||
const res = JSON.parse(data.toString()) | ||
if (res.result) { | ||
e.sender.send('eth-wallet-new-wallet', res.result) | ||
} | ||
client.end() | ||
}) | ||
}) | ||
|
||
ipcMain.on('eth-wallet-wallets', (e, data) => { | ||
const client = net.createConnection(ipcPath) | ||
|
||
client.on('connect', () => { | ||
client.write(JSON.stringify({ 'method': 'db_putString', 'params': ['braveEthWallet', 'wallets', data], 'id': 1, 'jsonrpc': '2.0' })) | ||
}) | ||
|
||
client.on('data', (data) => { | ||
client.end() | ||
}) | ||
}) | ||
|
||
ipcMain.on('eth-wallet-unlock-account', (e, address, pw) => { | ||
const client = net.createConnection(ipcPath) | ||
|
||
client.on('connect', () => { | ||
client.write(JSON.stringify({ 'method': 'personal_unlockAccount', 'params': [address, pw], 'id': 1, 'jsonrpc': '2.0' })) | ||
}) | ||
|
||
client.on('data', (data) => { | ||
client.end() | ||
e.sender.send('eth-wallet-unlock-account-result', data.toString()) | ||
}) | ||
}) | ||
|
||
ipcMain.on('eth-wallet-get-geth-address', (e) => { | ||
e.sender.send('eth-wallet-geth-address', `ws://localhost:${wsPort}`) | ||
}) | ||
|
||
ipcMain.on('get-popup-bat-balance', (e) => { | ||
const appState = appStore.getState() | ||
const ledgerInfo = ledgerState.getInfoProps(appState) | ||
e.sender.send('popup-bat-balance', | ||
ledgerInfo.get('balance'), | ||
ledgerInfo.getIn(['addresses', 'BAT'])) | ||
}) | ||
|
||
ipcMain.on('eth-wallet-get-metamask-state', (e) => { | ||
e.sender.send('eth-wallet-metamask-state', getSetting(settings.METAMASK_ENABLED) ? 'enabled' : 'disabled') | ||
}) | ||
|
||
ipcMain.on('eth-wallet-enable-metamask', (e) => { | ||
appDispatcher.dispatch({ | ||
actionType: appConstants.APP_CHANGE_SETTING, | ||
key: settings.METAMASK_ENABLED, | ||
value: true | ||
}) | ||
}) | ||
|
||
ipcMain.on('eth-wallet-get-keys-path', (e) => { | ||
e.sender.send('eth-wallet-keys-path', path.join(gethDataDir, 'keystore')) | ||
}) | ||
|
||
const launchGeth = async function () { | ||
await spawnGeth() | ||
} | ||
|
||
module.exports = { | ||
launchGeth, | ||
cleanupGeth | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Slava is this block supposed to be here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this is needed. Maybe you can remember the context of this commit? c375ba3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Slava lol wow i have no idea. sorry i thought it was left over from the rebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
er yeah this needs to - looks like a rebase issue from before -> after the signle-webview project. Tab's now
detach
every time they are made inactive / active, so this will break something (minor).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petemill sorry do you mean this chunk should be deleted or kept (or other)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petemill ping
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like this block got added during rebase because of a fix within in the original ethwallet branch - 00cdfdd#diff-2be38b3d97f35cd818780bac4be979c4R629
I think we should delete this block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops missed out a key word
Thanks for the spot