Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions packages/api/src/graphql/modules/BlockResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import { Arg, Field, ObjectType, Query } from "type-graphql";

import { GraphqlModule, graphqlModule } from "../GraphqlModule";

import { BatchTransactionModel } from "./model/BatchTransactionModel";
import { TransactionExecutionResultModel } from "./model/TransactionExecutionResultModel";

@ObjectType()
export class BlockModel {
public static fromServiceLayerModel(block: Block) {
return new BlockModel(
Number(block.networkState.during.block.height.toBigInt()),
block.transactions.map((tx) =>
BatchTransactionModel.fromServiceLayerModel({
TransactionExecutionResultModel.fromServiceLayerModel({
tx: tx.tx,
status: tx.status.toBoolean(),
status: tx.status,
statusMessage: tx.statusMessage,
})
),
Expand All @@ -33,15 +33,15 @@ export class BlockModel {
@Field()
height: number;

@Field(() => [BatchTransactionModel])
txs: BatchTransactionModel[];
@Field(() => [TransactionExecutionResultModel])
txs: TransactionExecutionResultModel[];

@Field()
transactionsHash: string;

private constructor(
height: number,
txs: BatchTransactionModel[],
txs: TransactionExecutionResultModel[],
transactionsHash: string,
hash: string,
previousBlockHash: string | undefined
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { ObjectType, Field } from "type-graphql";
import { BatchTransaction } from "@proto-kit/sequencer";
import { IsBoolean } from "class-validator";
import { TransactionExecutionResult } from "@proto-kit/sequencer";

import { TransactionObject } from "../MempoolResolver";

@ObjectType()
export class BatchTransactionModel {
public static fromServiceLayerModel(cbt: BatchTransaction) {
export class TransactionExecutionResultModel {
public static fromServiceLayerModel(
cbt: Pick<TransactionExecutionResult, "tx" | "status" | "statusMessage">
) {
const { tx, status, statusMessage } = cbt;
return new BatchTransactionModel(
return new TransactionExecutionResultModel(
TransactionObject.fromServiceLayerModel(tx),
status,
status.toBoolean(),
statusMessage
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- CreateTable
CREATE TABLE "SkippedTransactionInputPaths" (
"transactionHash" TEXT NOT NULL,
"paths" DECIMAL(78,0)[],

CONSTRAINT "SkippedTransactionInputPaths_pkey" PRIMARY KEY ("transactionHash")
);

-- AddForeignKey
ALTER TABLE "SkippedTransactionInputPaths" ADD CONSTRAINT "SkippedTransactionInputPaths_transactionHash_fkey" FOREIGN KEY ("transactionHash") REFERENCES "Transaction"("hash") ON DELETE RESTRICT ON UPDATE CASCADE;
10 changes: 10 additions & 0 deletions packages/persistance/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ model Transaction {
IncomingMessageBatchTransaction IncomingMessageBatchTransaction[]

priority TransactionPriority?

inputPaths SkippedTransactionInputPaths?
}

model TransactionPriority {
Expand All @@ -68,6 +70,14 @@ model TransactionPriority {
@@id([transactionHash])
}

model SkippedTransactionInputPaths {
transactionHash String @id

paths Decimal[] @db.Decimal(78, 0)

transaction Transaction @relation(fields: [transactionHash], references: [hash])
}

model TransactionExecutionResult {
// TODO Make StateTransitionBatch and StateTransition Table
stateTransitions Json @db.Json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import type { PrismaConnection } from "../../PrismaDatabaseConnection";

import { TransactionMapper } from "./mappers/TransactionMapper";
import { Decimal } from "./PrismaStateService";

@injectable()
export class PrismaTransactionStorage implements TransactionStorage {
Expand All @@ -33,6 +34,9 @@ export class PrismaTransactionStorage implements TransactionStorage {
isMessage: {
equals: false,
},
inputPaths: {
is: null,
},
},
orderBy: {
priority: {
Expand Down Expand Up @@ -127,4 +131,29 @@ export class PrismaTransactionStorage implements TransactionStorage {
batch,
};
}

public async reportSkippedTransactions(
paths: Record<string, bigint[]>
): Promise<void> {
const { prismaClient } = this.connection;

await prismaClient.skippedTransactionInputPaths.createMany({
data: Object.entries(paths).map(([transactionHash, pathArray]) => ({
transactionHash,
paths: pathArray.map((path) => new Decimal(path.toString())),
})),
});
}

public async reportChangedPaths(paths: bigint[]): Promise<void> {
const { prismaClient } = this.connection;

await prismaClient.skippedTransactionInputPaths.deleteMany({
where: {
paths: {
hasSome: paths.map((path) => new Decimal(path.toString())),
},
},
});
}
}
12 changes: 10 additions & 2 deletions packages/protocol/src/hooks/AccountStateHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ export class AccountState extends Struct({
nonce: UInt64,
}) {}

export type AccountStateHookConfig = {
maximumNonceLookahead?: number;
};

@injectable()
export class AccountStateHook extends ProvableTransactionHook {
export class AccountStateHook extends ProvableTransactionHook<AccountStateHookConfig> {
@state() public accountState = StateMap.from<PublicKey, AccountState>(
PublicKey,
AccountState
Expand Down Expand Up @@ -67,6 +71,10 @@ export class AccountStateHook extends ProvableTransactionHook {

const currentNonce = accountState.nonce;

return transaction.nonce.value.lessThan(currentNonce).toBoolean();
const exceedsMaximumLookahead = transaction.nonce.value.greaterThan(
currentNonce.add(this.config.maximumNonceLookahead ?? 10)
);
const nonceIsInPast = transaction.nonce.value.lessThan(currentNonce);
return nonceIsInPast.or(exceedsMaximumLookahead).toBoolean();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
TransactionExecutionResultStatus,
TransactionExecutionService,
} from "./TransactionExecutionService";
import { Ordering } from "./Ordering";
import { Ordering, OrderingMetadata } from "./Ordering";

// TODO Allow user overriding of the blockbuilder
@injectable()
Expand Down Expand Up @@ -67,6 +67,7 @@ export class BlockBuilder {
): Promise<{
blockState: BlockTrackers;
executionResults: TransactionExecutionResultStatus[];
orderingMetadata: OrderingMetadata;
}> {
let blockState = state;
const exceptionExecutionResults: TransactionExecutionResultStatus[] = [];
Expand Down Expand Up @@ -139,11 +140,13 @@ export class BlockBuilder {
}
}

const orderingResults = ordering.getResults();
const { results: orderingResults, orderingMetadata } =
ordering.getResults();

return {
blockState,
executionResults: orderingResults.concat(...exceptionExecutionResults),
orderingMetadata,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { Database } from "../../../storage/Database";
import { Tracer } from "../../../logging/Tracer";
import { trace } from "../../../logging/trace";
import { AsyncLinkedLeafStore } from "../../../state/async/AsyncLinkedLeafStore";
import { TransactionStorage } from "../../../storage/repositories/TransactionStorage";
import { ensureNotBusy } from "../../../helpers/BusyGuard";

import { BlockProductionService } from "./BlockProductionService";
Expand All @@ -45,6 +46,8 @@ export class BlockProducerModule extends SequencerModule<BlockConfig> {
private readonly unprovenLinkedLeafStore: AsyncLinkedLeafStore,
@inject("BlockQueue")
private readonly blockQueue: BlockQueue,
@inject("TransactionStorage")
private readonly transactionStorage: TransactionStorage,
@inject("BlockTreeStore")
private readonly blockTreeStore: AsyncMerkleTreeStore,
private readonly productionService: BlockProductionService,
Expand Down Expand Up @@ -194,7 +197,7 @@ export class BlockProducerModule extends SequencerModule<BlockConfig> {
);

if (blockResult !== undefined) {
const { block, stateChanges } = blockResult;
const { block, stateChanges, orderingMetadata } = blockResult;

// Skip production if no transactions are available for now
if (block.transactions.length === 0 && !this.allowEmptyBlock()) {
Expand All @@ -218,6 +221,13 @@ export class BlockProducerModule extends SequencerModule<BlockConfig> {
.filter((x) => x.type === "shouldRemove")
.map((x) => x.hash)
);

await this.transactionStorage.reportChangedPaths(
orderingMetadata.allChangedPaths
);
await this.transactionStorage.reportSkippedTransactions(
orderingMetadata.skippedPaths
);
});
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
TransactionExecutionResultStatus,
} from "./TransactionExecutionService";
import { BlockBuilder } from "./BlockBuilder";
import { OrderingMetadata } from "./Ordering";

function isIncludedTxs(x: TransactionExecutionResultStatus): x is {
status: "included";
Expand Down Expand Up @@ -111,6 +112,7 @@ export class BlockProductionService {
hash: string;
type: "included" | "skipped" | "shouldRemove";
}[];
orderingMetadata: OrderingMetadata;
}
| undefined
> {
Expand Down Expand Up @@ -142,13 +144,16 @@ export class BlockProductionService {
UntypedStateTransition.fromStateTransition(transition)
);

const { blockState: newBlockState, executionResults } =
await this.blockBuilder.buildBlock(
stateService,
networkState,
blockState,
maximumBlockSize
);
const {
blockState: newBlockState,
executionResults,
orderingMetadata,
} = await this.blockBuilder.buildBlock(
stateService,
networkState,
blockState,
maximumBlockSize
);

const previousBlockHash =
lastResult.blockHash === 0n ? undefined : Field(lastResult.blockHash);
Expand Down Expand Up @@ -206,6 +211,7 @@ export class BlockProductionService {
},
stateChanges: stateService,
includedTxs,
orderingMetadata,
};
}
}
Loading