Skip to content

Commit 151dcc7

Browse files
Merge branch 'master' of github.com:bitpay/bitcore
2 parents 5da0b72 + 1ce2f52 commit 151dcc7

File tree

12 files changed

+89
-26
lines changed

12 files changed

+89
-26
lines changed

packages/bitcore-wallet-service/src/lib/chain/btc/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,4 +1013,8 @@ export class BtcChain implements IChain {
10131013
getReserve(server: WalletService, wallet: IWallet, cb: (err?, reserve?: number) => void) {
10141014
return cb(null, 0);
10151015
}
1016+
1017+
refreshTxData(_server: WalletService, txp, _opts, cb) {
1018+
return cb(null, txp);
1019+
}
10161020
}

packages/bitcore-wallet-service/src/lib/chain/eth/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,4 +648,8 @@ export class EthChain implements IChain {
648648
getReserve(server: WalletService, wallet: IWallet, cb: (err?, reserve?: number) => void) {
649649
return cb(null, 0);
650650
}
651+
652+
refreshTxData(_server: WalletService, txp, _opts, cb) {
653+
return cb(null, txp);
654+
}
651655
}

packages/bitcore-wallet-service/src/lib/chain/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export interface IChain {
7373
onCoin(coin: any): INotificationData | null;
7474
onTx(tx: any): INotificationData | null;
7575
getReserve(server: WalletService, wallet: IWallet, cb: (err?, reserve?: number) => void);
76+
refreshTxData(server: WalletService, txp: TxProposal, opts: any, cb);
7677
}
7778

7879
const chains: { [chain: string]: IChain } = {
@@ -222,6 +223,10 @@ class ChainProxy {
222223
getReserve(server: WalletService, wallet: IWallet, cb: (err?, reserve?: number) => void) {
223224
return this.get(wallet.chain).getReserve(server, wallet, cb);
224225
}
226+
227+
refreshTxData(server, txp, opts, cb) {
228+
return this.get(txp.chain).refreshTxData(server, txp, opts, cb);
229+
}
225230
}
226231

227232
export let ChainService = new ChainProxy();

packages/bitcore-wallet-service/src/lib/chain/sol/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,23 @@ export class SolChain implements IChain {
267267
});
268268
}
269269

270+
refreshTxData(server: WalletService, txp, _opts, cb) {
271+
if ((txp.blockHeight || txp.blockHash) && txp.isRepublishEnabled()) {
272+
server._getBlockchainHeight(txp.chain, txp.network, (err, height, hash) => {
273+
if (err) return cb(err);
274+
txp.blockHeight = height;
275+
txp.blockHash = hash;
276+
return cb(null, txp);
277+
});
278+
} else {
279+
return cb(null, txp);
280+
}
281+
}
282+
270283
getReserve(server: WalletService, wallet: IWallet, cb: (err?, reserve?: number) => void) {
271284
return cb(null, 0);
272285
}
286+
273287
getSizeSafetyMargin() {
274288
return 0;
275289
}

packages/bitcore-wallet-service/src/lib/chain/xrp/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,4 +310,8 @@ export class XrpChain implements IChain {
310310
return cb(null, reserve);
311311
});
312312
}
313+
314+
refreshTxData(_server: WalletService, txp, _opts, cb) {
315+
return cb(null, txp);
316+
}
313317
}

packages/bitcore-wallet-service/src/lib/common/defaults.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,10 @@ export const Defaults = {
280280
BALANCE_CACHE_DURATION: 10,
281281

282282
// Cache time for blockchain height (in ms)
283-
// this is actually erased on 'new block' notifications
284-
// so, 30m seems fine
285-
BLOCKHEIGHT_CACHE_TIME: 30 * 60 * 1000,
286-
283+
BLOCKHEIGHT_CACHE_TIME: {
284+
default: 30 * 60 * 1000, // this is erased on 'new block' notifications so, 30m seems fine
285+
sol: 5 * 1000 // 5 seconds - Solana needs to maintain the freshes blockheight to land txs consistently
286+
},
287287
// Cache time fee levels (in ms)
288288
FEE_LEVEL_CACHE_DURATION: 6 * 60 * 1000,
289289

packages/bitcore-wallet-service/src/lib/model/txproposal.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ export interface ITxProposal {
8989
category?: string;
9090
priorityFee?: number;
9191
computeUnits?: number;
92+
refreshOnPublish?: boolean;
93+
prePublishRaw?: string;
9294
}
9395

9496
export class TxProposal {
@@ -168,6 +170,8 @@ export class TxProposal {
168170
category?: string;
169171
priorityFee?: number;
170172
computeUnits?: number;
173+
refreshOnPublish?: boolean;
174+
prePublishRaw?: string;
171175

172176
static create(opts) {
173177
opts = opts || {};
@@ -281,6 +285,8 @@ export class TxProposal {
281285
x.computeUnits = opts.computeUnits;
282286
x.priorityFee = opts.priorityFee;
283287

288+
x.refreshOnPublish = opts.refreshOnPublish;
289+
284290
return x;
285291
}
286292

@@ -367,6 +373,9 @@ export class TxProposal {
367373
x.computeUnits = obj.computeUnits;
368374
x.priorityFee = obj.priorityFee;
369375

376+
x.refreshOnPublish = obj.refreshOnPublish;
377+
x.prePublishRaw = obj.prePublishRaw;
378+
370379
if (x.status == 'broadcasted') {
371380
x.raw = obj.raw;
372381
}
@@ -503,6 +512,10 @@ export class TxProposal {
503512
this.addAction(copayerId, 'reject', reason);
504513
}
505514

515+
isRepublishEnabled() {
516+
return !!this.refreshOnPublish
517+
}
518+
506519
isTemporary() {
507520
return this.status == 'temporary';
508521
}

packages/bitcore-wallet-service/src/lib/pushnotificationsservice.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export class PushNotificationsService {
163163
_sendPushNotifications(notification, cb) {
164164
cb = cb || function() {};
165165

166-
const notifType = _.cloneDeep(PUSHNOTIFICATIONS_TYPES[notification.type]);
166+
const notifType = _.cloneDeep(PUSHNOTIFICATIONS_TYPES[notification?.type]);
167167
if (!notifType) return cb();
168168

169169
if (notification.type === 'NewIncomingTx') {

packages/bitcore-wallet-service/src/lib/server.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2650,11 +2650,12 @@ export class WalletService implements IWalletService {
26502650
return next();
26512651
},
26522652
async next => {
2653-
if (Constants.SVM_CHAINS[wallet.chain.toUpperCase()] && (!opts.blockHeight || !opts.blockHash)) {
2653+
if (Constants.SVM_CHAINS[wallet.chain.toUpperCase()] && !opts.nonceAddress) {
26542654
this._getBlockchainHeight(wallet.chain, wallet.network, (err, height, hash) => {
26552655
if (err) return next(err);
26562656
opts.blockHeight = height;
26572657
opts.blockHash = hash;
2658+
opts.refreshOnPublish = true;
26582659
return next();
26592660
});
26602661
} else {
@@ -2735,7 +2736,8 @@ export class WalletService implements IWalletService {
27352736
category: opts.category,
27362737
fromKeyPair: opts.fromKeyPair,
27372738
priorityFee: opts.priorityFee,
2738-
computeUnits: opts.computeUnits
2739+
computeUnits: opts.computeUnits,
2740+
refreshOnPublish: opts.refreshOnPublish
27392741
};
27402742
txp = TxProposal.create(txOpts);
27412743
next();
@@ -2847,7 +2849,7 @@ export class WalletService implements IWalletService {
28472849
this.storage.fetchTx(this.walletId, opts.txProposalId, (err, txp) => {
28482850
if (err) return cb(err);
28492851
if (!txp) return cb(Errors.TX_NOT_FOUND);
2850-
if (!txp.isTemporary()) return cb(null, txp);
2852+
if (!txp.isTemporary() && !txp.isRepublishEnabled()) return cb(null, txp);
28512853

28522854
const copayer = wallet.getCopayer(this.copayerId);
28532855

@@ -2857,11 +2859,18 @@ export class WalletService implements IWalletService {
28572859
} catch (ex) {
28582860
return cb(ex);
28592861
}
2860-
const signingKey = this._getSigningKey(raw, opts.proposalSignature, copayer.requestPubKeys);
2862+
2863+
let signingKey = this._getSigningKey(raw, opts.proposalSignature, copayer.requestPubKeys);
28612864
if (!signingKey) {
2862-
return cb(new ClientError('Invalid proposal signature'));
2865+
// If the txp has been published previously, we will verify the signature against the previously published raw tx
2866+
if (txp.isRepublishEnabled() && txp.prePublishRaw) {
2867+
raw = txp.prePublishRaw;
2868+
signingKey = this._getSigningKey(raw, opts.proposalSignature, copayer.requestPubKeys);
2869+
}
2870+
if (!signingKey) {
2871+
return cb(new ClientError('Invalid proposal signature'));
2872+
}
28632873
}
2864-
28652874
// Save signature info for other copayers to check
28662875
txp.proposalSignature = opts.proposalSignature;
28672876
if (signingKey.selfSigned) {
@@ -2872,15 +2881,22 @@ export class WalletService implements IWalletService {
28722881
ChainService.checkTxUTXOs(this, txp, opts, err => {
28732882
if (err) return cb(err);
28742883
txp.status = 'pending';
2875-
this.storage.storeTx(this.walletId, txp, err => {
2884+
ChainService.refreshTxData(this, txp, opts, (err, txp) => {
28762885
if (err) return cb(err);
2877-
2878-
this._notifyTxProposalAction('NewTxProposal', txp, () => {
2879-
if (txp.coin == 'bch' && txp.changeAddress) {
2880-
const format = opts.noCashAddr ? 'copay' : 'cashaddr';
2881-
txp.changeAddress.address = BCHAddressTranslator.translate(txp.changeAddress.address, format);
2882-
}
2883-
return cb(null, txp);
2886+
if (txp.isRepublishEnabled() && !txp.prePublishRaw) {
2887+
// We save the original raw transaction for verification on republish
2888+
txp.prePublishRaw = raw;
2889+
}
2890+
this.storage.storeTx(this.walletId, txp, err => {
2891+
if (err) return cb(err);
2892+
const action = txp.isRepublishEnabled() && txp.prePublishRaw ? 'UpdatedTxProposal' : 'NewTxProposal';
2893+
this._notifyTxProposalAction(action, txp, () => {
2894+
if (txp.coin == 'bch' && txp.changeAddress) {
2895+
const format = opts.noCashAddr ? 'copay' : 'cashaddr';
2896+
txp.changeAddress.address = BCHAddressTranslator.translate(txp.changeAddress.address, format);
2897+
}
2898+
return cb(null, txp);
2899+
});
28842900
});
28852901
});
28862902
});
@@ -3142,6 +3158,7 @@ export class WalletService implements IWalletService {
31423158
return cb(err);
31433159
}
31443160
}
3161+
31453162

31463163
const copayer = wallet.getCopayer(this.copayerId);
31473164

@@ -3663,8 +3680,9 @@ export class WalletService implements IWalletService {
36633680

36643681
_getBlockchainHeight(chain, network, cb) {
36653682
const cacheKey = Storage.BCHEIGHT_KEY + ':' + chain + ':' + network;
3683+
const cacheTime = Defaults.BLOCKHEIGHT_CACHE_TIME[chain.toLowerCase()] || Defaults.BLOCKHEIGHT_CACHE_TIME.default;
36663684

3667-
this.storage.checkAndUseGlobalCache(cacheKey, Defaults.BLOCKHEIGHT_CACHE_TIME, (err, values) => {
3685+
this.storage.checkAndUseGlobalCache(cacheKey, cacheTime, (err, values) => {
36683686
if (err) return cb(err);
36693687

36703688
if (values) return cb(null, values.current, values.hash, true);

packages/bitcore-wallet-service/test/integration/history.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,11 @@ describe('History', function() {
382382

383383
it('should get tx history from cache and bc mixed, updating confirmations', function(done) {
384384
var _cache = Defaults.CONFIRMATIONS_TO_START_CACHING;
385-
var _time = Defaults.BLOCKHEIGHT_CACHE_TIME ;
385+
var _time = Defaults.BLOCKHEIGHT_CACHE_TIME.default ;
386386
Defaults.CONFIRMATIONS_TO_START_CACHING = 10;
387387

388388
// remove bc tip cache.
389-
Defaults.BLOCKHEIGHT_CACHE_TIME = 0;
389+
Defaults.BLOCKHEIGHT_CACHE_TIME = { default: 0 };
390390
helpers.stubHistory(50, BCHEIGHT); //(0->49)
391391

392392
// this call is to fill the cache
@@ -405,7 +405,7 @@ describe('History', function() {
405405
tx.confirmations.should.equal(i + heightOffset);
406406
i++;
407407
});
408-
Defaults.BLOCKHEIGHT_CACHE_TIME = _time;
408+
Defaults.BLOCKHEIGHT_CACHE_TIME.default = _time;
409409
Defaults.CONFIRMATIONS_TO_START_CACHING = _cache;
410410
done();
411411
});

0 commit comments

Comments
 (0)