mirror of
https://github.com/fullstack-cash/fullstack-gatsby-theme-bch-wallet.git
synced 2026-09-21 16:52:06 -07:00
Merge pull request #165 from Permissionless-Software-Foundation/ct-unstable
fix(IPFS RPC): Reinitializing wallet with auto-retry
This commit is contained in:
@@ -7,8 +7,8 @@ import CommandRouter from '../lib/commands'
|
||||
|
||||
import './ipfs.css'
|
||||
|
||||
// import RetryQueue from '../../../../lib/retry-queue.mjs'
|
||||
// const queue = new RetryQueue()
|
||||
import RetryQueue from '../../../../lib/retry-queue.mjs'
|
||||
const queue = new RetryQueue()
|
||||
|
||||
const WalletService = require('../lib/wallet-service')
|
||||
const BchWallet = typeof window !== 'undefined' ? window.SlpWallet : null
|
||||
@@ -301,6 +301,8 @@ class IPFS extends React.Component {
|
||||
}
|
||||
|
||||
// pollForServices callback
|
||||
// This method is called from lib/ipfs-control.js. It executes when a BCH
|
||||
// wallet service is found.
|
||||
async onAppStatus (msg) {
|
||||
try {
|
||||
let output
|
||||
@@ -339,83 +341,48 @@ class IPFS extends React.Component {
|
||||
jsonRpcWalletService: walletService
|
||||
}
|
||||
|
||||
_this.bchWalletLib = new _this.BchWallet(mnemonic, advancedConfig)
|
||||
|
||||
let utxosInitialized = false
|
||||
let cnt = 0
|
||||
do {
|
||||
cnt++
|
||||
|
||||
try {
|
||||
// Wait for wallet to be created.
|
||||
await _this.bchWalletLib.walletInfoPromise
|
||||
|
||||
// await _this.bchWalletLib.bchjs.Util.sleep(5000)
|
||||
await _this.sleep(5000)
|
||||
|
||||
const utxos = await _this.bchWalletLib.getUtxos()
|
||||
if (_this.bchWalletLib.utxos.utxoStore) {
|
||||
_this.onStatusLog(
|
||||
`utxo initialization succeeded: ${JSON.stringify(utxos, null, 2)}`
|
||||
)
|
||||
utxosInitialized = true
|
||||
} else {
|
||||
_this.onStatusLog(
|
||||
`Attempt ${cnt} to re-initialize timed out. Will try again.`
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
_this.onStatusLog(
|
||||
`Attempt ${cnt} to re-initialize wallet failed. Will try again.`
|
||||
)
|
||||
console.log(err)
|
||||
|
||||
await _this.sleep(5000)
|
||||
}
|
||||
// } while (!utxosInitialized)
|
||||
} while (!utxosInitialized && cnt < 10)
|
||||
|
||||
// console.log('_this.bchWalletLib: ', _this.bchWalletLib)
|
||||
//
|
||||
// setInterval(async function () {
|
||||
// const now = new Date()
|
||||
// console.log(`Getting UTXOs at ${now.toLocaleString()}`)
|
||||
// await _this.bchWalletLib.getUtxos()
|
||||
// console.log(
|
||||
// `_this.bchWalletLib.utxos.utxoStore: ${JSON.stringify(
|
||||
// _this.bchWalletLib.utxos.utxoStore,
|
||||
// null,
|
||||
// 2
|
||||
// )}`
|
||||
// )
|
||||
// }, 20000)
|
||||
|
||||
// let now = new Date()
|
||||
// console.log(`Starting at ${now.toLocaleString()}`)
|
||||
// await _this.bchWalletLib.bchjs.Util.sleep(5000)
|
||||
// now = new Date()
|
||||
// console.log(`Finished at ${now.toLocaleString()}`)
|
||||
|
||||
// // If UTXOs fail to update, try one more time.
|
||||
// if (!_this.bchWalletLib.utxos.utxoStore) {
|
||||
// await _this.bchWalletLib.getUtxos()
|
||||
//
|
||||
// // Throw an error if UTXOs are still not updated.
|
||||
// if (!_this.bchWalletLib.utxos.utxoStore) {
|
||||
// throw new Error('UTXOs failed to update. Try again.')
|
||||
// }
|
||||
// }
|
||||
// Initialize the wallet, using auth-rety on failure.
|
||||
const walletIn = { mnemonic, advancedConfig }
|
||||
await queue.retryWrapper(_this.initWallet, walletIn)
|
||||
|
||||
// Update redux state
|
||||
_this.props.setBchWallet(_this.bchWalletLib)
|
||||
_this.onStatusLog('re-initialize success!')
|
||||
} catch (error) {
|
||||
_this.onStatusLog('Error on re-initialize')
|
||||
_this.onStatusLog('Error in reInitialize()')
|
||||
_this.onStatusLog(error.message)
|
||||
// Don't throw an error as this is a top-level handler.
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the wallet and retrieve the UTXOs for the wallet.
|
||||
// This function is called by the queue library, to do automatic retry on
|
||||
// network failure.
|
||||
async initWallet (walletIn) {
|
||||
try {
|
||||
const { mnemonic, advancedConfig } = walletIn
|
||||
|
||||
_this.bchWalletLib = new _this.BchWallet(mnemonic, advancedConfig)
|
||||
|
||||
// Wait for wallet to be created.
|
||||
await _this.bchWalletLib.walletInfoPromise
|
||||
|
||||
// If auto UTXO initialization fails, do it manually.
|
||||
let utxos = _this.bchWalletLib.utxos.utxoStore
|
||||
if (!utxos) {
|
||||
utxos = await _this.bchWalletLib.getUtxos()
|
||||
}
|
||||
|
||||
_this.onStatusLog(
|
||||
`utxo initialization succeeded: ${JSON.stringify(utxos, null, 2)}`
|
||||
)
|
||||
|
||||
return _this.bchWalletLib
|
||||
} catch (err) {
|
||||
console.error('Error in initWallet(): ', err)
|
||||
}
|
||||
}
|
||||
|
||||
// Fill the queue with the incoming data (private messages) from the petitions
|
||||
// So it will be sweeped by the lib/wallet-service/waitForRPCResponse() function
|
||||
handleRpcDataQueue (data) {
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
pay-to-write-access-controller.js depends on this library.
|
||||
*/
|
||||
|
||||
// const PQueue = require('p-queue').default
|
||||
'use strict'
|
||||
|
||||
import PQueue from 'p-queue'
|
||||
import pRetry from 'p-retry'
|
||||
|
||||
@@ -55,7 +52,7 @@ class RetryQueue {
|
||||
)
|
||||
return returnVal
|
||||
} catch (err) {
|
||||
console.error('Error in addToQueue(): ', err)
|
||||
console.error('Error in addToQueue()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -99,11 +96,12 @@ class RetryQueue {
|
||||
try {
|
||||
const errorMsg = `Attempt ${error.attemptNumber} to validate entry. There are ${error.retriesLeft} retries left. Waiting before trying again.`
|
||||
console.log(errorMsg)
|
||||
const SLEEP_TIME = 30000
|
||||
|
||||
const SLEEP_TIME = _this.retryPeriod
|
||||
console.log(`Waiting ${SLEEP_TIME} milliseconds before trying again.\n`)
|
||||
await _this.bchjs.Util.sleep(SLEEP_TIME) // 30 sec
|
||||
await _this.sleep(SLEEP_TIME) // 30 sec
|
||||
} catch (err) {
|
||||
console.error('Error in handleValidationError(): ', err)
|
||||
console.error('Error in handleValidationError()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,127 +32,138 @@ describe('#retry-queue.js', () => {
|
||||
assert.include(err.message, 'function handler is required')
|
||||
}
|
||||
})
|
||||
//
|
||||
// it('should throw an error if input object is not provided', async () => {
|
||||
// try {
|
||||
// const funcHandler = () => {}
|
||||
// await uut.retryWrapper(funcHandler)
|
||||
// assert.fail('unexpected code path')
|
||||
// } catch (err) {
|
||||
// assert.include(err.message, 'input object is required')
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// it('should execute the given function.', async () => {
|
||||
// const inputTest = 'test'
|
||||
// // func mock to execute into the retry wrapper
|
||||
// const funcHandle = sinon.spy()
|
||||
//
|
||||
// await uut.retryWrapper(funcHandle, inputTest)
|
||||
//
|
||||
// assert.equal(inputTest, funcHandle.getCall(0).args[0])
|
||||
// assert.equal(funcHandle.callCount, 1)
|
||||
// })
|
||||
//
|
||||
// it('should call handleValidationError() when p-retry error is thrown', async () => {
|
||||
// try {
|
||||
// // Mock for ignore sleep time
|
||||
// sandbox.stub(uut.bchjs.Util, 'sleep').resolves({})
|
||||
//
|
||||
// const inputTest = 'test'
|
||||
// const funcHandle = () => {
|
||||
// throw new Error('test error')
|
||||
// }
|
||||
// uut.attempts = 1
|
||||
// await uut.retryWrapper(funcHandle, inputTest)
|
||||
// assert.fail('unexpected code path')
|
||||
// } catch (err) {
|
||||
// assert.include(err.message, 'test error')
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// it('should retry the specific number of times before giving up', async () => {
|
||||
// // Mock for ignore sleep time
|
||||
// sandbox.stub(uut.bchjs.Util, 'sleep').resolves({})
|
||||
//
|
||||
// const inputTest = 'test'
|
||||
// const funcHandle = () => {
|
||||
// throw new Error('test error')
|
||||
// }
|
||||
// // func handler
|
||||
// const spy = sinon.spy(funcHandle)
|
||||
//
|
||||
// // p-retry attempts
|
||||
// const attempts = 1
|
||||
//
|
||||
// try {
|
||||
// uut.attempts = attempts
|
||||
// await uut.retryWrapper(spy, inputTest)
|
||||
// assert.fail('unexpected code path')
|
||||
// } catch (error) {
|
||||
// assert.equal(spy.callCount, attempts + 1)
|
||||
// }
|
||||
// })
|
||||
|
||||
it('should throw an error if input object is not provided', async () => {
|
||||
try {
|
||||
const funcHandler = () => {}
|
||||
await uut.retryWrapper(funcHandler)
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'input object is required')
|
||||
}
|
||||
})
|
||||
|
||||
it('should execute the given function.', async () => {
|
||||
const inputTest = 'test'
|
||||
// func mock to execute into the retry wrapper
|
||||
const funcHandle = sinon.spy()
|
||||
|
||||
await uut.retryWrapper(funcHandle, inputTest)
|
||||
|
||||
assert.equal(inputTest, funcHandle.getCall(0).args[0])
|
||||
assert.equal(funcHandle.callCount, 1)
|
||||
})
|
||||
|
||||
it('should call handleValidationError() when p-retry error is thrown', async () => {
|
||||
try {
|
||||
// Mock for ignore sleep time
|
||||
sandbox.stub(uut, 'sleep').resolves({})
|
||||
|
||||
const inputTest = 'test'
|
||||
const funcHandle = () => {
|
||||
throw new Error('test error')
|
||||
}
|
||||
uut.attempts = 1
|
||||
|
||||
await uut.retryWrapper(funcHandle, inputTest)
|
||||
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
it('should retry the specific number of times before giving up', async () => {
|
||||
// Mock for ignore sleep time
|
||||
sandbox.stub(uut, 'sleep').resolves({})
|
||||
|
||||
const inputTest = 'test'
|
||||
const funcHandle = () => {
|
||||
throw new Error('test error')
|
||||
}
|
||||
// func handler
|
||||
const spy = sinon.spy(funcHandle)
|
||||
|
||||
// p-retry attempts
|
||||
const attempts = 1
|
||||
|
||||
try {
|
||||
uut.attempts = attempts
|
||||
|
||||
await uut.retryWrapper(spy, inputTest)
|
||||
|
||||
assert.fail('unexpected code path')
|
||||
} catch (error) {
|
||||
assert.equal(spy.callCount, attempts + 1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// describe('#addToQueue', () => {
|
||||
// it('should throw an error if function handler is not provided', async () => {
|
||||
// try {
|
||||
// await uut.addToQueue()
|
||||
// assert.fail('unexpected code path')
|
||||
// } catch (err) {
|
||||
// assert.include(err.message, 'function handler is required')
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// it('should throw an error if input object is not provided', async () => {
|
||||
// try {
|
||||
// const funcHandler = () => {}
|
||||
// await uut.addToQueue(funcHandler)
|
||||
// assert.fail('unexpected code path')
|
||||
// } catch (err) {
|
||||
// assert.include(err.message, 'input object is required')
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// it('should add a function and input object to the queue and execute them', async () => {
|
||||
// const inputTest = 'test'
|
||||
// // func mock to execute into the retry wrapper
|
||||
// const funcHandle = sinon.spy()
|
||||
//
|
||||
// await uut.addToQueue(funcHandle, inputTest)
|
||||
// assert.equal(inputTest, funcHandle.getCall(0).args[0])
|
||||
// assert.equal(funcHandle.callCount, 1)
|
||||
// })
|
||||
//
|
||||
// it('should catch and throw an error', async () => {
|
||||
// try {
|
||||
// // Mock for ignore sleep time
|
||||
// sandbox.stub(uut.bchjs.Util, 'sleep').resolves({})
|
||||
//
|
||||
// const inputTest = 'test'
|
||||
//
|
||||
// const funcHandle = () => {
|
||||
// throw new Error('test error')
|
||||
// }
|
||||
// uut.attempts = 1
|
||||
// await uut.retryWrapper(funcHandle, inputTest)
|
||||
// assert.fail('unexpected code path')
|
||||
// } catch (err) {
|
||||
// assert.include(err.message, 'test error')
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
describe('#addToQueue', () => {
|
||||
it('should throw an error if function handler is not provided', async () => {
|
||||
try {
|
||||
await uut.addToQueue()
|
||||
|
||||
// describe('#handleValidationError', () => {
|
||||
// it('should catch and throw an error', async () => {
|
||||
// try {
|
||||
// await uut.handleValidationError()
|
||||
// assert.fail('unexpected code path')
|
||||
// } catch (err) {
|
||||
// console.log(err)
|
||||
// assert.include(err.message, 'Cannot read property')
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'function handler is required')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if input object is not provided', async () => {
|
||||
try {
|
||||
const funcHandler = () => {}
|
||||
|
||||
await uut.addToQueue(funcHandler)
|
||||
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'input object is required')
|
||||
}
|
||||
})
|
||||
|
||||
it('should add a function and input object to the queue and execute them', async () => {
|
||||
const inputTest = 'test'
|
||||
// func mock to execute into the retry wrapper
|
||||
const funcHandle = sinon.spy()
|
||||
|
||||
await uut.addToQueue(funcHandle, inputTest)
|
||||
|
||||
assert.equal(inputTest, funcHandle.getCall(0).args[0])
|
||||
assert.equal(funcHandle.callCount, 1)
|
||||
})
|
||||
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
// Mock for ignore sleep time
|
||||
sandbox.stub(uut, 'sleep').resolves({})
|
||||
|
||||
const inputTest = 'test'
|
||||
|
||||
const funcHandle = () => {
|
||||
throw new Error('test error')
|
||||
}
|
||||
|
||||
uut.attempts = 1
|
||||
await uut.retryWrapper(funcHandle, inputTest)
|
||||
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#handleValidationError', () => {
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
await uut.handleValidationError()
|
||||
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user