Skip to content

Commit

Permalink
Merge pull request #469 from rithvikvibhu/spv-fixes
Browse files Browse the repository at this point in the history
SPV, RPC, Rescan fixes
  • Loading branch information
rithvikvibhu authored Jul 5, 2022
2 parents 44beb51 + 9b0baa0 commit 1185fbe
Show file tree
Hide file tree
Showing 21 changed files with 188 additions and 129 deletions.
1 change: 0 additions & 1 deletion app/background/node/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export const clientStub = ipcRendererInjector => makeClient(ipcRendererInjector,
'getNameInfo',
'getTXByAddresses',
'getNameByHash',
'getAuctionInfo',
'getBlockByHeight',
'getTx',
'broadcastRawTx',
Expand Down
32 changes: 16 additions & 16 deletions app/background/node/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import path from 'path';
import fs from 'fs';
import crypto from 'crypto';
import EventEmitter from 'events';
import throttle from 'lodash.throttle';
import { NodeClient } from 'hs-client';
import { BigNumber } from 'bignumber.js';
import { ConnectionTypes, getConnection, getCustomRPC } from '../connections/service';
Expand Down Expand Up @@ -36,6 +37,7 @@ const WALLET_API_KEY = 'walletApiKey';
const NODE_API_KEY = 'nodeApiKey';
const NODE_NO_DNS = 'nodeNoDns1';
const SPV_MODE = 'nodeSpvMode';
const HANDSHAKE_API_BASE_URL = 'https://api.handshakeapi.com/hsd';

export class NodeService extends EventEmitter {
constructor() {
Expand Down Expand Up @@ -110,10 +112,10 @@ export class NodeService extends EventEmitter {
}

async setSpvMode(spv) {
await put(SPV_MODE, !!spv ? '1' : '');
await put(SPV_MODE, !!spv ? '1' : '0');
dispatchToMainWindow({
type: SET_SPV_MODE,
payload: spv === '1',
payload: spv === true,
});
}

Expand Down Expand Up @@ -191,6 +193,7 @@ export class NodeService extends EventEmitter {
this.network = network;
this.apiKey = await this.getAPIKey();
this.noDns = await this.getNoDns();
this.spv = await this.getSpvMode();
}

async startNode() {
Expand Down Expand Up @@ -253,6 +256,8 @@ export class NodeService extends EventEmitter {
});
});

this.hsd.on('connect', async () => this.refreshNodeInfo());

await this.hsd.ensure();
await this.hsd.open();
this.emit('start local', this.hsd.get('walletdb'), walletApiKey);
Expand All @@ -264,8 +269,6 @@ export class NodeService extends EventEmitter {
if (!(await get(migrateFlag))) {
await put(migrateFlag, true);
}

this.hsd.on('connect', async () => this.refreshNodeInfo());
}

async setHSDLocalClient() {
Expand Down Expand Up @@ -381,9 +384,12 @@ export class NodeService extends EventEmitter {
if (!this.client)
return;

await this._refreshNodeInfo();
};

_refreshNodeInfo = throttle(async () => {
try {
const info = await this.getInfo();
this.emit('refreshNodeInfo', info);

dispatchToMainWindow({
type: SET_NODE_INFO,
Expand All @@ -402,9 +408,8 @@ export class NodeService extends EventEmitter {
}

this.height = info.chain.height;
} catch (e) {
}
};
} catch (e) {}
}, 500, {trailing: true})

async generateToAddress(numblocks, address) {
return this._execRPC('generatetoaddress', [numblocks, address]);
Expand Down Expand Up @@ -440,10 +445,6 @@ export class NodeService extends EventEmitter {
return name;
}

async getAuctionInfo(name) {
return this._execRPC('getauctioninfo', [name], true);
}

async getBlock(height) {
if (await this.getSpvMode()) {
return hapiGet(`/block/${block}`);
Expand Down Expand Up @@ -572,7 +573,7 @@ export class NodeService extends EventEmitter {
getAgent() {
const { name, version } = pkg;

return `${name}:${version}`;
return `${name}:${version}`;
}

async _ensureStarted() {
Expand Down Expand Up @@ -616,7 +617,6 @@ const methods = {
getInfo: () => service.getInfo(),
getNameInfo: (name) => service.getNameInfo(name),
getNameByHash: (hash) => service.getNameByHash(hash),
getAuctionInfo: (name) => service.getAuctionInfo(name),
getBlock: (height) => service.getBlock(height),
generateToAddress: (numblocks, address) => service.generateToAddress(numblocks, address),
getTXByAddresses: (addresses) => service.getTXByAddresses(addresses),
Expand Down Expand Up @@ -645,7 +645,7 @@ export async function start(server) {
}

async function hapiGet(path = '') {
const res = await fetch(`https://api.handshakeapi.com/hsd${path}`, {
const res = await fetch(HANDSHAKE_API_BASE_URL + path, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Expand All @@ -671,7 +671,7 @@ async function hapiGet(path = '') {
}

async function hapiPost(path = '', body) {
const res = await fetch(`https://api.handshakeapi.com/hsd${path}`, {
const res = await fetch(HANDSHAKE_API_BASE_URL + path, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
106 changes: 46 additions & 60 deletions app/background/wallet/service.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { WalletClient } from 'hs-client';
import BigNumber from 'bignumber.js';
import path from 'path';
import { app } from 'electron';
import crypto from 'crypto';
const Validator = require('bval');
import { ConnectionTypes, getConnection } from '../connections/service';
Expand All @@ -17,6 +15,7 @@ import {
STOP_SYNC_WALLET,
SYNC_WALLET_PROGRESS,
SET_WALLET_NETWORK,
SET_RESCAN_HEIGHT,
SET_FIND_NONCE_PROGRESS,
} from '../../ducks/walletReducer';
import {STOP, SET_CUSTOM_RPC_STATUS} from '../../ducks/nodeReducer';
Expand Down Expand Up @@ -51,24 +50,26 @@ const {LedgerHSD, LedgerChange, LedgerCovenant, LedgerInput} = hsdLedger;
const {Device} = hsdLedger.HID;
const ONE_MINUTE = 60000;

const HSD_DATA_DIR = path.join(app.getPath('userData'), 'hsd_data');
const WALLET_API_KEY = 'walletApiKey';

class WalletService {
constructor() {
nodeService.on('start remote', this._useWalletNode);
nodeService.on('start local', this._usePlugin);
nodeService.on('stopped', this._onNodeStop);
nodeService.on('refreshNodeInfo', this._onRefreshNodeInfo);
this.nodeService = nodeService;
this.nodeHeight = 0;
this.lastProgressUpdate = 0;
this.lastKnownChainHeight = 0;
this.heightBeforeRescan = null; // null = not rescanning
this.conn = {type: null};
this.findNonceStop = false;
}

// Wallet as a plugin to the hsd full node is the default configuration
/**
* Wallet as a plugin to the hsd full node is the default configuration
* @param {import('hsd/lib/wallet/plugin')} plugin
* @param {string} apiKey
*/
_usePlugin = async (plugin, apiKey) => {
if (this.node) {
// The app was restarted but the nodes are already running,
Expand Down Expand Up @@ -108,8 +109,8 @@ class WalletService {
this.node.wdb.on('error', e => {
console.error('walletdb error', e);
});
this.node.wdb.client.bind('block connect', this.onNewBlock);
this.node.wdb.client.bind('block rescan', this.onRescanBlock);

this.node.wdb.on('block connect', this.onNewBlock);

this.client = new WalletClient({
network: this.network,
Expand All @@ -123,6 +124,8 @@ class WalletService {
type: SET_WALLETS,
payload: createPayloadForSetWallets(wallets),
});

this.lastKnownChainHeight = this.node.wdb.height;
};

// Wallet as a separate process only runs in Custom RPC mode
Expand Down Expand Up @@ -204,16 +207,7 @@ class WalletService {
console.error('walletdb error', e);
});

this.node.wdb.client.bind('block connect', this.onNewBlock);
this.node.wdb.client.unhook('block rescan');
this.node.wdb.client.hook('block rescan', async (entry, txs) => {
try {
await this.node.wdb.rescanBlock(entry, txs);
} catch (e) {
this.node.wdb.emit('error', e);
}
await this.onRescanBlock(entry);
});
this.node.wdb.on('block connect', this.onNewBlock);

await this.node.open();

Expand Down Expand Up @@ -244,23 +238,6 @@ class WalletService {
this.conn = {type: null};
};

// Called when node emits refreshNodeInfo
// Required to get node height once node is connected
_onRefreshNodeInfo = async (nodeInfo) => {
this.nodeHeight = nodeInfo.chain.height;

// If wallet is synced up with node,
// stop wallet sync (similar to onRescanBlock)
if (this.lastKnownChainHeight === this.nodeHeight) {
dispatchToMainWindow({type: STOP_SYNC_WALLET});
dispatchToMainWindow({
type: SYNC_WALLET_PROGRESS,
payload: this.nodeHeight,
});
await this.refreshWalletInfo();
}
}

isReady = async () => {
let attempts = 0;
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -414,11 +391,18 @@ class WalletService {
};

rescan = async (height = 0) => {
this.heightBeforeRescan = this.lastKnownChainHeight;
this.lastKnownChainHeight = height;

dispatchToMainWindow({type: START_SYNC_WALLET});
dispatchToMainWindow({
type: SYNC_WALLET_PROGRESS,
payload: height,
});
dispatchToMainWindow({
type: SET_RESCAN_HEIGHT,
payload: this.heightBeforeRescan,
});

return this.node.wdb.rescan(height);
};
Expand Down Expand Up @@ -812,8 +796,16 @@ class WalletService {
return this.client.zap(this.name, 'default', 1);
};

importName = (name, start) => {
return this._executeRPC('importname', [name, start]);
importName = async (name, start) => {
await this._executeRPC('importname', [name, null]);

// wait 1 sec (for filterload to update on peer)
if (this.nodeService.spv) {
await new Promise(resolve => setTimeout(resolve, 1000));
}

// rescan
this.rescan(start);
};

rpcGetWalletInfo = async () => {
Expand Down Expand Up @@ -1177,42 +1169,36 @@ class WalletService {

onNewBlock = async (entry) => {
await this._ensureClient();
await this.refreshWalletInfo();

dispatchToMainWindow({
type: SYNC_WALLET_PROGRESS,
payload: entry.height,
});

this.lastKnownChainHeight = entry.height;
};

/**
* Stub handler for rescan block
*
* @param {ChainEntry} entry
* @param {TX[]} txs
* @returns {Promise}
*/

onRescanBlock = async (entry) => {
this.lastKnownChainHeight = entry.height;

if (entry.height === this.nodeHeight) {
// If wallet rescanning, and has reached
// height before rescan start, the stop sync.
if (
this.heightBeforeRescan !== null
&& this.heightBeforeRescan <= entry.height
) {
// Stop sync
dispatchToMainWindow({type: STOP_SYNC_WALLET});
dispatchToMainWindow({
type: SYNC_WALLET_PROGRESS,
payload: entry.height,
});

// Reset rescan height
this.heightBeforeRescan = null;
dispatchToMainWindow({
type: SET_RESCAN_HEIGHT,
payload: null,
});

// Refresh wallet info
await this.refreshWalletInfo();
return;
}

// debounce for 500 msec
const now = Date.now();

// debounce wallet sync update
if (now - this.lastProgressUpdate > 500) {
dispatchToMainWindow({type: START_SYNC_WALLET});
dispatchToMainWindow({
type: SYNC_WALLET_PROGRESS,
payload: entry.height,
Expand Down
13 changes: 11 additions & 2 deletions app/components/Sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ const nodeClient = clientStub(() => require('electron').ipcRenderer);
chainHeight: state.node.chain.height,
tip: state.node.chain.tip,
newBlockStatus: state.node.newBlockStatus,
spv: state.node.spv,
walletId: state.wallet.wid,
walletWatchOnly: state.wallet.watchOnly,
walletSync: state.wallet.walletSync,
walletHeight: state.wallet.walletHeight,
rescanHeight: state.wallet.rescanHeight,
address: state.wallet.address,
updateAvailable: state.app.updateAvailable,
}),
Expand All @@ -41,9 +43,11 @@ class Sidebar extends Component {
walletId: PropTypes.string.isRequired,
tip: PropTypes.string.isRequired,
newBlockStatus: PropTypes.string.isRequired,
spv: PropTypes.bool.isRequired,
walletWatchOnly: PropTypes.bool.isRequired,
walletSync: PropTypes.bool.isRequired,
walletHeight: PropTypes.number.isRequired,
rescanHeight: PropTypes.number,
network: PropTypes.string.isRequired,
address: PropTypes.string.isRequired,
updateAvailable: PropTypes.object,
Expand Down Expand Up @@ -169,7 +173,11 @@ class Sidebar extends Component {
}

renderGenerateBlockButton(numblocks) {
const { network, address } = this.props;
const { network, address, spv } = this.props;
if (spv) {
return;
}

if ([NETWORKS.SIMNET, NETWORKS.REGTEST].includes(network)) {
return (
<button
Expand All @@ -188,6 +196,7 @@ class Sidebar extends Component {
const {
walletSync,
walletHeight,
rescanHeight,
newBlockStatus,
chainHeight,
tip,
Expand Down Expand Up @@ -215,7 +224,7 @@ class Sidebar extends Component {
<div className="sidebar__footer__row">
<div className="sidebar__footer__title">{t('currentHeight')}</div>
<div className="sidebar__footer__text">
{walletSync ? `${walletHeight}/${chainHeight}` : `${chainHeight}` || '--'}
{walletSync ? `${walletHeight}/${rescanHeight}` : `${chainHeight}` || '--'}
</div>
<div className="sidebar__footer__simnet-controls">
{this.renderGenerateBlockButton(1)}
Expand Down
Loading

0 comments on commit 1185fbe

Please sign in to comment.