diff --git a/packages/cli/src/scripts/settlement/deploy.ts b/packages/cli/src/scripts/settlement/deploy.ts index 2d206fb16..14e49c581 100644 --- a/packages/cli/src/scripts/settlement/deploy.ts +++ b/packages/cli/src/scripts/settlement/deploy.ts @@ -1,6 +1,5 @@ import "reflect-metadata"; import { container } from "tsyringe"; -import type { Environment } from "@proto-kit/stack"; import { loadEnvironmentVariables, @@ -11,14 +10,28 @@ import { loadUserModules } from "../../utils/loadUserModules"; export default async function (options: LoadEnvOptions) { try { - const { Provable, PublicKey } = await import("o1js"); + loadEnvironmentVariables(options); + const { Provable, PublicKey, PrivateKey } = await import("o1js"); const { Runtime } = await import("@proto-kit/module"); const { Protocol } = await import("@proto-kit/protocol"); - const { AppChain, Sequencer, SettlementModule, InMemoryDatabase } = - await import("@proto-kit/sequencer"); + const { + AppChain, + Sequencer, + SettlementModule, + InMemoryDatabase, + BatchProducerModule, + BridgingModule, + ConstantFeeStrategy, + InMemoryMinaSigner, + MinaBaseLayer, + PrivateMempool, + LocalTaskQueue, + LocalTaskWorkerModule, + VanillaTaskWorkerModules, + SequencerStartupModule, + } = await import("@proto-kit/sequencer"); - const { DefaultModules, DefaultConfigs } = await import("@proto-kit/stack"); - loadEnvironmentVariables(options); + const { DefaultConfigs } = await import("@proto-kit/stack"); const { runtime, protocol } = await loadUserModules(); const appChain = AppChain.from({ Runtime: Runtime.from(runtime.modules), @@ -28,7 +41,18 @@ export default async function (options: LoadEnvOptions) { }), Sequencer: Sequencer.from({ Database: InMemoryDatabase, - ...DefaultModules.settlementScript(), + BaseLayer: MinaBaseLayer, + FeeStrategy: ConstantFeeStrategy, + BatchProducerModule, + SettlementModule, + SettlementSigner: InMemoryMinaSigner, + BridgingModule, + Mempool: PrivateMempool, + TaskQueue: LocalTaskQueue, + LocalTaskWorker: LocalTaskWorkerModule.from( + VanillaTaskWorkerModules.allTasks() + ), + SequencerStartupModule, }), }); @@ -40,16 +64,46 @@ export default async function (options: LoadEnvOptions) { }, Sequencer: { ...DefaultConfigs.inMemoryDatabase(), - ...DefaultConfigs.settlementScript({ - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - preset: options.env as Environment, - }), + BaseLayer: { + network: { + // eslint-disable-next-line max-len + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions,@typescript-eslint/no-unsafe-assignment + type: process.env.MINA_NETWORK as any, + graphql: process.env.MINA_NODE_GRAPHQL!, + archive: process.env.MINA_ARCHIVE_GRAPHQL!, + accountManager: process.env.MINA_ACCOUNT_MANAGER!, + }, + }, + SettlementSigner: { + feepayer: PrivateKey.fromBase58( + process.env.PROTOKIT_SEQUENCER_PRIVATE_KEY! + ), + contractKeys: [ + PrivateKey.fromBase58( + process.env.PROTOKIT_SETTLEMENT_CONTRACT_PRIVATE_KEY! + ), + PrivateKey.fromBase58( + process.env.PROTOKIT_DISPATCHER_CONTRACT_PRIVATE_KEY! + ), + PrivateKey.fromBase58( + process.env.PROTOKIT_MINA_BRIDGE_CONTRACT_PRIVATE_KEY! + ), + ], + }, + FeeStrategy: {}, + BatchProducerModule: {}, SettlementModule: { addresses: undefined, }, BridgingModule: { addresses: undefined, }, + SequencerStartupModule: {}, + TaskQueue: { + simulatedDuration: 0, + }, + LocalTaskWorker: VanillaTaskWorkerModules.defaultConfig(), + Mempool: {}, }, }); diff --git a/packages/deployment/src/queue/BullQueue.ts b/packages/deployment/src/queue/BullQueue.ts index 2a4f4e640..8c037fa8d 100644 --- a/packages/deployment/src/queue/BullQueue.ts +++ b/packages/deployment/src/queue/BullQueue.ts @@ -94,6 +94,9 @@ export class BullQueue const queue = new Queue(queueName, { connection: redis, + defaultJobOptions: { + attempts: this.config.retryAttempts ?? 2, + }, }); const events = new QueueEvents(queueName, { connection: redis }); diff --git a/packages/protocol/src/Constants.ts b/packages/protocol/src/Constants.ts index 30f2a732c..1e2de64dd 100644 --- a/packages/protocol/src/Constants.ts +++ b/packages/protocol/src/Constants.ts @@ -1,3 +1,5 @@ +import { log } from "@proto-kit/common"; + const constants = { STATE_TRANSITION_BATCH_SIZE: 4, BLOCK_ARGUMENT_BATCH_SIZE: 4, @@ -9,6 +11,7 @@ const prefix = "PROTOKIT"; export const Constants = { getConstant( name: Key, + // TODO Remove this pattern and delegate parsing to the called - this is bad imo transform: (arg: string) => (typeof constants)[Key] ): (typeof constants)[Key] { const env = process.env[name] ?? process.env[`${prefix}_${name}`]; @@ -18,4 +21,16 @@ export const Constants = { return constants[name]; } }, + + printAllConstants() { + const constantsString = + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (Object.keys(constants) as (keyof typeof constants)[]) + .map((name) => { + const constant = Constants.getConstant(name, parseInt); + return `${name}=${constant}`; + }) + .join(", "); + log.info("Protocol constants: ", constantsString); + }, }; diff --git a/packages/sequencer/src/sequencer/SequencerStartupModule.ts b/packages/sequencer/src/sequencer/SequencerStartupModule.ts index ee707749d..d72f3683f 100644 --- a/packages/sequencer/src/sequencer/SequencerStartupModule.ts +++ b/packages/sequencer/src/sequencer/SequencerStartupModule.ts @@ -4,6 +4,7 @@ import { ContractArgsRegistry, MandatoryProtocolModulesRecord, Protocol, + ProtocolConstants, RuntimeVerificationKeyRootService, } from "@proto-kit/protocol"; import { @@ -143,6 +144,8 @@ export class SequencerStartupModule } public async start() { + ProtocolConstants.printAllConstants(); + const flow = this.flowCreator.createFlow("compile-circuits", {}); this.protocol.dependencyContainer diff --git a/packages/sequencer/src/settlement/interactions/bridging/BridgingDeployInteraction.ts b/packages/sequencer/src/settlement/interactions/bridging/BridgingDeployInteraction.ts index c1c24d4a4..9fa2e6194 100644 --- a/packages/sequencer/src/settlement/interactions/bridging/BridgingDeployInteraction.ts +++ b/packages/sequencer/src/settlement/interactions/bridging/BridgingDeployInteraction.ts @@ -21,6 +21,8 @@ import { SettlementUtils } from "../../utils/SettlementUtils"; @injectable() export class BridgingDeployInteraction implements DeployInteraction { + private utils: SettlementUtils; + public constructor( @inject("AddressRegistry") private readonly addressRegistry: AddressRegistry, @@ -33,7 +35,9 @@ export class BridgingDeployInteraction implements DeployInteraction { private readonly feeStrategy: FeeStrategy, @inject("TransactionSender") private readonly transactionSender: MinaTransactionSender - ) {} + ) { + this.utils = new SettlementUtils(this.baseLayer, this.signer); + } protected settlementContractModule(): SettlementContractModule { return this.protocol.dependencyContainer.resolve( @@ -59,7 +63,8 @@ export class BridgingDeployInteraction implements DeployInteraction { const feepayer = this.signer.getFeepayerKey(); - const nonce = options?.nonce ?? 0; + const nonce = + options?.nonce ?? (await this.utils.fetchNonce(feepayer)) ?? 0; const sm = this.settlementContractModule(); const { diff --git a/packages/sequencer/src/settlement/interactions/vanilla/VanillaDeployInteraction.ts b/packages/sequencer/src/settlement/interactions/vanilla/VanillaDeployInteraction.ts index c5fb126fe..448630418 100644 --- a/packages/sequencer/src/settlement/interactions/vanilla/VanillaDeployInteraction.ts +++ b/packages/sequencer/src/settlement/interactions/vanilla/VanillaDeployInteraction.ts @@ -21,6 +21,8 @@ import { SettlementUtils } from "../../utils/SettlementUtils"; @injectable() export class VanillaDeployInteraction implements DeployInteraction { + private utils: SettlementUtils; + public constructor( @inject("AddressRegistry") private readonly addressRegistry: AddressRegistry, @@ -33,7 +35,9 @@ export class VanillaDeployInteraction implements DeployInteraction { private readonly feeStrategy: FeeStrategy, @inject("TransactionSender") private readonly transactionSender: MinaTransactionSender - ) {} + ) { + this.utils = new SettlementUtils(this.baseLayer, this.signer); + } protected settlementContractModule(): SettlementContractModule { return this.protocol.dependencyContainer.resolve( @@ -62,7 +66,8 @@ export class VanillaDeployInteraction implements DeployInteraction { const feepayer = this.signer.getFeepayerKey(); - const nonce = options?.nonce ?? 0; + const nonce = + options?.nonce ?? (await this.utils.fetchNonce(feepayer)) ?? 0; const sm = this.settlementContractModule(); const { SettlementContract: settlementContract } = sm.createContracts({ diff --git a/packages/sequencer/src/settlement/transactions/MinaTransactionSimulator.ts b/packages/sequencer/src/settlement/transactions/MinaTransactionSimulator.ts index b3d8713a2..0323312b0 100644 --- a/packages/sequencer/src/settlement/transactions/MinaTransactionSimulator.ts +++ b/packages/sequencer/src/settlement/transactions/MinaTransactionSimulator.ts @@ -18,7 +18,7 @@ import { } from "@proto-kit/protocol"; import { match } from "ts-pattern"; import { inject, injectable } from "tsyringe"; -import { hashWithPrefix, noop, range } from "@proto-kit/common"; +import { hashWithPrefix, log, noop, range } from "@proto-kit/common"; import { distinctByPredicate } from "../../helpers/utils"; import type { MinaBaseLayer } from "../../protocol/baselayer/MinaBaseLayer"; @@ -173,17 +173,26 @@ export class MinaTransactionSimulator { const getAccountSafe = () => { try { return Mina.getAccount(publicKey, tokenId); - } catch { + } catch (e) { + log.trace(e); return undefined; } }; const account = match(fetchedAccount) .with(undefined, () => getAccountSafe()) - .with({ account: undefined }, () => getAccountSafe()) + .with({ account: undefined }, (e) => { + // TODO Check if it's a "account not found" error, and if it's not then display the error + // (as it's probably networking related) + log.trace(e.error); + return getAccountSafe(); + }) .with({ error: undefined }, (v) => v.account) .exhaustive(); if (account !== undefined) { + log.trace( + `Reloaded account ${account.publicKey.toBase58()}, ${account.balance.toJSON()} MINA` + ); addCachedAccount(account); this.loaded[key] = account; } diff --git a/packages/sequencer/src/settlement/utils/SettlementUtils.ts b/packages/sequencer/src/settlement/utils/SettlementUtils.ts index 9c9f2bba8..f0824a6dc 100644 --- a/packages/sequencer/src/settlement/utils/SettlementUtils.ts +++ b/packages/sequencer/src/settlement/utils/SettlementUtils.ts @@ -2,12 +2,13 @@ import { Bool, fetchAccount, Field, + Mina, PrivateKey, PublicKey, Transaction, UInt32, } from "o1js"; -import { mapSequential } from "@proto-kit/common"; +import { log, mapSequential } from "@proto-kit/common"; import type { MinaBaseLayer } from "../../protocol/baselayer/MinaBaseLayer"; import { MinaSigner } from "../MinaSigner"; @@ -27,6 +28,29 @@ export class SettlementUtils { private readonly signer: MinaSigner ) {} + public async fetchNonce(publicKey: PublicKey): Promise { + const account = await this.safeFetchAccount(publicKey); + if (account !== undefined) { + return parseInt(account.nonce.toString(), 10); + } + return undefined; + } + + public async safeFetchAccount(publicKey: PublicKey, tokenId?: Field) { + const isLocal = this.baseLayer.isLocalBlockChain(); + if (isLocal && Mina.hasAccount(publicKey, tokenId)) { + return Mina.getAccount(publicKey, tokenId); + } else if (!isLocal) { + const fetchResult = await fetchAccount({ publicKey, tokenId }); + if (fetchResult.account !== undefined) { + return fetchResult.account; + } else { + log.info(fetchResult.error); + } + } + return undefined; + } + public signTransaction( tx: Transaction, options: SignTransactionOptions = {}