Browse Source

Merge pull request #921 from BlueWallet/electrum-improvements

REF: electrum android reconnect improvements
snyk-fix-84644e4a03e171e392ba652f3dc364b5
Overtorment 5 years ago
committed by GitHub
parent
commit
1ebc2dcd21
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      BlueElectrum.js
  2. 4
      package-lock.json
  3. 2
      package.json
  4. 38
      screen/settings/electrumSettings.js
  5. 8
      tests/integration/BlueElectrum.test.js

26
BlueElectrum.js

@ -1,4 +1,5 @@
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
import { Platform } from 'react-native';
import { AppStorage } from './class'; import { AppStorage } from './class';
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
const ElectrumClient = require('electrum-client'); const ElectrumClient = require('electrum-client');
@ -38,11 +39,19 @@ async function connectMain() {
console.log('begin connection:', JSON.stringify(usingPeer)); console.log('begin connection:', JSON.stringify(usingPeer));
mainClient = new ElectrumClient(usingPeer.ssl || usingPeer.tcp, usingPeer.host, usingPeer.ssl ? 'tls' : 'tcp'); mainClient = new ElectrumClient(usingPeer.ssl || usingPeer.tcp, usingPeer.host, usingPeer.ssl ? 'tls' : 'tcp');
mainClient.onError = function(e) { mainClient.onError = function(e) {
console.log('ElectrumClient error: ' + e); if (Platform.OS === 'android' && mainConnected) {
// android sockets are buggy and dont always issue CLOSE event, which actually makes the persistence code to reconnect.
// so lets do it manually, but only if we were previously connected (mainConnected), otherwise theres other
// code which does connection retries
mainClient.close();
mainConnected = false;
setTimeout(connectMain, 500);
console.warn('reconnecting after socket error');
return;
}
mainConnected = false; mainConnected = false;
}; };
await mainClient.connect(); const ver = await mainClient.initElectrum({ client: 'bluewallet', version: '1.4' });
const ver = await mainClient.server_version('2.7.11', '1.4');
if (ver && ver[0]) { if (ver && ver[0]) {
console.log('connected to ', ver); console.log('connected to ', ver);
mainConnected = true; mainConnected = true;
@ -56,9 +65,7 @@ async function connectMain() {
if (!mainConnected) { if (!mainConnected) {
console.log('retry'); console.log('retry');
mainClient.keepAlive = () => {}; // dirty hack to make it stop reconnecting mainClient.close && mainClient.close();
mainClient.reconnect = () => {}; // dirty hack to make it stop reconnecting
mainClient.close();
setTimeout(connectMain, 500); setTimeout(connectMain, 500);
} }
} }
@ -132,7 +139,7 @@ module.exports.getConfig = async function() {
return { return {
host: mainClient.host, host: mainClient.host,
port: mainClient.port, port: mainClient.port,
status: mainClient.status, status: mainClient.status && mainConnected ? 1 : 0,
}; };
}; };
@ -373,6 +380,11 @@ module.exports.estimateFee = async function(numberOfBlocks) {
); );
}; };
module.exports.serverFeatures = async function() {
if (!mainClient) throw new Error('Electrum client is not connected');
return mainClient.server_features();
};
module.exports.broadcast = async function(hex) { module.exports.broadcast = async function(hex) {
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
try { try {

4
package-lock.json

@ -4374,8 +4374,8 @@
"integrity": "sha512-NK9DBBYEBb5f9D7zXI0hiE941gq3wkBeQmXs1ingigA/jnTg5mhwY2Z5egwA+ZI8OLGKCx0h1Cl8/xeuIBuLlg==" "integrity": "sha512-NK9DBBYEBb5f9D7zXI0hiE941gq3wkBeQmXs1ingigA/jnTg5mhwY2Z5egwA+ZI8OLGKCx0h1Cl8/xeuIBuLlg=="
}, },
"electrum-client": { "electrum-client": {
"version": "git+https://github.com/BlueWallet/rn-electrum-client.git#4bbd13f3c2b9ae683ee8ec064d770be1f76b23a7", "version": "git+https://github.com/BlueWallet/rn-electrum-client.git#2a5bb11dd9a8d89f328049d9ed59bce49d88a15d",
"from": "git+https://github.com/BlueWallet/rn-electrum-client.git#4bbd13f3c2b9ae683ee8ec064d770be1f76b23a7" "from": "git+https://github.com/BlueWallet/rn-electrum-client.git#2a5bb11dd9a8d89f328049d9ed59bce49d88a15d"
}, },
"elliptic": { "elliptic": {
"version": "6.5.2", "version": "6.5.2",

2
package.json

@ -76,7 +76,7 @@
"crypto-js": "3.1.9-1", "crypto-js": "3.1.9-1",
"dayjs": "1.8.20", "dayjs": "1.8.20",
"ecurve": "1.0.6", "ecurve": "1.0.6",
"electrum-client": "git+https://github.com/BlueWallet/rn-electrum-client.git#4bbd13f3c2b9ae683ee8ec064d770be1f76b23a7", "electrum-client": "git+https://github.com/BlueWallet/rn-electrum-client.git#2a5bb11dd9a8d89f328049d9ed59bce49d88a15d",
"eslint-config-prettier": "6.10.0", "eslint-config-prettier": "6.10.0",
"eslint-config-standard": "12.0.0", "eslint-config-standard": "12.0.0",
"eslint-config-standard-react": "7.0.2", "eslint-config-standard-react": "7.0.2",

38
screen/settings/electrumSettings.js

@ -3,7 +3,16 @@ import React, { Component } from 'react';
import { View, TextInput } from 'react-native'; import { View, TextInput } from 'react-native';
import { AppStorage } from '../../class'; import { AppStorage } from '../../class';
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
import { BlueLoading, BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueNavigationStyle, BlueText } from '../../BlueComponents'; import {
BlueLoading,
BlueSpacing20,
BlueButton,
SafeBlueArea,
BlueCard,
BlueNavigationStyle,
BlueText,
BlueButtonLink,
} from '../../BlueComponents';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
let loc = require('../../loc'); let loc = require('../../loc');
let BlueElectrum = require('../../BlueElectrum'); let BlueElectrum = require('../../BlueElectrum');
@ -39,23 +48,32 @@ export default class ElectrumSettings extends Component {
}); });
} }
checkServer = async () => {
this.setState({ isLoading: true }, async () => {
const features = await BlueElectrum.serverFeatures();
alert(JSON.stringify(features, null, 2));
this.setState({ isLoading: false });
});
};
save = () => { save = () => {
const host = this.state.host ? this.state.host : '';
const port = this.state.port ? this.state.port : '';
const sslPort = this.state.sslPort ? this.state.sslPort : '';
this.setState({ isLoading: true }, async () => { 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 { try {
if (!this.state.host && !this.state.port && !this.state.sslPort) { if (!host && !port && !sslPort) {
await AsyncStorage.setItem(AppStorage.ELECTRUM_HOST, ''); await AsyncStorage.setItem(AppStorage.ELECTRUM_HOST, '');
await AsyncStorage.setItem(AppStorage.ELECTRUM_TCP_PORT, ''); await AsyncStorage.setItem(AppStorage.ELECTRUM_TCP_PORT, '');
await AsyncStorage.setItem(AppStorage.ELECTRUM_SSL_PORT, ''); await AsyncStorage.setItem(AppStorage.ELECTRUM_SSL_PORT, '');
alert('Your changes have been saved successfully. Restart may be required for changes to take effect.'); 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, this.state.sslPort))) { } else if (!(await BlueElectrum.testConnection(host, port, sslPort))) {
alert("Can't connect to provided Electrum server"); alert("Can't connect to provided Electrum server");
} else { } else {
await AsyncStorage.setItem(AppStorage.ELECTRUM_HOST, this.state.host); await AsyncStorage.setItem(AppStorage.ELECTRUM_HOST, host);
await AsyncStorage.setItem(AppStorage.ELECTRUM_TCP_PORT, this.state.port); await AsyncStorage.setItem(AppStorage.ELECTRUM_TCP_PORT, port);
await AsyncStorage.setItem(AppStorage.ELECTRUM_SSL_PORT, this.state.sslPort); await AsyncStorage.setItem(AppStorage.ELECTRUM_SSL_PORT, sslPort);
alert('Your changes have been saved successfully. Restart may be required for changes to take effect.'); alert('Your changes have been saved successfully. Restart may be required for changes to take effect.');
} }
} catch (_) {} } catch (_) {}
@ -157,6 +175,8 @@ export default class ElectrumSettings extends Component {
<BlueText>Host: {this.state.config.host}</BlueText> <BlueText>Host: {this.state.config.host}</BlueText>
<BlueText>Port: {this.state.config.port}</BlueText> <BlueText>Port: {this.state.config.port}</BlueText>
<BlueText>Connected: {(this.state.config.status === 1 && 'Yes') || 'No'}</BlueText> <BlueText>Connected: {(this.state.config.status === 1 && 'Yes') || 'No'}</BlueText>
<BlueSpacing20 />
{this.state.isLoading ? <BlueLoading /> : <BlueButtonLink onPress={this.checkServer} title={'Check current server'} />}
</BlueCard> </BlueCard>
</SafeBlueArea> </SafeBlueArea>
); );

8
tests/integration/BlueElectrum.test.js

@ -31,6 +31,14 @@ describe('BlueElectrum', () => {
assert.ok((await BlueElectrum.estimateFee(1)) > 1); assert.ok((await BlueElectrum.estimateFee(1)) > 1);
}); });
it('ElectrumClient can request server features', async () => {
const features = await BlueElectrum.serverFeatures();
// console.warn({features});
assert.ok(features.server_version);
assert.ok(features.protocol_min);
assert.ok(features.protocol_max);
});
it('BlueElectrum can do getBalanceByAddress()', async function() { it('BlueElectrum can do getBalanceByAddress()', async function() {
let address = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK'; let address = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK';
let balance = await BlueElectrum.getBalanceByAddress(address); let balance = await BlueElectrum.getBalanceByAddress(address);

Loading…
Cancel
Save