opnet 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/browser/_version.d.ts +1 -1
- package/browser/index.js +1 -1
- package/browser/transactions/interfaces/BroadcastedTransaction.d.ts +0 -1
- package/browser/utxos/UTXOsManager.d.ts +5 -8
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/contracts/CallResult.js +1 -1
- package/build/providers/AbstractRpcProvider.js +2 -16
- package/build/transactions/interfaces/BroadcastedTransaction.d.ts +0 -1
- package/build/utxos/UTXOsManager.d.ts +5 -8
- package/build/utxos/UTXOsManager.js +62 -41
- package/package.json +2 -2
- package/src/_version.ts +1 -1
- package/src/contracts/CallResult.ts +5 -1
- package/src/providers/AbstractRpcProvider.ts +2 -18
- package/src/transactions/interfaces/BroadcastedTransaction.ts +0 -5
- package/src/utxos/UTXOsManager.ts +120 -93
|
@@ -3,17 +3,14 @@ import { AbstractRpcProvider } from '../providers/AbstractRpcProvider.js';
|
|
|
3
3
|
import { RequestUTXOsParams, RequestUTXOsParamsWithAmount } from './interfaces/IUTXOsManager.js';
|
|
4
4
|
export declare class UTXOsManager {
|
|
5
5
|
private readonly provider;
|
|
6
|
-
private
|
|
7
|
-
private pendingUTXOs;
|
|
8
|
-
private pendingUtxoDepth;
|
|
9
|
-
private lastCleanup;
|
|
10
|
-
private lastFetchTimestamp;
|
|
11
|
-
private lastFetchedData;
|
|
6
|
+
private dataByAddress;
|
|
12
7
|
constructor(provider: AbstractRpcProvider);
|
|
13
|
-
spentUTXO(spent: UTXOs, newUTXOs: UTXOs): void;
|
|
14
|
-
|
|
8
|
+
spentUTXO(address: string, spent: UTXOs, newUTXOs: UTXOs): void;
|
|
9
|
+
getPendingUTXOs(address: string): UTXOs;
|
|
10
|
+
clean(address?: string): void;
|
|
15
11
|
getUTXOs({ address, optimize, mergePendingUTXOs, filterSpentUTXOs, }: RequestUTXOsParams): Promise<UTXOs>;
|
|
16
12
|
getUTXOsForAmount({ address, amount, optimize, mergePendingUTXOs, filterSpentUTXOs, throwErrors, }: RequestUTXOsParamsWithAmount): Promise<UTXOs>;
|
|
13
|
+
private getAddressData;
|
|
17
14
|
private maybeFetchUTXOs;
|
|
18
15
|
private fetchUTXOs;
|
|
19
16
|
private syncPendingDepthWithFetched;
|
package/build/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "1.4.
|
|
1
|
+
export declare const version = "1.4.2";
|
package/build/_version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.4.
|
|
1
|
+
export const version = '1.4.2';
|
|
@@ -137,7 +137,7 @@ export class CallResult {
|
|
|
137
137
|
if (!tx2.result) {
|
|
138
138
|
throw new Error('No transaction ID returned');
|
|
139
139
|
}
|
|
140
|
-
this.#provider.utxoManager.spentUTXO(UTXOs, transaction.nextUTXOs);
|
|
140
|
+
this.#provider.utxoManager.spentUTXO(interactionParams.refundTo, UTXOs, transaction.nextUTXOs);
|
|
141
141
|
return {
|
|
142
142
|
transactionId: tx2.result,
|
|
143
143
|
peerAcknowledgements: tx2.peers || 0,
|
|
@@ -278,14 +278,7 @@ export class AbstractRpcProvider {
|
|
|
278
278
|
}
|
|
279
279
|
const payload = this.buildJsonRpcPayload(JSONRpcMethods.BROADCAST_TRANSACTION, [tx, psbt]);
|
|
280
280
|
const rawTx = await this.callPayloadSingle(payload);
|
|
281
|
-
|
|
282
|
-
if (result && result.id) {
|
|
283
|
-
return {
|
|
284
|
-
...result,
|
|
285
|
-
id: result.id,
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
return result;
|
|
281
|
+
return rawTx.result;
|
|
289
282
|
}
|
|
290
283
|
async sendRawTransactions(txs) {
|
|
291
284
|
const payloads = txs.map((tx) => {
|
|
@@ -296,14 +289,7 @@ export class AbstractRpcProvider {
|
|
|
296
289
|
throw new Error(`Error sending transactions: ${rawTxs.error}`);
|
|
297
290
|
}
|
|
298
291
|
return rawTxs.map((rawTx) => {
|
|
299
|
-
|
|
300
|
-
if (result && result.id) {
|
|
301
|
-
return {
|
|
302
|
-
...result,
|
|
303
|
-
id: result.id,
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
return result;
|
|
292
|
+
return rawTx.result;
|
|
307
293
|
});
|
|
308
294
|
}
|
|
309
295
|
async getBlockWitness(height = -1, trusted, limit, page) {
|
|
@@ -3,17 +3,14 @@ import { AbstractRpcProvider } from '../providers/AbstractRpcProvider.js';
|
|
|
3
3
|
import { RequestUTXOsParams, RequestUTXOsParamsWithAmount } from './interfaces/IUTXOsManager.js';
|
|
4
4
|
export declare class UTXOsManager {
|
|
5
5
|
private readonly provider;
|
|
6
|
-
private
|
|
7
|
-
private pendingUTXOs;
|
|
8
|
-
private pendingUtxoDepth;
|
|
9
|
-
private lastCleanup;
|
|
10
|
-
private lastFetchTimestamp;
|
|
11
|
-
private lastFetchedData;
|
|
6
|
+
private dataByAddress;
|
|
12
7
|
constructor(provider: AbstractRpcProvider);
|
|
13
|
-
spentUTXO(spent: UTXOs, newUTXOs: UTXOs): void;
|
|
14
|
-
|
|
8
|
+
spentUTXO(address: string, spent: UTXOs, newUTXOs: UTXOs): void;
|
|
9
|
+
getPendingUTXOs(address: string): UTXOs;
|
|
10
|
+
clean(address?: string): void;
|
|
15
11
|
getUTXOs({ address, optimize, mergePendingUTXOs, filterSpentUTXOs, }: RequestUTXOsParams): Promise<UTXOs>;
|
|
16
12
|
getUTXOsForAmount({ address, amount, optimize, mergePendingUTXOs, filterSpentUTXOs, throwErrors, }: RequestUTXOsParamsWithAmount): Promise<UTXOs>;
|
|
13
|
+
private getAddressData;
|
|
17
14
|
private maybeFetchUTXOs;
|
|
18
15
|
private fetchUTXOs;
|
|
19
16
|
private syncPendingDepthWithFetched;
|
|
@@ -5,30 +5,26 @@ const FETCH_COOLDOWN = 10000;
|
|
|
5
5
|
const MEMPOOL_CHAIN_LIMIT = 25;
|
|
6
6
|
export class UTXOsManager {
|
|
7
7
|
provider;
|
|
8
|
-
|
|
9
|
-
pendingUTXOs = [];
|
|
10
|
-
pendingUtxoDepth = {};
|
|
11
|
-
lastCleanup = Date.now();
|
|
12
|
-
lastFetchTimestamp = 0;
|
|
13
|
-
lastFetchedData = null;
|
|
8
|
+
dataByAddress = {};
|
|
14
9
|
constructor(provider) {
|
|
15
10
|
this.provider = provider;
|
|
16
11
|
}
|
|
17
|
-
spentUTXO(spent, newUTXOs) {
|
|
12
|
+
spentUTXO(address, spent, newUTXOs) {
|
|
13
|
+
const addressData = this.getAddressData(address);
|
|
18
14
|
const utxoKey = (u) => `${u.transactionId}:${u.outputIndex}`;
|
|
19
|
-
|
|
15
|
+
addressData.pendingUTXOs = addressData.pendingUTXOs.filter((utxo) => {
|
|
20
16
|
return !spent.some((spentUtxo) => spentUtxo.transactionId === utxo.transactionId &&
|
|
21
17
|
spentUtxo.outputIndex === utxo.outputIndex);
|
|
22
18
|
});
|
|
23
19
|
for (const spentUtxo of spent) {
|
|
24
20
|
const key = utxoKey(spentUtxo);
|
|
25
|
-
delete
|
|
21
|
+
delete addressData.pendingUtxoDepth[key];
|
|
26
22
|
}
|
|
27
|
-
|
|
23
|
+
addressData.spentUTXOs.push(...spent);
|
|
28
24
|
let maxParentDepth = 0;
|
|
29
25
|
for (const spentUtxo of spent) {
|
|
30
26
|
const key = utxoKey(spentUtxo);
|
|
31
|
-
const parentDepth =
|
|
27
|
+
const parentDepth = addressData.pendingUtxoDepth[key] ?? 0;
|
|
32
28
|
if (parentDepth > maxParentDepth) {
|
|
33
29
|
maxParentDepth = parentDepth;
|
|
34
30
|
}
|
|
@@ -38,23 +34,34 @@ export class UTXOsManager {
|
|
|
38
34
|
throw new Error(`too-long-mempool-chain, too many descendants for tx ... [limit: ${MEMPOOL_CHAIN_LIMIT}]`);
|
|
39
35
|
}
|
|
40
36
|
for (const nu of newUTXOs) {
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
addressData.pendingUTXOs.push(nu);
|
|
38
|
+
addressData.pendingUtxoDepth[utxoKey(nu)] = newDepth;
|
|
43
39
|
}
|
|
44
40
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
getPendingUTXOs(address) {
|
|
42
|
+
const addressData = this.getAddressData(address);
|
|
43
|
+
return addressData.pendingUTXOs;
|
|
44
|
+
}
|
|
45
|
+
clean(address) {
|
|
46
|
+
if (address) {
|
|
47
|
+
const addressData = this.getAddressData(address);
|
|
48
|
+
addressData.spentUTXOs = [];
|
|
49
|
+
addressData.pendingUTXOs = [];
|
|
50
|
+
addressData.pendingUtxoDepth = {};
|
|
51
|
+
addressData.lastCleanup = Date.now();
|
|
52
|
+
addressData.lastFetchTimestamp = 0;
|
|
53
|
+
addressData.lastFetchedData = null;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.dataByAddress = {};
|
|
57
|
+
}
|
|
52
58
|
}
|
|
53
59
|
async getUTXOs({ address, optimize = true, mergePendingUTXOs = true, filterSpentUTXOs = true, }) {
|
|
60
|
+
const addressData = this.getAddressData(address);
|
|
54
61
|
const fetchedData = await this.maybeFetchUTXOs(address, optimize);
|
|
55
62
|
const utxoKey = (utxo) => `${utxo.transactionId}:${utxo.outputIndex}`;
|
|
56
|
-
const pendingUTXOKeys = new Set(
|
|
57
|
-
const spentUTXOKeys = new Set(
|
|
63
|
+
const pendingUTXOKeys = new Set(addressData.pendingUTXOs.map(utxoKey));
|
|
64
|
+
const spentUTXOKeys = new Set(addressData.spentUTXOs.map(utxoKey));
|
|
58
65
|
const fetchedSpentKeys = new Set(fetchedData.spentTransactions.map(utxoKey));
|
|
59
66
|
const combinedUTXOs = [];
|
|
60
67
|
const combinedKeysSet = new Set();
|
|
@@ -66,7 +73,7 @@ export class UTXOsManager {
|
|
|
66
73
|
}
|
|
67
74
|
}
|
|
68
75
|
if (mergePendingUTXOs) {
|
|
69
|
-
for (const utxo of
|
|
76
|
+
for (const utxo of addressData.pendingUTXOs) {
|
|
70
77
|
const key = utxoKey(utxo);
|
|
71
78
|
if (!combinedKeysSet.has(key)) {
|
|
72
79
|
combinedUTXOs.push(utxo);
|
|
@@ -108,23 +115,36 @@ export class UTXOsManager {
|
|
|
108
115
|
}
|
|
109
116
|
return utxoUntilAmount;
|
|
110
117
|
}
|
|
118
|
+
getAddressData(address) {
|
|
119
|
+
if (!this.dataByAddress[address]) {
|
|
120
|
+
this.dataByAddress[address] = {
|
|
121
|
+
spentUTXOs: [],
|
|
122
|
+
pendingUTXOs: [],
|
|
123
|
+
pendingUtxoDepth: {},
|
|
124
|
+
lastCleanup: Date.now(),
|
|
125
|
+
lastFetchTimestamp: 0,
|
|
126
|
+
lastFetchedData: null,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return this.dataByAddress[address];
|
|
130
|
+
}
|
|
111
131
|
async maybeFetchUTXOs(address, optimize) {
|
|
132
|
+
const addressData = this.getAddressData(address);
|
|
112
133
|
const now = Date.now();
|
|
113
|
-
const age = now -
|
|
114
|
-
if (now -
|
|
115
|
-
this.clean();
|
|
134
|
+
const age = now - addressData.lastFetchTimestamp;
|
|
135
|
+
if (now - addressData.lastCleanup > AUTO_PURGE_AFTER) {
|
|
136
|
+
this.clean(address);
|
|
116
137
|
}
|
|
117
|
-
if (
|
|
118
|
-
return
|
|
138
|
+
if (addressData.lastFetchedData && age < FETCH_COOLDOWN) {
|
|
139
|
+
return addressData.lastFetchedData;
|
|
119
140
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
this.syncPendingDepthWithFetched();
|
|
123
|
-
return
|
|
141
|
+
addressData.lastFetchedData = await this.fetchUTXOs(address, optimize);
|
|
142
|
+
addressData.lastFetchTimestamp = now;
|
|
143
|
+
this.syncPendingDepthWithFetched(address);
|
|
144
|
+
return addressData.lastFetchedData;
|
|
124
145
|
}
|
|
125
146
|
async fetchUTXOs(address, optimize = false) {
|
|
126
|
-
const
|
|
127
|
-
const payload = this.provider.buildJsonRpcPayload(JSONRpcMethods.GET_UTXOS, [addressStr, optimize]);
|
|
147
|
+
const payload = this.provider.buildJsonRpcPayload(JSONRpcMethods.GET_UTXOS, [address, optimize]);
|
|
128
148
|
const rawUTXOs = await this.provider.callPayloadSingle(payload);
|
|
129
149
|
if ('error' in rawUTXOs) {
|
|
130
150
|
throw new Error(`Error fetching block: ${rawUTXOs.error}`);
|
|
@@ -140,16 +160,17 @@ export class UTXOsManager {
|
|
|
140
160
|
spentTransactions: result.spentTransactions.map((utxo) => new UTXO(utxo)),
|
|
141
161
|
};
|
|
142
162
|
}
|
|
143
|
-
syncPendingDepthWithFetched() {
|
|
144
|
-
|
|
163
|
+
syncPendingDepthWithFetched(address) {
|
|
164
|
+
const addressData = this.getAddressData(address);
|
|
165
|
+
const fetched = addressData.lastFetchedData;
|
|
166
|
+
if (!fetched)
|
|
145
167
|
return;
|
|
146
|
-
}
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
this.pendingUTXOs = this.pendingUTXOs.filter((u) => {
|
|
168
|
+
const confirmedKeys = new Set(fetched.confirmed.map((u) => `${u.transactionId}:${u.outputIndex}`));
|
|
169
|
+
const spentKeys = new Set(fetched.spentTransactions.map((u) => `${u.transactionId}:${u.outputIndex}`));
|
|
170
|
+
addressData.pendingUTXOs = addressData.pendingUTXOs.filter((u) => {
|
|
150
171
|
const key = `${u.transactionId}:${u.outputIndex}`;
|
|
151
172
|
if (confirmedKeys.has(key) || spentKeys.has(key)) {
|
|
152
|
-
delete
|
|
173
|
+
delete addressData.pendingUtxoDepth[key];
|
|
153
174
|
return false;
|
|
154
175
|
}
|
|
155
176
|
return true;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opnet",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.2",
|
|
5
5
|
"author": "OP_NET",
|
|
6
6
|
"description": "The perfect library for building Bitcoin-based applications.",
|
|
7
7
|
"engines": {
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"@bitcoinerlab/secp256k1": "^1.2.0",
|
|
104
104
|
"@btc-vision/bitcoin": "^6.3.6",
|
|
105
105
|
"@btc-vision/bitcoin-rpc": "^1.0.1",
|
|
106
|
-
"@btc-vision/transaction": "^1.
|
|
106
|
+
"@btc-vision/transaction": "^1.4.0",
|
|
107
107
|
"@noble/hashes": "^1.7.1",
|
|
108
108
|
"bignumber.js": "^9.1.2",
|
|
109
109
|
"buffer": "^6.0.3",
|
package/src/_version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.4.
|
|
1
|
+
export const version = '1.4.2';
|
|
@@ -250,7 +250,11 @@ export class CallResult<
|
|
|
250
250
|
throw new Error('No transaction ID returned');
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
this.#provider.utxoManager.spentUTXO(
|
|
253
|
+
this.#provider.utxoManager.spentUTXO(
|
|
254
|
+
interactionParams.refundTo,
|
|
255
|
+
UTXOs,
|
|
256
|
+
transaction.nextUTXOs,
|
|
257
|
+
);
|
|
254
258
|
|
|
255
259
|
return {
|
|
256
260
|
transactionId: tx2.result,
|
|
@@ -586,15 +586,7 @@ export abstract class AbstractRpcProvider {
|
|
|
586
586
|
);
|
|
587
587
|
|
|
588
588
|
const rawTx: JsonRpcResult = await this.callPayloadSingle(payload);
|
|
589
|
-
|
|
590
|
-
if (result && result.id) {
|
|
591
|
-
return {
|
|
592
|
-
...result,
|
|
593
|
-
id: result.id,
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
return result;
|
|
589
|
+
return rawTx.result as BroadcastedTransaction;
|
|
598
590
|
}
|
|
599
591
|
|
|
600
592
|
/**
|
|
@@ -615,15 +607,7 @@ export abstract class AbstractRpcProvider {
|
|
|
615
607
|
}
|
|
616
608
|
|
|
617
609
|
return rawTxs.map((rawTx) => {
|
|
618
|
-
|
|
619
|
-
if (result && result.id) {
|
|
620
|
-
return {
|
|
621
|
-
...result,
|
|
622
|
-
id: result.id,
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
return result;
|
|
610
|
+
return rawTx.result as BroadcastedTransaction;
|
|
627
611
|
});
|
|
628
612
|
}
|
|
629
613
|
|