FIX: correctly work with addresses funded by coinbase transactions

This commit is contained in:
overtorment 2023-12-24 22:27:50 +00:00
parent be2aaade41
commit 7e89fc02da
8 changed files with 27 additions and 6 deletions

View file

@ -603,6 +603,7 @@ module.exports.multiGetHistoryByAddress = async function (addresses, batchsize)
}; };
module.exports.multiGetTransactionByTxid = async function (txids, batchsize, verbose = true) { module.exports.multiGetTransactionByTxid = async function (txids, batchsize, verbose = true) {
txids = txids.filter(txid => !!txid); // failsafe: removing 'undefined' or other falsy stuff from txids array
batchsize = batchsize || 45; batchsize = batchsize || 45;
// this value is fine-tuned so althrough wallets in test suite will occasionally // this value is fine-tuned so althrough wallets in test suite will occasionally
// throw 'response too large (over 1,000,000 bytes', test suite will pass // throw 'response too large (over 1,000,000 bytes', test suite will pass

View file

@ -325,7 +325,8 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
const vinTxids = []; const vinTxids = [];
for (const txdata of Object.values(txdatas)) { for (const txdata of Object.values(txdatas)) {
for (const vin of txdata.vin) { for (const vin of txdata.vin) {
vinTxids.push(vin.txid); vin.txid && vinTxids.push(vin.txid);
// ^^^^ not all inputs have txid, some of them are Coinbase (newly-created coins)
} }
} }
const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids); const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids);

View file

@ -288,7 +288,9 @@ export class LegacyWallet extends AbstractWallet {
const vinTxids = []; const vinTxids = [];
for (const txdata of transactions) { for (const txdata of transactions) {
for (const vin of txdata.vin) { for (const vin of txdata.vin) {
vinTxids.push(vin.txid); // vinTxids.push(vin.txid);
vin.txid && vinTxids.push(vin.txid);
// ^^^^ not all inputs have txid, some of them are Coinbase (newly-created coins)
} }
} }
const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids); const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids);

View file

@ -3,7 +3,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
import { FiatUnit } from '../../models/fiatUnit'; import { FiatUnit } from '../../models/fiatUnit';
jest.setTimeout(30 * 1000); jest.setTimeout(90 * 1000);
describe('currency', () => { describe('currency', () => {
it('fetches exchange rate and saves to AsyncStorage', async () => { it('fetches exchange rate and saves to AsyncStorage', async () => {

View file

@ -10,7 +10,7 @@ const bitcoin = require('bitcoinjs-lib');
const ecc = require('tiny-secp256k1'); const ecc = require('tiny-secp256k1');
const ECPair = ECPairFactory(ecc); const ECPair = ECPairFactory(ecc);
jest.setTimeout(30 * 1000); jest.setTimeout(90 * 1000);
afterAll(async () => { afterAll(async () => {
// after all tests we close socket so the test suite can actually terminate // after all tests we close socket so the test suite can actually terminate

View file

@ -3,7 +3,7 @@ import assert from 'assert';
import { HDSegwitBech32Wallet } from '../../class'; import { HDSegwitBech32Wallet } from '../../class';
import * as BlueElectrum from '../../blue_modules/BlueElectrum'; import * as BlueElectrum from '../../blue_modules/BlueElectrum';
jest.setTimeout(30 * 1000); jest.setTimeout(90 * 1000);
afterAll(async () => { afterAll(async () => {
// after all tests we close socket so the test suite can actually terminate // after all tests we close socket so the test suite can actually terminate

View file

@ -98,4 +98,13 @@ describe('Watch only wallet', () => {
assert.strictEqual(w.getTransactions().length, 4); assert.strictEqual(w.getTransactions().length, 4);
assert.ok((await w.getAddressAsync()).startsWith('bc1')); assert.ok((await w.getAddressAsync()).startsWith('bc1'));
}); });
// skipped because its generally rare case
it.skip('can fetch txs for address funded by genesis txs', async () => {
const w = new WatchOnlyWallet();
w.setSecret('37jKPSmbEGwgfacCr2nayn1wTaqMAbA94Z');
await w.fetchBalance();
await w.fetchTransactions();
assert.ok(w.getTransactions().length >= 138);
});
}); });

View file

@ -131,8 +131,15 @@ jest.mock('rn-ldk/lib/module', () => ({}));
jest.mock('rn-ldk/src/index', () => ({})); jest.mock('rn-ldk/src/index', () => ({}));
const realmInstanceMock = { const realmInstanceMock = {
create: function () {},
delete: function () {},
close: function () {}, close: function () {},
write: function () {}, write: function (transactionFn) {
if (typeof transactionFn === 'function') {
// to test if something is not right in Realm transactional database write
transactionFn();
}
},
objectForPrimaryKey: function () { objectForPrimaryKey: function () {
return {}; return {};
}, },
@ -147,6 +154,7 @@ const realmInstanceMock = {
}; };
jest.mock('realm', () => { jest.mock('realm', () => {
return { return {
UpdateMode: { Modified: 1 },
open: jest.fn(() => realmInstanceMock), open: jest.fn(() => realmInstanceMock),
}; };
}); });