@cogcoin/client 1.1.6 → 1.1.8
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/README.md +2 -2
- package/dist/bitcoind/indexer-daemon.js +29 -79
- package/dist/bitcoind/managed-runtime/bitcoind-runtime.d.ts +20 -0
- package/dist/bitcoind/managed-runtime/bitcoind-runtime.js +74 -0
- package/dist/bitcoind/managed-runtime/bitcoind-status.d.ts +11 -0
- package/dist/bitcoind/managed-runtime/bitcoind-status.js +44 -0
- package/dist/bitcoind/managed-runtime/indexer-runtime.d.ts +15 -0
- package/dist/bitcoind/managed-runtime/indexer-runtime.js +82 -0
- package/dist/bitcoind/managed-runtime/types.d.ts +40 -0
- package/dist/bitcoind/node.d.ts +2 -2
- package/dist/bitcoind/node.js +2 -2
- package/dist/bitcoind/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +53 -3
- package/dist/bitcoind/service.js +47 -127
- package/dist/cli/command-registry.d.ts +1 -1
- package/dist/cli/command-registry.js +2 -64
- package/dist/cli/commands/client-admin.js +3 -18
- package/dist/cli/commands/mining-runtime.js +4 -60
- package/dist/cli/commands/wallet-admin.js +6 -6
- package/dist/cli/context.js +1 -3
- package/dist/cli/mining-json.d.ts +1 -22
- package/dist/cli/mining-json.js +0 -23
- package/dist/cli/output.js +16 -2
- package/dist/cli/parse.js +0 -2
- package/dist/cli/preview-json.d.ts +1 -22
- package/dist/cli/preview-json.js +0 -19
- package/dist/cli/types.d.ts +1 -3
- package/dist/cli/wallet-format.js +1 -1
- package/dist/cli/workflow-hints.d.ts +1 -2
- package/dist/cli/workflow-hints.js +5 -8
- package/dist/wallet/lifecycle/context.js +0 -1
- package/dist/wallet/lifecycle/repair-mining.d.ts +1 -5
- package/dist/wallet/lifecycle/repair-mining.js +5 -39
- package/dist/wallet/lifecycle/repair.js +0 -3
- package/dist/wallet/lifecycle/setup.js +10 -8
- package/dist/wallet/lifecycle/types.d.ts +1 -4
- package/dist/wallet/managed-core-wallet.d.ts +2 -0
- package/dist/wallet/managed-core-wallet.js +27 -1
- package/dist/wallet/mining/candidate.d.ts +1 -0
- package/dist/wallet/mining/candidate.js +38 -6
- package/dist/wallet/mining/competitiveness.d.ts +1 -0
- package/dist/wallet/mining/competitiveness.js +6 -0
- package/dist/wallet/mining/cycle.d.ts +2 -0
- package/dist/wallet/mining/cycle.js +14 -4
- package/dist/wallet/mining/engine-state.js +10 -0
- package/dist/wallet/mining/engine-types.d.ts +1 -0
- package/dist/wallet/mining/index.d.ts +1 -1
- package/dist/wallet/mining/index.js +1 -1
- package/dist/wallet/mining/publish.d.ts +3 -0
- package/dist/wallet/mining/publish.js +78 -6
- package/dist/wallet/mining/runner.d.ts +0 -32
- package/dist/wallet/mining/runner.js +59 -104
- package/dist/wallet/mining/stop.d.ts +7 -0
- package/dist/wallet/mining/stop.js +23 -0
- package/dist/wallet/mining/supervisor.d.ts +2 -36
- package/dist/wallet/mining/supervisor.js +139 -246
- package/dist/wallet/mining/visualizer-sync.js +79 -15
- package/dist/wallet/read/context.d.ts +1 -5
- package/dist/wallet/read/context.js +21 -205
- package/dist/wallet/read/managed-services.d.ts +33 -0
- package/dist/wallet/read/managed-services.js +222 -0
- package/dist/wallet/reset/artifacts.d.ts +16 -0
- package/dist/wallet/reset/artifacts.js +141 -0
- package/dist/wallet/reset/execution.d.ts +38 -0
- package/dist/wallet/reset/execution.js +458 -0
- package/dist/wallet/reset/preflight.d.ts +7 -0
- package/dist/wallet/reset/preflight.js +116 -0
- package/dist/wallet/reset/preview.d.ts +2 -0
- package/dist/wallet/reset/preview.js +50 -0
- package/dist/wallet/reset/process-cleanup.d.ts +12 -0
- package/dist/wallet/reset/process-cleanup.js +179 -0
- package/dist/wallet/reset/types.d.ts +189 -0
- package/dist/wallet/reset/types.js +1 -0
- package/dist/wallet/reset.d.ts +4 -119
- package/dist/wallet/reset.js +4 -882
- package/dist/wallet/state/client-password/bootstrap.d.ts +2 -0
- package/dist/wallet/state/client-password/bootstrap.js +3 -0
- package/dist/wallet/state/client-password/context.d.ts +10 -0
- package/dist/wallet/state/client-password/context.js +46 -0
- package/dist/wallet/state/client-password/crypto.d.ts +34 -0
- package/dist/wallet/state/client-password/crypto.js +117 -0
- package/dist/wallet/state/client-password/files.d.ts +10 -0
- package/dist/wallet/state/client-password/files.js +109 -0
- package/dist/wallet/state/client-password/legacy-cleanup.d.ts +11 -0
- package/dist/wallet/state/client-password/legacy-cleanup.js +338 -0
- package/dist/wallet/state/client-password/messages.d.ts +3 -0
- package/dist/wallet/state/client-password/messages.js +9 -0
- package/dist/wallet/state/client-password/migration.d.ts +4 -0
- package/dist/wallet/state/client-password/migration.js +32 -0
- package/dist/wallet/state/client-password/prompts.d.ts +12 -0
- package/dist/wallet/state/client-password/prompts.js +79 -0
- package/dist/wallet/state/client-password/protected-secrets.d.ts +13 -0
- package/dist/wallet/state/client-password/protected-secrets.js +90 -0
- package/dist/wallet/state/client-password/readiness.d.ts +4 -0
- package/dist/wallet/state/client-password/readiness.js +48 -0
- package/dist/wallet/state/client-password/references.d.ts +1 -0
- package/dist/wallet/state/client-password/references.js +56 -0
- package/dist/wallet/state/client-password/rotation.d.ts +6 -0
- package/dist/wallet/state/client-password/rotation.js +98 -0
- package/dist/wallet/state/client-password/session-policy.d.ts +6 -0
- package/dist/wallet/state/client-password/session-policy.js +28 -0
- package/dist/wallet/state/client-password/session.d.ts +19 -0
- package/dist/wallet/state/client-password/session.js +170 -0
- package/dist/wallet/state/client-password/setup.d.ts +8 -0
- package/dist/wallet/state/client-password/setup.js +49 -0
- package/dist/wallet/state/client-password/types.d.ts +82 -0
- package/dist/wallet/state/client-password/types.js +5 -0
- package/dist/wallet/state/client-password.d.ts +7 -38
- package/dist/wallet/state/client-password.js +52 -937
- package/dist/wallet/tx/anchor.js +123 -216
- package/dist/wallet/tx/cog.js +294 -489
- package/dist/wallet/tx/common.d.ts +2 -0
- package/dist/wallet/tx/common.js +2 -0
- package/dist/wallet/tx/domain-admin.js +111 -220
- package/dist/wallet/tx/domain-market.js +401 -681
- package/dist/wallet/tx/executor.d.ts +176 -0
- package/dist/wallet/tx/executor.js +302 -0
- package/dist/wallet/tx/field.js +109 -215
- package/dist/wallet/tx/register.js +158 -269
- package/dist/wallet/tx/reputation.js +120 -227
- package/package.json +1 -1
- package/dist/wallet/mining/worker-main.d.ts +0 -1
- package/dist/wallet/mining/worker-main.js +0 -17
- package/dist/wallet/state/client-password-agent.d.ts +0 -1
- package/dist/wallet/state/client-password-agent.js +0 -211
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
|
|
2
|
+
import { createRpcClient } from "../../bitcoind/node.js";
|
|
3
|
+
import { openWalletReadContext, type WalletReadContext } from "../read/index.js";
|
|
4
|
+
import { type WalletRuntimePaths } from "../runtime.js";
|
|
5
|
+
import { type WalletSecretProvider } from "../state/provider.js";
|
|
6
|
+
import type { PendingMutationRecord, PendingMutationStatus, WalletStateV1 } from "../types.js";
|
|
7
|
+
import { type BuiltWalletMutationTransaction, type FixedWalletInput, type WalletMutationFeeSelection, type WalletMutationFeeSummary, type WalletMutationRpcClient } from "./common.js";
|
|
8
|
+
export interface WalletMutationExecutionContext<TRpc extends WalletMutationRpcClient> {
|
|
9
|
+
provider: WalletSecretProvider;
|
|
10
|
+
nowUnixMs: number;
|
|
11
|
+
paths: WalletRuntimePaths;
|
|
12
|
+
readContext: WalletReadContext;
|
|
13
|
+
rpc: TRpc;
|
|
14
|
+
walletName: string;
|
|
15
|
+
feeSelection: WalletMutationFeeSelection;
|
|
16
|
+
}
|
|
17
|
+
export interface WalletMutationExecutionResult<TResult, TBuilt extends BuiltWalletMutationTransaction = BuiltWalletMutationTransaction> {
|
|
18
|
+
result: TResult;
|
|
19
|
+
state: WalletStateV1;
|
|
20
|
+
mutation: PendingMutationRecord | null;
|
|
21
|
+
built: TBuilt | null;
|
|
22
|
+
reusedExisting: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface WalletMutationReconcileResult {
|
|
25
|
+
state: WalletStateV1;
|
|
26
|
+
mutation: PendingMutationRecord;
|
|
27
|
+
resolution: "confirmed" | "live" | "repair-required" | "not-seen" | "continue";
|
|
28
|
+
}
|
|
29
|
+
export interface WalletMutationPublishResult {
|
|
30
|
+
state: WalletStateV1;
|
|
31
|
+
mutation: PendingMutationRecord;
|
|
32
|
+
status: PendingMutationStatus;
|
|
33
|
+
}
|
|
34
|
+
export interface WalletMutationPublishRpcClient extends Pick<WalletMutationRpcClient, "lockUnspent"> {
|
|
35
|
+
getBlockchainInfo(): Promise<{
|
|
36
|
+
blocks: number;
|
|
37
|
+
}>;
|
|
38
|
+
sendRawTransaction(hex: string): Promise<string>;
|
|
39
|
+
}
|
|
40
|
+
export interface WalletMutationRuntimeOptions<TRpc extends WalletMutationRpcClient> {
|
|
41
|
+
dataDir: string;
|
|
42
|
+
databasePath: string;
|
|
43
|
+
provider?: WalletSecretProvider;
|
|
44
|
+
nowUnixMs?: number;
|
|
45
|
+
paths?: WalletRuntimePaths;
|
|
46
|
+
feeRateSatVb?: number | null;
|
|
47
|
+
openReadContext?: typeof openWalletReadContext;
|
|
48
|
+
attachService?: typeof attachOrStartManagedBitcoindService;
|
|
49
|
+
rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => TRpc;
|
|
50
|
+
}
|
|
51
|
+
export interface WalletMutationOperationSpec<TOperation extends {
|
|
52
|
+
state: WalletStateV1;
|
|
53
|
+
}, TRpc extends WalletMutationRpcClient, TPrepared, TBuilt extends BuiltWalletMutationTransaction, TResult> {
|
|
54
|
+
controlLockPurpose: string;
|
|
55
|
+
preemptionReason: string;
|
|
56
|
+
resolveOperation(readContext: WalletReadContext): Promise<TOperation> | TOperation;
|
|
57
|
+
createIntentFingerprint(operation: TOperation): string;
|
|
58
|
+
resolveExistingMutation?(options: {
|
|
59
|
+
operation: TOperation;
|
|
60
|
+
existingMutation: PendingMutationRecord | null;
|
|
61
|
+
execution: WalletMutationExecutionContext<TRpc>;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
state: WalletStateV1;
|
|
64
|
+
replacementFixedInputs: FixedWalletInput[] | null;
|
|
65
|
+
result: TResult | null;
|
|
66
|
+
}>;
|
|
67
|
+
confirm(options: {
|
|
68
|
+
operation: TOperation;
|
|
69
|
+
existingMutation: PendingMutationRecord | null;
|
|
70
|
+
execution: WalletMutationExecutionContext<TRpc>;
|
|
71
|
+
}): Promise<void>;
|
|
72
|
+
createDraftMutation(options: {
|
|
73
|
+
operation: TOperation;
|
|
74
|
+
existingMutation: PendingMutationRecord | null;
|
|
75
|
+
execution: WalletMutationExecutionContext<TRpc>;
|
|
76
|
+
intentFingerprintHex: string;
|
|
77
|
+
}): Promise<{
|
|
78
|
+
mutation: PendingMutationRecord;
|
|
79
|
+
prepared: TPrepared;
|
|
80
|
+
}> | {
|
|
81
|
+
mutation: PendingMutationRecord;
|
|
82
|
+
prepared: TPrepared;
|
|
83
|
+
};
|
|
84
|
+
prepareBuildState?(options: {
|
|
85
|
+
operation: TOperation;
|
|
86
|
+
state: WalletStateV1;
|
|
87
|
+
execution: WalletMutationExecutionContext<TRpc>;
|
|
88
|
+
existingMutation: PendingMutationRecord | null;
|
|
89
|
+
prepared: TPrepared;
|
|
90
|
+
}): Promise<WalletStateV1>;
|
|
91
|
+
build(options: {
|
|
92
|
+
operation: TOperation;
|
|
93
|
+
state: WalletStateV1;
|
|
94
|
+
execution: WalletMutationExecutionContext<TRpc>;
|
|
95
|
+
replacementFixedInputs: FixedWalletInput[] | null;
|
|
96
|
+
existingMutation: PendingMutationRecord | null;
|
|
97
|
+
prepared: TPrepared;
|
|
98
|
+
}): Promise<TBuilt>;
|
|
99
|
+
beforePublish?(options: {
|
|
100
|
+
operation: TOperation;
|
|
101
|
+
state: WalletStateV1;
|
|
102
|
+
execution: WalletMutationExecutionContext<TRpc>;
|
|
103
|
+
built: TBuilt;
|
|
104
|
+
mutation: PendingMutationRecord;
|
|
105
|
+
prepared: TPrepared;
|
|
106
|
+
}): Promise<void>;
|
|
107
|
+
publish(options: {
|
|
108
|
+
operation: TOperation;
|
|
109
|
+
state: WalletStateV1;
|
|
110
|
+
execution: WalletMutationExecutionContext<TRpc>;
|
|
111
|
+
built: TBuilt;
|
|
112
|
+
mutation: PendingMutationRecord;
|
|
113
|
+
prepared: TPrepared;
|
|
114
|
+
}): Promise<WalletMutationPublishResult>;
|
|
115
|
+
createResult(options: {
|
|
116
|
+
operation: TOperation;
|
|
117
|
+
state: WalletStateV1;
|
|
118
|
+
mutation: PendingMutationRecord;
|
|
119
|
+
execution: WalletMutationExecutionContext<TRpc>;
|
|
120
|
+
built: TBuilt | null;
|
|
121
|
+
status: PendingMutationStatus;
|
|
122
|
+
reusedExisting: boolean;
|
|
123
|
+
fees: WalletMutationFeeSummary;
|
|
124
|
+
prepared: TPrepared | null;
|
|
125
|
+
}): TResult;
|
|
126
|
+
}
|
|
127
|
+
export declare function persistWalletMutationState(options: {
|
|
128
|
+
state: WalletStateV1;
|
|
129
|
+
provider: WalletSecretProvider;
|
|
130
|
+
nowUnixMs: number;
|
|
131
|
+
paths: WalletRuntimePaths;
|
|
132
|
+
}): Promise<WalletStateV1>;
|
|
133
|
+
export declare function resolveExistingWalletMutation<TRpc extends Pick<WalletMutationRpcClient, "getMempoolEntry" | "getTransaction" | "getRawTransaction">, TResult>(options: {
|
|
134
|
+
existingMutation: PendingMutationRecord | null;
|
|
135
|
+
execution: {
|
|
136
|
+
rpc: TRpc;
|
|
137
|
+
walletName: string;
|
|
138
|
+
feeSelection: WalletMutationFeeSelection;
|
|
139
|
+
};
|
|
140
|
+
repairRequiredErrorCode: string;
|
|
141
|
+
reconcileExistingMutation(existingMutation: PendingMutationRecord): Promise<WalletMutationReconcileResult>;
|
|
142
|
+
createReuseResult(options: {
|
|
143
|
+
mutation: PendingMutationRecord;
|
|
144
|
+
resolution: "confirmed" | "live";
|
|
145
|
+
fees: WalletMutationFeeSummary;
|
|
146
|
+
}): TResult;
|
|
147
|
+
}): Promise<{
|
|
148
|
+
state: WalletStateV1;
|
|
149
|
+
replacementFixedInputs: FixedWalletInput[] | null;
|
|
150
|
+
result: TResult | null;
|
|
151
|
+
}>;
|
|
152
|
+
export declare function publishWalletMutation<TRpc extends WalletMutationPublishRpcClient>(options: {
|
|
153
|
+
rpc: TRpc;
|
|
154
|
+
walletName: string;
|
|
155
|
+
snapshotHeight: number | null;
|
|
156
|
+
built: BuiltWalletMutationTransaction;
|
|
157
|
+
mutation: PendingMutationRecord;
|
|
158
|
+
state: WalletStateV1;
|
|
159
|
+
provider: WalletSecretProvider;
|
|
160
|
+
nowUnixMs: number;
|
|
161
|
+
paths: WalletRuntimePaths;
|
|
162
|
+
errorPrefix: string;
|
|
163
|
+
afterAccepted?(options: {
|
|
164
|
+
state: WalletStateV1;
|
|
165
|
+
broadcastingMutation: PendingMutationRecord;
|
|
166
|
+
built: BuiltWalletMutationTransaction;
|
|
167
|
+
nowUnixMs: number;
|
|
168
|
+
}): Promise<{
|
|
169
|
+
state: WalletStateV1;
|
|
170
|
+
mutation: PendingMutationRecord;
|
|
171
|
+
status: PendingMutationStatus;
|
|
172
|
+
}>;
|
|
173
|
+
}): Promise<WalletMutationPublishResult>;
|
|
174
|
+
export declare function executeWalletMutationOperation<TOperation extends {
|
|
175
|
+
state: WalletStateV1;
|
|
176
|
+
}, TRpc extends WalletMutationRpcClient, TPrepared, TBuilt extends BuiltWalletMutationTransaction, TResult>(options: WalletMutationRuntimeOptions<TRpc> & WalletMutationOperationSpec<TOperation, TRpc, TPrepared, TBuilt, TResult>): Promise<WalletMutationExecutionResult<TResult, TBuilt>>;
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
|
|
2
|
+
import { createRpcClient } from "../../bitcoind/node.js";
|
|
3
|
+
import { acquireFileLock } from "../fs/lock.js";
|
|
4
|
+
import { openWalletReadContext, } from "../read/index.js";
|
|
5
|
+
import { resolveWalletRuntimePathsForTesting, } from "../runtime.js";
|
|
6
|
+
import { createDefaultWalletSecretProvider, } from "../state/provider.js";
|
|
7
|
+
import { createBuiltWalletMutationFeeSummary, isAlreadyAcceptedError, isBroadcastUnknownError, pauseMiningForWalletMutation, resolvePendingMutationReuseDecision, resolveWalletMutationFeeSelection, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
8
|
+
import { findPendingMutationByIntent, upsertPendingMutation, } from "./journal.js";
|
|
9
|
+
export async function persistWalletMutationState(options) {
|
|
10
|
+
const nextState = {
|
|
11
|
+
...options.state,
|
|
12
|
+
stateRevision: options.state.stateRevision + 1,
|
|
13
|
+
lastWrittenAtUnixMs: options.nowUnixMs,
|
|
14
|
+
};
|
|
15
|
+
await saveWalletStatePreservingUnlock({
|
|
16
|
+
state: nextState,
|
|
17
|
+
provider: options.provider,
|
|
18
|
+
nowUnixMs: options.nowUnixMs,
|
|
19
|
+
paths: options.paths,
|
|
20
|
+
});
|
|
21
|
+
return nextState;
|
|
22
|
+
}
|
|
23
|
+
export async function resolveExistingWalletMutation(options) {
|
|
24
|
+
if (options.existingMutation === null) {
|
|
25
|
+
throw new Error("wallet_mutation_existing_required");
|
|
26
|
+
}
|
|
27
|
+
const reconciled = await options.reconcileExistingMutation(options.existingMutation);
|
|
28
|
+
if (reconciled.resolution === "repair-required") {
|
|
29
|
+
throw new Error(options.repairRequiredErrorCode);
|
|
30
|
+
}
|
|
31
|
+
if (reconciled.resolution !== "confirmed" && reconciled.resolution !== "live") {
|
|
32
|
+
return {
|
|
33
|
+
state: reconciled.state,
|
|
34
|
+
replacementFixedInputs: null,
|
|
35
|
+
result: null,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const reuse = await resolvePendingMutationReuseDecision({
|
|
39
|
+
rpc: options.execution.rpc,
|
|
40
|
+
walletName: options.execution.walletName,
|
|
41
|
+
mutation: reconciled.mutation,
|
|
42
|
+
nextFeeSelection: options.execution.feeSelection,
|
|
43
|
+
});
|
|
44
|
+
if (reuse.reuseExisting) {
|
|
45
|
+
return {
|
|
46
|
+
state: reconciled.state,
|
|
47
|
+
replacementFixedInputs: null,
|
|
48
|
+
result: options.createReuseResult({
|
|
49
|
+
mutation: reconciled.mutation,
|
|
50
|
+
resolution: reconciled.resolution,
|
|
51
|
+
fees: reuse.fees,
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
state: reconciled.state,
|
|
57
|
+
replacementFixedInputs: reuse.replacementFixedInputs,
|
|
58
|
+
result: null,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export async function publishWalletMutation(options) {
|
|
62
|
+
let nextState = options.state;
|
|
63
|
+
const broadcastingMutation = updateMutationRecord(options.mutation, "broadcasting", options.nowUnixMs, {
|
|
64
|
+
attemptedTxid: options.built.txid,
|
|
65
|
+
attemptedWtxid: options.built.wtxid,
|
|
66
|
+
temporaryBuilderLockedOutpoints: options.built.temporaryBuilderLockedOutpoints,
|
|
67
|
+
});
|
|
68
|
+
nextState = await persistWalletMutationState({
|
|
69
|
+
state: upsertPendingMutation(nextState, broadcastingMutation),
|
|
70
|
+
provider: options.provider,
|
|
71
|
+
nowUnixMs: options.nowUnixMs,
|
|
72
|
+
paths: options.paths,
|
|
73
|
+
});
|
|
74
|
+
if (options.snapshotHeight !== null
|
|
75
|
+
&& options.snapshotHeight !== (await options.rpc.getBlockchainInfo()).blocks) {
|
|
76
|
+
await unlockTemporaryBuilderLocks(options.rpc, options.walletName, options.built.temporaryBuilderLockedOutpoints);
|
|
77
|
+
throw new Error(`${options.errorPrefix}_tip_mismatch`);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
await options.rpc.sendRawTransaction(options.built.rawHex);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (!isAlreadyAcceptedError(error)) {
|
|
84
|
+
if (isBroadcastUnknownError(error)) {
|
|
85
|
+
const unknownMutation = updateMutationRecord(broadcastingMutation, "broadcast-unknown", options.nowUnixMs, {
|
|
86
|
+
attemptedTxid: options.built.txid,
|
|
87
|
+
attemptedWtxid: options.built.wtxid,
|
|
88
|
+
temporaryBuilderLockedOutpoints: options.built.temporaryBuilderLockedOutpoints,
|
|
89
|
+
});
|
|
90
|
+
nextState = await persistWalletMutationState({
|
|
91
|
+
state: upsertPendingMutation(nextState, unknownMutation),
|
|
92
|
+
provider: options.provider,
|
|
93
|
+
nowUnixMs: options.nowUnixMs,
|
|
94
|
+
paths: options.paths,
|
|
95
|
+
});
|
|
96
|
+
throw new Error(`${options.errorPrefix}_broadcast_unknown`);
|
|
97
|
+
}
|
|
98
|
+
await unlockTemporaryBuilderLocks(options.rpc, options.walletName, options.built.temporaryBuilderLockedOutpoints);
|
|
99
|
+
const canceledMutation = updateMutationRecord(broadcastingMutation, "canceled", options.nowUnixMs, {
|
|
100
|
+
attemptedTxid: options.built.txid,
|
|
101
|
+
attemptedWtxid: options.built.wtxid,
|
|
102
|
+
temporaryBuilderLockedOutpoints: [],
|
|
103
|
+
});
|
|
104
|
+
nextState = await persistWalletMutationState({
|
|
105
|
+
state: upsertPendingMutation(nextState, canceledMutation),
|
|
106
|
+
provider: options.provider,
|
|
107
|
+
nowUnixMs: options.nowUnixMs,
|
|
108
|
+
paths: options.paths,
|
|
109
|
+
});
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
await unlockTemporaryBuilderLocks(options.rpc, options.walletName, options.built.temporaryBuilderLockedOutpoints);
|
|
114
|
+
const accepted = options.afterAccepted === undefined
|
|
115
|
+
? {
|
|
116
|
+
state: upsertPendingMutation(nextState, updateMutationRecord(broadcastingMutation, "live", options.nowUnixMs, {
|
|
117
|
+
attemptedTxid: options.built.txid,
|
|
118
|
+
attemptedWtxid: options.built.wtxid,
|
|
119
|
+
temporaryBuilderLockedOutpoints: [],
|
|
120
|
+
})),
|
|
121
|
+
mutation: updateMutationRecord(broadcastingMutation, "live", options.nowUnixMs, {
|
|
122
|
+
attemptedTxid: options.built.txid,
|
|
123
|
+
attemptedWtxid: options.built.wtxid,
|
|
124
|
+
temporaryBuilderLockedOutpoints: [],
|
|
125
|
+
}),
|
|
126
|
+
status: "live",
|
|
127
|
+
}
|
|
128
|
+
: await options.afterAccepted({
|
|
129
|
+
state: nextState,
|
|
130
|
+
broadcastingMutation,
|
|
131
|
+
built: options.built,
|
|
132
|
+
nowUnixMs: options.nowUnixMs,
|
|
133
|
+
});
|
|
134
|
+
const persistedState = await persistWalletMutationState({
|
|
135
|
+
state: accepted.state,
|
|
136
|
+
provider: options.provider,
|
|
137
|
+
nowUnixMs: options.nowUnixMs,
|
|
138
|
+
paths: options.paths,
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
state: persistedState,
|
|
142
|
+
mutation: accepted.mutation,
|
|
143
|
+
status: accepted.status,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
export async function executeWalletMutationOperation(options) {
|
|
147
|
+
const provider = options.provider ?? createDefaultWalletSecretProvider();
|
|
148
|
+
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
149
|
+
const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
|
|
150
|
+
const controlLock = await acquireFileLock(paths.walletControlLockPath, {
|
|
151
|
+
purpose: options.controlLockPurpose,
|
|
152
|
+
walletRootId: null,
|
|
153
|
+
});
|
|
154
|
+
try {
|
|
155
|
+
const miningPreemption = await pauseMiningForWalletMutation({
|
|
156
|
+
paths,
|
|
157
|
+
reason: options.preemptionReason,
|
|
158
|
+
});
|
|
159
|
+
const readContext = await (options.openReadContext ?? openWalletReadContext)({
|
|
160
|
+
dataDir: options.dataDir,
|
|
161
|
+
databasePath: options.databasePath,
|
|
162
|
+
secretProvider: provider,
|
|
163
|
+
walletControlLockHeld: true,
|
|
164
|
+
paths,
|
|
165
|
+
});
|
|
166
|
+
try {
|
|
167
|
+
const operation = await options.resolveOperation(readContext);
|
|
168
|
+
const node = await (options.attachService ?? attachOrStartManagedBitcoindService)({
|
|
169
|
+
dataDir: options.dataDir,
|
|
170
|
+
chain: "main",
|
|
171
|
+
startHeight: 0,
|
|
172
|
+
walletRootId: operation.state.walletRootId,
|
|
173
|
+
});
|
|
174
|
+
const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
|
|
175
|
+
const execution = {
|
|
176
|
+
provider,
|
|
177
|
+
nowUnixMs,
|
|
178
|
+
paths,
|
|
179
|
+
readContext,
|
|
180
|
+
rpc,
|
|
181
|
+
walletName: operation.state.managedCoreWallet.walletName,
|
|
182
|
+
feeSelection: await resolveWalletMutationFeeSelection({
|
|
183
|
+
rpc,
|
|
184
|
+
feeRateSatVb: options.feeRateSatVb ?? null,
|
|
185
|
+
}),
|
|
186
|
+
};
|
|
187
|
+
const intentFingerprintHex = options.createIntentFingerprint(operation);
|
|
188
|
+
const existingMutation = findPendingMutationByIntent(operation.state, intentFingerprintHex);
|
|
189
|
+
let workingState = operation.state;
|
|
190
|
+
let replacementFixedInputs = null;
|
|
191
|
+
if (options.resolveExistingMutation !== undefined) {
|
|
192
|
+
const existingResolution = await options.resolveExistingMutation({
|
|
193
|
+
operation,
|
|
194
|
+
existingMutation,
|
|
195
|
+
execution,
|
|
196
|
+
});
|
|
197
|
+
workingState = existingResolution.state;
|
|
198
|
+
replacementFixedInputs = existingResolution.replacementFixedInputs;
|
|
199
|
+
if (existingResolution.result !== null && existingMutation !== null) {
|
|
200
|
+
return {
|
|
201
|
+
result: existingResolution.result,
|
|
202
|
+
state: workingState,
|
|
203
|
+
mutation: existingMutation,
|
|
204
|
+
built: null,
|
|
205
|
+
reusedExisting: true,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
await options.confirm({
|
|
210
|
+
operation,
|
|
211
|
+
existingMutation,
|
|
212
|
+
execution,
|
|
213
|
+
});
|
|
214
|
+
const draft = await options.createDraftMutation({
|
|
215
|
+
operation,
|
|
216
|
+
existingMutation,
|
|
217
|
+
execution,
|
|
218
|
+
intentFingerprintHex,
|
|
219
|
+
});
|
|
220
|
+
let nextState = upsertPendingMutation(workingState, draft.mutation);
|
|
221
|
+
nextState = await persistWalletMutationState({
|
|
222
|
+
state: nextState,
|
|
223
|
+
provider,
|
|
224
|
+
nowUnixMs,
|
|
225
|
+
paths,
|
|
226
|
+
});
|
|
227
|
+
if (options.prepareBuildState !== undefined) {
|
|
228
|
+
nextState = await options.prepareBuildState({
|
|
229
|
+
operation,
|
|
230
|
+
state: nextState,
|
|
231
|
+
execution,
|
|
232
|
+
existingMutation,
|
|
233
|
+
prepared: draft.prepared,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const currentMutation = nextState.pendingMutations?.find((mutation) => mutation.intentFingerprintHex === intentFingerprintHex);
|
|
237
|
+
if (currentMutation === undefined) {
|
|
238
|
+
throw new Error("wallet_mutation_draft_missing");
|
|
239
|
+
}
|
|
240
|
+
const built = await options.build({
|
|
241
|
+
operation,
|
|
242
|
+
state: nextState,
|
|
243
|
+
execution,
|
|
244
|
+
replacementFixedInputs,
|
|
245
|
+
existingMutation,
|
|
246
|
+
prepared: draft.prepared,
|
|
247
|
+
});
|
|
248
|
+
if (options.beforePublish !== undefined) {
|
|
249
|
+
try {
|
|
250
|
+
await options.beforePublish({
|
|
251
|
+
operation,
|
|
252
|
+
state: nextState,
|
|
253
|
+
execution,
|
|
254
|
+
built,
|
|
255
|
+
mutation: currentMutation,
|
|
256
|
+
prepared: draft.prepared,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
await unlockTemporaryBuilderLocks(execution.rpc, execution.walletName, built.temporaryBuilderLockedOutpoints);
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const published = await options.publish({
|
|
265
|
+
operation,
|
|
266
|
+
state: nextState,
|
|
267
|
+
execution,
|
|
268
|
+
built,
|
|
269
|
+
mutation: currentMutation,
|
|
270
|
+
prepared: draft.prepared,
|
|
271
|
+
});
|
|
272
|
+
const result = options.createResult({
|
|
273
|
+
operation,
|
|
274
|
+
state: published.state,
|
|
275
|
+
mutation: published.mutation,
|
|
276
|
+
execution,
|
|
277
|
+
built,
|
|
278
|
+
status: published.status,
|
|
279
|
+
reusedExisting: false,
|
|
280
|
+
fees: createBuiltWalletMutationFeeSummary({
|
|
281
|
+
selection: execution.feeSelection,
|
|
282
|
+
built,
|
|
283
|
+
}),
|
|
284
|
+
prepared: draft.prepared,
|
|
285
|
+
});
|
|
286
|
+
return {
|
|
287
|
+
result,
|
|
288
|
+
state: published.state,
|
|
289
|
+
mutation: published.mutation,
|
|
290
|
+
built,
|
|
291
|
+
reusedExisting: false,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
finally {
|
|
295
|
+
await readContext.close();
|
|
296
|
+
await miningPreemption.release();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
finally {
|
|
300
|
+
await controlLock.release();
|
|
301
|
+
}
|
|
302
|
+
}
|