Skip to content

Commit 90a451f

Browse files
committed
Merge branch 'main' into fix-witness-proof-endpoints
2 parents 37ed581 + aea0ac3 commit 90a451f

9 files changed

Lines changed: 157 additions & 61 deletions

File tree

demo/midgard-node/pnpm-lock.yaml

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/midgard-node/src/transactions/state-queue/init.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Effect } from "effect";
2-
import { handleSignSubmit } from "../utils.js";
2+
import { ConfirmError, handleSignSubmit, SubmitError } from "../utils.js";
33
import * as SDK from "@al-ft/midgard-sdk";
44
import { AlwaysSucceeds } from "@/services/index.js";
55
import { User } from "@/config.js";
@@ -14,5 +14,17 @@ export const stateQueueInit = Effect.gen(function* () {
1414
stateQueueMintingScript: mintScript,
1515
};
1616
const txBuilder = yield* SDK.Endpoints.initTxProgram(lucid, initParams);
17-
return yield* handleSignSubmit(lucid, txBuilder);
17+
const onSubmitFailure = (err: SubmitError) =>
18+
Effect.gen(function* () {
19+
yield* Effect.logError(`Sumbit tx error: ${err}`);
20+
yield* Effect.fail(err.err);
21+
});
22+
const onConfirmFailure = (err: ConfirmError) =>
23+
Effect.logError(`Confirm tx error: ${err}`);
24+
return yield* handleSignSubmit(
25+
lucid,
26+
txBuilder,
27+
onSubmitFailure,
28+
onConfirmFailure,
29+
);
1830
});

demo/midgard-node/src/transactions/state-queue/merge-to-confirm-state.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ import { findAllSpentAndProducedUTxOs } from "@/utils.js";
1212
import * as SDK from "@al-ft/midgard-sdk";
1313
import { LucidEvolution, Script, fromHex } from "@lucid-evolution/lucid";
1414
import { Effect, Metric } from "effect";
15-
import { fetchFirstBlockTxs, handleSignSubmit } from "../utils.js";
15+
import {
16+
ConfirmError,
17+
fetchFirstBlockTxs,
18+
handleSignSubmit,
19+
SubmitError,
20+
} from "../utils.js";
1621

1722
const mergeBlockCounter = Metric.counter("merge_block_count", {
1823
description: "A counter for tracking merge blocks",
@@ -107,9 +112,19 @@ export const buildAndSubmitMergeTx = (
107112
).pipe(Effect.withSpan("mergeToConfirmedStateProgram"));
108113

109114
// Submit the transaction
110-
yield* handleSignSubmit(lucid, txBuilder).pipe(
111-
Effect.withSpan("handleSignSubmit-merge-tx"),
112-
);
115+
const onSubmitFailure = (err: SubmitError) =>
116+
Effect.gen(function* () {
117+
yield* Effect.logError(`Sumbit tx error: ${err}`);
118+
yield* Effect.fail(err.err);
119+
});
120+
const onConfirmFailure = (err: ConfirmError) =>
121+
Effect.logError(`Confirm tx error: ${err}`);
122+
yield* handleSignSubmit(
123+
lucid,
124+
txBuilder,
125+
onSubmitFailure,
126+
onConfirmFailure,
127+
).pipe(Effect.withSpan("handleSignSubmit-merge-tx"));
113128
yield* Effect.logInfo(
114129
"🔸 Merge transaction submitted, updating the db...",
115130
);

demo/midgard-node/src/transactions/state-queue/reset.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
import { AlwaysSucceeds } from "@/services/index.js";
1111
import { User } from "@/config.js";
1212
import { Effect } from "effect";
13-
import { handleSignSubmit } from "../utils.js";
13+
import { ConfirmError, handleSignSubmit, SubmitError } from "../utils.js";
1414

1515
const collectAndBurnStateQueueNodesProgram = (
1616
lucid: LucidEvolution,
@@ -35,7 +35,19 @@ const collectAndBurnStateQueueNodesProgram = (
3535
.attach.Script(stateQueueSpendingScript)
3636
.attach.Script(stateQueueMintingScript);
3737
const completed = yield* tx.completeProgram();
38-
return yield* handleSignSubmit(lucid, completed);
38+
const onSubmitFailure = (err: SubmitError) =>
39+
Effect.gen(function* () {
40+
yield* Effect.logError(`Sumbit tx error: ${err}`);
41+
yield* Effect.fail(err.err);
42+
});
43+
const onConfirmFailure = (err: ConfirmError) =>
44+
Effect.logError(`Confirm tx error: ${err}`);
45+
return yield* handleSignSubmit(
46+
lucid,
47+
completed,
48+
onSubmitFailure,
49+
onConfirmFailure,
50+
);
3951
});
4052

4153
export const resetStateQueue = Effect.gen(function* () {

demo/midgard-node/src/transactions/utils.ts

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
UTxO,
77
fromHex,
88
} from "@lucid-evolution/lucid";
9-
import { Effect, Schedule } from "effect";
9+
import { Data, Effect, pipe, Schedule } from "effect";
1010
import * as BlocksDB from "../database/blocks.js";
1111
import * as ImmutableDB from "../database/immutable.js";
1212
import { Database } from "@/services/database.js";
@@ -21,26 +21,47 @@ import { Database } from "@/services/database.js";
2121
export const handleSignSubmit = (
2222
lucid: LucidEvolution,
2323
signBuilder: TxSignBuilder,
24-
): Effect.Effect<string, Error> =>
24+
onSubmitFailure: (error: SubmitError) => Effect.Effect<void, Error>,
25+
onConfirmFailure: (error: ConfirmError) => Effect.Effect<void, Error>,
26+
): Effect.Effect<string | void, Error> =>
2527
Effect.gen(function* () {
26-
const signed = yield* signBuilder.sign.withWallet().completeProgram();
28+
const signed = yield* signBuilder.sign
29+
.withWallet()
30+
.completeProgram()
31+
.pipe(Effect.mapError((err) => new SignError({ err })));
2732
yield* Effect.logInfo("✉️ Submitting transaction...");
28-
const txHash = yield* signed
29-
.submitProgram()
30-
.pipe(
31-
Effect.retry(
32-
Schedule.compose(Schedule.exponential(5_000), Schedule.recurs(5)),
33-
),
34-
);
33+
const txHash = yield* signed.submitProgram().pipe(
34+
Effect.retry(
35+
Schedule.compose(Schedule.exponential(5_000), Schedule.recurs(5)),
36+
),
37+
Effect.mapError((err) => new SubmitError({ err })),
38+
);
3539
yield* Effect.logInfo(`🚀 Transaction submitted: ${txHash}`);
3640
yield* Effect.logInfo(`⏳ Confirming Transaction...`);
37-
yield* Effect.tryPromise(() => lucid.awaitTx(txHash, 10_000));
41+
yield* Effect.tryPromise({
42+
try: () => lucid.awaitTx(txHash, 10_000),
43+
catch: (err: any) => new ConfirmError({ err, txHash }),
44+
});
3845
yield* Effect.logInfo(`🎉 Transaction confirmed: ${txHash}`);
3946
yield* Effect.logInfo("⌛ Pausing for 10 seconds...");
4047
yield* Effect.sleep("10 seconds");
4148
yield* Effect.logInfo("✅ Pause ended.");
4249
return txHash;
43-
});
50+
}).pipe(
51+
Effect.catchAll((err: HandleSignSubmitError) => {
52+
switch (err._tag) {
53+
case "SubmitError":
54+
return onSubmitFailure(err);
55+
case "ConfirmError":
56+
return onConfirmFailure(err);
57+
case "SignError":
58+
return pipe(
59+
Effect.logError(`Signing tx error: ${err.err}`),
60+
Effect.flatMap(() => Effect.fail(err)),
61+
);
62+
}
63+
}),
64+
);
4465

4566
/**
4667
* Handle the signing and submission of a transaction without waiting for the transaction to be confirmed.
@@ -50,19 +71,46 @@ export const handleSignSubmit = (
5071
*/
5172
export const handleSignSubmitWithoutConfirmation = (
5273
signBuilder: TxSignBuilder,
53-
): Effect.Effect<string, Error> =>
74+
onSubmitFailure: (error: SubmitError) => Effect.Effect<void, Error>,
75+
): Effect.Effect<string | void, Error> =>
5476
Effect.gen(function* () {
55-
const signed = yield* signBuilder.sign.withWallet().completeProgram();
56-
const txHash = yield* signed
57-
.submitProgram()
58-
.pipe(
59-
Effect.retry(
60-
Schedule.compose(Schedule.exponential(5_000), Schedule.recurs(5)),
61-
),
62-
);
77+
const signed = yield* signBuilder.sign
78+
.withWallet()
79+
.completeProgram()
80+
.pipe(Effect.mapError((err) => new SignError({ err })));
81+
const txHash = yield* signed.submitProgram().pipe(
82+
Effect.retry(
83+
Schedule.compose(Schedule.exponential(5_000), Schedule.recurs(5)),
84+
),
85+
Effect.mapError((err) => new SubmitError({ err })),
86+
);
6387
yield* Effect.logDebug(`🚀 Transaction submitted: ${txHash}`);
6488
return txHash;
65-
});
89+
}).pipe(
90+
Effect.catchAll((err: SignError | SubmitError) =>
91+
err._tag === "SubmitError"
92+
? onSubmitFailure(err)
93+
: pipe(
94+
Effect.logError(`Signing tx error: ${err.err}`),
95+
Effect.flatMap(() => Effect.fail(err)),
96+
),
97+
),
98+
);
99+
100+
export type HandleSignSubmitError = SignError | SubmitError | ConfirmError;
101+
102+
export class SignError extends Data.TaggedError("SignError")<{
103+
readonly err: Error;
104+
}> {}
105+
106+
export class SubmitError extends Data.TaggedError("SubmitError")<{
107+
readonly err: Error;
108+
}> {}
109+
110+
export class ConfirmError extends Data.TaggedError("ConfirmError")<{
111+
readonly err: Error;
112+
readonly txHash: string;
113+
}> {}
66114

67115
/**
68116
* Fetch transactions of the first block by querying BlocksDB and ImmutableDB.

demo/midgard-node/src/workers/commit-block-header.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import {
88
} from "@/utils.js";
99
import { makeAlwaysSucceedsServiceFn } from "@/services/always-succeeds.js";
1010
import { BlocksDB, ImmutableDB, MempoolDB } from "@/database/index.js";
11-
import { handleSignSubmit } from "@/transactions/utils.js";
11+
import {
12+
ConfirmError,
13+
handleSignSubmit,
14+
SubmitError,
15+
} from "@/transactions/utils.js";
1216
import { fromHex, toHex } from "@lucid-evolution/lucid";
1317
import * as ETH from "@ethereumjs/mpt";
1418
import * as ETH_UTILS from "@ethereumjs/util";
@@ -22,11 +26,7 @@ const rootKey = ETH.ROOT_DB_KEY;
2226

2327
const wrapper = (
2428
_input: WorkerInput,
25-
): Effect.Effect<
26-
WorkerOutput,
27-
Error,
28-
NodeConfig | User | Database
29-
> =>
29+
): Effect.Effect<WorkerOutput, Error, NodeConfig | User | Database> =>
3030
Effect.gen(function* () {
3131
const nodeConfig = yield* NodeConfig;
3232
const { user: lucid } = yield* User;
@@ -200,9 +200,19 @@ const wrapper = (
200200

201201
// Using sign and submit helper with confirmation so that databases are
202202
// only updated after a successful on-chain registration of the block.
203-
yield* handleSignSubmit(lucid, txBuilder).pipe(
204-
Effect.withSpan("handleSignSubmit-commit-block"),
205-
);
203+
const onSubmitFailure = (err: SubmitError) =>
204+
Effect.gen(function* () {
205+
yield* Effect.logError(`Sumbit tx error: ${err}`);
206+
yield* Effect.fail(err.err);
207+
});
208+
const onConfirmFailure = (err: ConfirmError) =>
209+
Effect.logError(`Confirm tx error: ${err}`);
210+
yield* handleSignSubmit(
211+
lucid,
212+
txBuilder,
213+
onSubmitFailure,
214+
onConfirmFailure,
215+
).pipe(Effect.withSpan("handleSignSubmit-commit-block"));
206216

207217
const batchSize = 100;
208218

@@ -264,9 +274,7 @@ const wrapper = (
264274

265275
return output;
266276
} else {
267-
yield* Effect.logInfo(
268-
"🔹 No transactions were found in MempoolDB",
269-
);
277+
yield* Effect.logInfo("🔹 No transactions were found in MempoolDB");
270278
const output: WorkerOutput = {
271279
txSize: 0,
272280
mempoolTxsCount: 0,

onchain/aiken/lib/midgard/common/utils.ak

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,9 @@ pub fn authentic_value_has_tokens(
258258
}
259259

260260
/// Traverses two lists in parallel, accumulating a value using the provided
261-
/// `with` function. The lists are traversed from right, and the smaller list
262-
/// determines the number of elements traversed.
261+
/// `with` function. The lists are traversed from left to right, stopping after
262+
/// the smaller list's elements are exhausted. However, the `with` function
263+
/// is applied in reverse order (i.e. right to left).
263264
pub fn zip_foldr(
264265
self: List<a>,
265266
bs: List<b>,

technical-spec/2-user-event-protocol/4-withdrawal-order.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ \section{Withdrawal order (L1)}
3232
\item Send min-ADA to the Midgard withdrawal order address, along with the withdrawal order token and the above datum.
3333
\end{enumerate}
3434

35-
\notebox{By adjusting incentives, users can be relieved from producing the withdrawal event utxo on L1 themselves, and rely on operators to take care of this second step.}
35+
\notebox{We could adapt Midgard's incentive structure to encourage operators to perform this second step on L1 on behalf of users, relieving users from this chore during normal protocol operation.}
3636

3737
At the time of the L1 withdrawal order, its \code{inclusion\_time} is set to the sum of the L1 transaction's validity interval upper bound and the \code{event\_wait\_duration} Midgard protocol parameter.
3838
According to Midgard's ledger rules:

technical-spec/3-consensus-protocol/6-settlement-queue.tex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ \subsection{Minting policy}
6262
\item The transaction must burn the Midgard hub oracle NFT.
6363
\item The transaction must Deinit the \code{settlement\_queue} list.
6464
\end{enumerate}
65-
\item[Append Settlement Node.] Append a settlement node to store a merged block's deposits, withdrawals and L2 transaction orders.
65+
\item[Append Settlement Node.] Append a settlement node to store a merged block's deposits, withdrawals and transaction orders.
6666
Conditions:
6767
\begin{enumerate}
6868
\item The transaction must include the Midgard hub oracle NFT in a reference input.
@@ -123,7 +123,7 @@ \subsection{Spending validator}
123123
\item The spent input must be reproduced as a settlement node without a resolution claim.
124124
\item The transaction must include the Midgard hub oracle NFT in a reference input.
125125
\item Let \code{active\_operators}, \code{deposit}, \code{withdrawal}, and \code{tx\_order} be the corresponding policy IDs in the Midgard hub oracle.
126-
\item The transaction must include either a deposit, a withdrawal, or an L2 transaction order as a reference input.
126+
\item The transaction must include either a deposit, a withdrawal, or an transaction order as a reference input.
127127
Let that reference input be \code{unprocessed\_event}.
128128
\item A valid membership proof must be provided, proving that \code{unprocessed\_event} is a member of the corresponding tree in the settlement node.
129129
\item The transaction's time-validity upper bound must be earlier than the resolution claim's \code{resolution\_time}.

0 commit comments

Comments
 (0)