Browse Source

Merge remote-tracking branch 'origin/master' into fix

snyk-fix-84644e4a03e171e392ba652f3dc364b5
Overtorment 5 years ago
parent
commit
23b74666a4
  1. 31
      BlueElectrum.js
  2. 1
      class/app-storage.js
  3. 97
      package-lock.json
  4. 2
      package.json
  5. 36
      screen/settings/electrumSettings.js
  6. 4
      shim.js
  7. 44
      tests/integration/BlueElectrum.test.js
  8. 55
      tests/integration/ElectrumClient.test.js
  9. 1
      tests/integration/HDWallet.test.js
  10. 1
      tests/integration/LegacyWallet.test.js
  11. 1
      tests/integration/WatchOnlyWallet.test.js
  12. 1
      tests/integration/hd-segwit-bech32-transaction.test.js
  13. 1
      tests/integration/hd-segwit-bech32-wallet.test.js

31
BlueElectrum.js

@ -6,7 +6,7 @@ let reverse = require('buffer-reverse');
let BigNumber = require('bignumber.js');
const storageKey = 'ELECTRUM_PEERS';
const defaultPeer = { host: 'electrum1.bluewallet.io', tcp: '50001' };
const defaultPeer = { host: 'electrum1.bluewallet.io', ssl: '443' };
const hardcodedPeers = [
// { host: 'noveltybobble.coinjoined.com', tcp: '50001' }, // down
// { host: 'electrum.be', tcp: '50001' },
@ -16,27 +16,27 @@ const hardcodedPeers = [
// { host: 'Bitkoins.nl', tcp: '50001' }, // down
// { host: 'fullnode.coinkite.com', tcp: '50001' },
// { host: 'preperfect.eleCTruMioUS.com', tcp: '50001' }, // down
{ host: 'electrum1.bluewallet.io', tcp: '50001' },
{ host: 'electrum1.bluewallet.io', tcp: '50001' }, // 2x weight
{ host: 'electrum2.bluewallet.io', tcp: '50001' },
{ host: 'electrum3.bluewallet.io', tcp: '50001' },
{ host: 'electrum3.bluewallet.io', tcp: '50001' }, // 2x weight
{ host: 'electrum1.bluewallet.io', ssl: '443' },
{ host: 'electrum1.bluewallet.io', ssl: '443' }, // 2x weight
{ host: 'electrum2.bluewallet.io', ssl: '443' },
{ host: 'electrum3.bluewallet.io', ssl: '443' },
{ host: 'electrum3.bluewallet.io', ssl: '443' }, // 2x weight
];
let mainClient = false;
let mainClient: ElectrumClient = false;
let mainConnected = false;
let wasConnectedAtLeastOnce = false;
async function connectMain() {
let usingPeer = await getRandomHardcodedPeer();
let savedPeer = await getSavedPeer();
if (savedPeer && savedPeer.host && savedPeer.tcp) {
if (savedPeer && savedPeer.host && (savedPeer.tcp || savedPeer.ssl)) {
usingPeer = savedPeer;
}
try {
console.log('begin connection:', JSON.stringify(usingPeer));
mainClient = new ElectrumClient(usingPeer.tcp, usingPeer.host, 'tcp');
mainClient = new ElectrumClient(usingPeer.ssl || usingPeer.tcp, usingPeer.host, usingPeer.ssl ? 'tls' : 'tcp');
mainClient.onError = function(e) {
console.log('ElectrumClient error: ' + e);
mainConnected = false;
@ -78,7 +78,8 @@ async function getRandomHardcodedPeer() {
async function getSavedPeer() {
let host = await AsyncStorage.getItem(AppStorage.ELECTRUM_HOST);
let port = await AsyncStorage.getItem(AppStorage.ELECTRUM_TCP_PORT);
return { host, tcp: port };
let sslPort = await AsyncStorage.getItem(AppStorage.ELECTRUM_SSL_PORT);
return { host, tcp: port, ssl: sslPort };
}
/**
@ -391,17 +392,15 @@ module.exports.broadcastV2 = async function(hex) {
*
* @param host
* @param tcpPort
* @param sslPort
* @returns {Promise<boolean>} Whether provided host:port is a valid electrum server
*/
module.exports.testConnection = async function(host, tcpPort) {
let client = new ElectrumClient(tcpPort, host, 'tcp');
module.exports.testConnection = async function(host, tcpPort, sslPort) {
let client = new ElectrumClient(sslPort || tcpPort, host, sslPort ? 'tls' : 'tcp');
try {
await client.connect();
await client.server_version('2.7.11', '1.4');
await client.server_ping();
client.keepAlive = () => {}; // dirty hack to make it stop reconnecting
client.reconnect = () => {}; // dirty hack to make it stop reconnecting
client.close();
return true;
} catch (_) {
@ -410,8 +409,6 @@ module.exports.testConnection = async function(host, tcpPort) {
};
module.exports.forceDisconnect = () => {
mainClient.keepAlive = () => {}; // dirty hack to make it stop reconnecting
mainClient.reconnect = () => {}; // dirty hack to make it stop reconnecting
mainClient.close();
};

1
class/app-storage.js

@ -23,6 +23,7 @@ export class AppStorage {
static LNDHUB = 'lndhub';
static ELECTRUM_HOST = 'electrum_host';
static ELECTRUM_TCP_PORT = 'electrum_tcp_port';
static ELECTRUM_SSL_PORT = 'electrum_ssl_port';
static PREFERRED_CURRENCY = 'preferredCurrency';
static ADVANCED_MODE_ENABLED = 'advancedmodeenabled';
static DELETE_WALLET_AFTER_UNINSTALL = 'deleteWalletAfterUninstall';

97
package-lock.json

@ -6767,9 +6767,9 @@
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="
},
"ip-regex": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz",
"integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0="
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-3.0.0.tgz",
"integrity": "sha512-T8wDtjy+Qf2TAPDQmBp0eGKJ8GavlWlUnamr3wRn6vvdZlKVuJXXMlSncYFRYgVHOM3If5NR1H4+OvVQU9Idvg=="
},
"is": {
"version": "0.2.7",
@ -11697,33 +11697,86 @@
}
},
"react-native-tcp": {
"version": "git+https://github.com/aprock/react-native-tcp.git#6a3b1bc702bf1d40287274ac32698335a8fba61a",
"from": "git+https://github.com/aprock/react-native-tcp.git",
"requires": {
"base64-js": "0.0.8",
"buffer": "^5.0.0",
"events": "^1.0.2",
"ip-regex": "^1.0.3",
"process": "^0.11.9",
"util": "^0.10.3"
"version": "git+https://github.com/BlueWallet/react-native-tcp.git#113433d505063d58a17317e925f03f65e7fc5c3d",
"from": "git+https://github.com/BlueWallet/react-native-tcp.git",
"requires": {
"base64-js": "1.3.0",
"buffer": "5.2.1",
"events": "3.0.0",
"ip-regex": "3.0.0",
"process": "0.11.10",
"stream-browserify": "2.0.1",
"util": "0.11.1"
},
"dependencies": {
"base64-js": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
"integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg="
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
"buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
"integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
}
},
"events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
"integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA=="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"stream-browserify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
"integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
"requires": {
"inherits": "~2.0.1",
"readable-stream": "^2.0.2"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"util": {
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
"integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
"integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
"requires": {
"inherits": "2.0.3"
},
"dependencies": {
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
}
}
}
}

2
package.json

@ -122,7 +122,7 @@
"react-native-snap-carousel": "3.8.4",
"react-native-sortable-list": "0.0.23",
"react-native-svg": "9.13.6",
"react-native-tcp": "git+https://github.com/aprock/react-native-tcp.git",
"react-native-tcp": "git+https://github.com/BlueWallet/react-native-tcp.git",
"react-native-tooltip": "git+https://github.com/marcosrdz/react-native-tooltip.git",
"react-native-vector-icons": "6.6.0",
"react-native-watch-connectivity": "0.4.2",

36
screen/settings/electrumSettings.js

@ -25,11 +25,13 @@ export default class ElectrumSettings extends Component {
async componentDidMount() {
let host = await AsyncStorage.getItem(AppStorage.ELECTRUM_HOST);
let port = await AsyncStorage.getItem(AppStorage.ELECTRUM_TCP_PORT);
let sslPort = await AsyncStorage.getItem(AppStorage.ELECTRUM_SSL_PORT);
this.setState({
isLoading: false,
host,
port,
sslPort,
});
await this.setState({
@ -41,16 +43,19 @@ export default class ElectrumSettings extends Component {
this.setState({ isLoading: true }, async () => {
this.state.host = this.state.host ? this.state.host : '';
this.state.port = this.state.port ? this.state.port : '';
this.state.sslPort = this.state.sslPort ? this.state.sslPort : '';
try {
if (!this.state.host && !this.state.port) {
if (!this.state.host && !this.state.port && !this.state.sslPort) {
await AsyncStorage.setItem(AppStorage.ELECTRUM_HOST, '');
await AsyncStorage.setItem(AppStorage.ELECTRUM_TCP_PORT, '');
await AsyncStorage.setItem(AppStorage.ELECTRUM_SSL_PORT, '');
alert('Your changes have been saved successfully. Restart may be required for changes to take effect.');
} else if (!(await BlueElectrum.testConnection(this.state.host, this.state.port))) {
} else if (!(await BlueElectrum.testConnection(this.state.host, this.state.port, this.state.sslPort))) {
alert("Can't connect to provided Electrum server");
} else {
await AsyncStorage.setItem(AppStorage.ELECTRUM_HOST, this.state.host);
await AsyncStorage.setItem(AppStorage.ELECTRUM_TCP_PORT, this.state.port);
await AsyncStorage.setItem(AppStorage.ELECTRUM_SSL_PORT, this.state.sslPort);
alert('Your changes have been saved successfully. Restart may be required for changes to take effect.');
}
} catch (_) {}
@ -99,6 +104,7 @@ export default class ElectrumSettings extends Component {
borderBottomWidth: 0.5,
backgroundColor: '#f5f5f5',
minHeight: 44,
width: 200,
height: 44,
alignItems: 'center',
borderRadius: 4,
@ -114,6 +120,32 @@ export default class ElectrumSettings extends Component {
underlineColorAndroid="transparent"
/>
</View>
<BlueSpacing20 />
<View
style={{
flexDirection: 'row',
borderColor: '#d2d2d2',
borderBottomColor: '#d2d2d2',
borderWidth: 1.0,
borderBottomWidth: 0.5,
backgroundColor: '#f5f5f5',
minHeight: 44,
height: 44,
width: 200,
alignItems: 'center',
borderRadius: 4,
}}
>
<TextInput
placeholder={'SSL port, usually 50002'}
value={this.state.sslPort}
onChangeText={text => this.setState({ sslPort: text })}
numberOfLines={1}
style={{ flex: 1, marginHorizontal: 8, minHeight: 36, height: 36 }}
editable={!this.state.isLoading}
underlineColorAndroid="transparent"
/>
</View>
<BlueSpacing20 />
{this.state.isLoading ? <BlueLoading /> : <BlueButton onPress={this.save} title={loc.settings.save} />}

4
shim.js

@ -1,6 +1,5 @@
/* global __DEV__, localStorage */
if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer;
global.net = require('react-native-tcp');
if (typeof __dirname === 'undefined') global.__dirname = '/';
if (typeof __filename === 'undefined') global.__filename = '';
if (typeof process === 'undefined') {
@ -16,6 +15,9 @@ if (typeof process === 'undefined') {
process.browser = false;
global.net = require('react-native-tcp');
global.tls = require('react-native-tcp/tls');
// global.location = global.location || { port: 80 }
const isDev = typeof __DEV__ === 'boolean' && __DEV__;
process.env['NODE_ENV'] = isDev ? 'development' : 'production';

44
tests/integration/Electrum.test.js → tests/integration/BlueElectrum.test.js

@ -1,6 +1,6 @@
/* global it, describe, afterAll, beforeAll, jasmine */
const bitcoin = require('bitcoinjs-lib');
global.net = require('net');
global.tls = require('tls');
let BlueElectrum = require('../../BlueElectrum');
let assert = require('assert');
jasmine.DEFAULT_TIMEOUT_INTERVAL = 150 * 1000;
@ -8,7 +8,6 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 150 * 1000;
afterAll(() => {
// after all tests we close socket so the test suite can actually terminate
BlueElectrum.forceDisconnect();
return new Promise(resolve => setTimeout(resolve, 10000)); // simple sleep to wait for all timeouts termination
});
beforeAll(async () => {
@ -22,53 +21,16 @@ beforeAll(async () => {
}
});
describe('Electrum', () => {
describe('BlueElectrum', () => {
it('ElectrumClient can test connection', async () => {
assert.ok(await BlueElectrum.testConnection('electrum1.bluewallet.io', '50001'));
assert.ok(await BlueElectrum.testConnection('electrum1.bluewallet.io', false, 443));
});
it('ElectrumClient can estimate fees', async () => {
assert.ok((await BlueElectrum.estimateFee(1)) > 1);
});
it('ElectrumClient can connect and query', async () => {
const ElectrumClient = require('electrum-client');
for (let peer of BlueElectrum.hardcodedPeers) {
let mainClient = new ElectrumClient(peer.tcp, peer.host, 'tcp');
try {
await mainClient.connect();
await mainClient.server_version('2.7.11', '1.4');
} catch (e) {
mainClient.reconnect = mainClient.keepAlive = () => {}; // dirty hack to make it stop reconnecting
mainClient.close();
throw new Error('bad connection: ' + JSON.stringify(peer) + ' ' + e.message);
}
let addr4elect = 'bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej';
let script = bitcoin.address.toOutputScript(addr4elect);
let hash = bitcoin.crypto.sha256(script);
let reversedHash = Buffer.from(hash.reverse());
let start = +new Date();
let balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex'));
let end = +new Date();
console.warn(peer.host, 'took', (end - start) / 1000, 'seconds to fetch balance');
assert.ok(balance.confirmed > 0);
addr4elect = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK';
script = bitcoin.address.toOutputScript(addr4elect);
hash = bitcoin.crypto.sha256(script);
reversedHash = Buffer.from(hash.reverse());
balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex'));
// let peers = await mainClient.serverPeers_subscribe();
// console.log(peers);
mainClient.reconnect = mainClient.keepAlive = () => {}; // dirty hack to make it stop reconnecting
mainClient.close();
}
});
it('BlueElectrum can do getBalanceByAddress()', async function() {
let address = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK';
let balance = await BlueElectrum.getBalanceByAddress(address);

55
tests/integration/ElectrumClient.test.js

@ -0,0 +1,55 @@
/* global it, describe, jasmine */
const bitcoin = require('bitcoinjs-lib');
global.net = require('net');
global.tls = require('tls');
let assert = require('assert');
jasmine.DEFAULT_TIMEOUT_INTERVAL = 150 * 1000;
const hardcodedPeers = [
{ host: 'electrum1.bluewallet.io', ssl: '443' },
{ host: 'electrum2.bluewallet.io', ssl: '443' },
{ host: 'electrum3.bluewallet.io', ssl: '443' },
{ host: 'electrum1.bluewallet.io', tcp: '50001' },
{ host: 'electrum2.bluewallet.io', tcp: '50001' },
{ host: 'electrum3.bluewallet.io', tcp: '50001' },
];
describe('ElectrumClient', () => {
it('can connect and query', async () => {
const ElectrumClient = require('electrum-client');
for (let peer of hardcodedPeers) {
let mainClient = new ElectrumClient(peer.ssl || peer.tcp, peer.host, peer.ssl ? 'tls' : 'tcp');
try {
await mainClient.connect();
await mainClient.server_version('2.7.11', '1.4');
} catch (e) {
mainClient.reconnect = mainClient.keepAlive = () => {}; // dirty hack to make it stop reconnecting
mainClient.close();
throw new Error('bad connection: ' + JSON.stringify(peer) + ' ' + e.message);
}
let addr4elect = 'bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej';
let script = bitcoin.address.toOutputScript(addr4elect);
let hash = bitcoin.crypto.sha256(script);
let reversedHash = Buffer.from(hash.reverse());
let start = +new Date();
let balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex'));
let end = +new Date();
end - start > 1000 && console.warn(peer.host, 'took', (end - start) / 1000, 'seconds to fetch balance');
assert.ok(balance.confirmed > 0);
addr4elect = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK';
script = bitcoin.address.toOutputScript(addr4elect);
hash = bitcoin.crypto.sha256(script);
reversedHash = Buffer.from(hash.reverse());
balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex'));
// let peers = await mainClient.serverPeers_subscribe();
// console.log(peers);
mainClient.close();
}
});
});

1
tests/integration/HDWallet.test.js

@ -12,6 +12,7 @@ const bitcoin = require('bitcoinjs-lib');
global.crypto = require('crypto'); // shall be used by tests under nodejs CLI, but not in RN environment
let assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP
jasmine.DEFAULT_TIMEOUT_INTERVAL = 300 * 1000;

1
tests/integration/LegacyWallet.test.js

@ -2,6 +2,7 @@
import { LegacyWallet, SegwitP2SHWallet, SegwitBech32Wallet } from '../../class';
let assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;

1
tests/integration/WatchOnlyWallet.test.js

@ -2,6 +2,7 @@
import { WatchOnlyWallet } from '../../class';
let assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP
afterAll(async () => {

1
tests/integration/hd-segwit-bech32-transaction.test.js

@ -4,6 +4,7 @@ const bitcoin = require('bitcoinjs-lib');
global.crypto = require('crypto'); // shall be used by tests under nodejs CLI, but not in RN environment
let assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum');
jasmine.DEFAULT_TIMEOUT_INTERVAL = 150 * 1000;

1
tests/integration/hd-segwit-bech32-wallet.test.js

@ -3,6 +3,7 @@ import { HDSegwitBech32Wallet } from '../../class';
global.crypto = require('crypto'); // shall be used by tests under nodejs CLI, but not in RN environment
let assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP
afterAll(async () => {

Loading…
Cancel
Save