Skip to content

Commit

Permalink
feat: Estimate tx size (#6928)
Browse files Browse the repository at this point in the history
Estimate size of tx dropping empty fields
  • Loading branch information
spalladino authored Jun 6, 2024
1 parent 4692fb0 commit 1fa7d84
Show file tree
Hide file tree
Showing 19 changed files with 152 additions and 2 deletions.
13 changes: 13 additions & 0 deletions yarn-project/circuit-types/src/tx/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Proof,
PublicCallRequest,
} from '@aztec/circuits.js';
import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection';
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';

import { type GetUnencryptedLogsResponse } from '../logs/get_unencrypted_logs_response.js';
Expand Down Expand Up @@ -193,6 +194,18 @@ export class Tx {
};
}

getSize() {
return (
this.data.getSize() +
this.proof.buffer.length +
this.noteEncryptedLogs.getSerializedLength() +
this.encryptedLogs.getSerializedLength() +
this.unencryptedLogs.getSerializedLength() +
arraySerializedSizeOfNonEmpty(this.enqueuedPublicFunctionCalls) +
arraySerializedSizeOfNonEmpty([this.publicTeardownFunctionCall])
);
}

/**
* Convenience function to get a hash out of a tx or a tx-like.
* @param tx - Tx-like object.
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/circuits.js/src/structs/content_commitment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export class ContentCommitment {
}
}

getSize() {
return this.toBuffer().length;
}

toBuffer() {
return serializeToBuffer(this.txTreeHeight, this.txsEffectsHash, this.inHash, this.outHash);
}
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/circuits.js/src/structs/gas_settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export class GasSettings {
public readonly inclusionFee: Fr,
) {}

getSize(): number {
return this.toBuffer().length;
}

static from(args: {
gasLimits: FieldsOf<Gas>;
teardownGasLimits: FieldsOf<Gas>;
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/circuits.js/src/structs/global_variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export class GlobalVariables {
public gasFees: GasFees,
) {}

getSize(): number {
return this.toBuffer().length;
}

static from(fields: FieldsOf<GlobalVariables>): GlobalVariables {
return new GlobalVariables(...GlobalVariables.getFields(fields));
}
Expand Down
10 changes: 10 additions & 0 deletions yarn-project/circuits.js/src/structs/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ export class Header {
] as const;
}

getSize() {
return (
this.lastArchive.getSize() +
this.contentCommitment.getSize() +
this.state.getSize() +
this.globalVariables.getSize() +
this.totalFees.size
);
}

toBuffer() {
return serializeToBuffer(...Header.getFields(this));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type FieldsOf, makeTuple } from '@aztec/foundation/array';
import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection';
import { Fr } from '@aztec/foundation/fields';
import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize';

Expand Down Expand Up @@ -67,6 +68,22 @@ export class CombinedAccumulatedData {
public gasUsed: Gas,
) {}

getSize() {
return (
arraySerializedSizeOfNonEmpty(this.newNoteHashes) +
arraySerializedSizeOfNonEmpty(this.newNullifiers) +
arraySerializedSizeOfNonEmpty(this.newL2ToL1Msgs) +
this.noteEncryptedLogsHash.size +
this.encryptedLogsHash.size +
this.unencryptedLogsHash.size +
this.noteEncryptedLogPreimagesLength.size +
this.encryptedLogPreimagesLength.size +
this.unencryptedLogPreimagesLength.size +
arraySerializedSizeOfNonEmpty(this.publicDataUpdateRequests) +
this.gasUsed.toBuffer().length
);
}

static getFields(fields: FieldsOf<CombinedAccumulatedData>) {
return [
fields.newNoteHashes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export class CombinedConstantData {
return serializeToBuffer(this.historicalHeader, this.txContext, this.globalVariables);
}

getSize() {
return this.historicalHeader.getSize() + this.txContext.getSize() + this.globalVariables.getSize();
}

static from({ historicalHeader, txContext, globalVariables }: FieldsOf<CombinedConstantData>): CombinedConstantData {
return new CombinedConstantData(historicalHeader, txContext, globalVariables);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { makeTuple } from '@aztec/foundation/array';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection';
import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize';

import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX } from '../../constants.gen.js';
Expand Down Expand Up @@ -35,6 +36,15 @@ export class PartialPrivateTailPublicInputsForPublic {
public publicTeardownCallStack: Tuple<CallRequest, typeof MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX>,
) {}

getSize() {
return (
this.validationRequests.getSize() +
this.endNonRevertibleData.getSize() +
this.end.getSize() +
arraySerializedSizeOfNonEmpty(this.publicTeardownCallStack)
);
}

get needsSetup() {
return !this.endNonRevertibleData.publicCallStack[0].isEmpty();
}
Expand Down Expand Up @@ -87,6 +97,10 @@ export class PartialPrivateTailPublicInputsForRollup {
);
}

getSize() {
return this.rollupValidationRequests.getSize() + this.end.getSize();
}

toBuffer() {
return serializeToBuffer(this.rollupValidationRequests, this.end);
}
Expand Down Expand Up @@ -131,6 +145,16 @@ export class PrivateKernelTailCircuitPublicInputs {
return (this.forPublic ?? this.forRollup)!;
}

getSize() {
return (
(this.forPublic?.getSize() ?? 0) +
(this.forRollup?.getSize() ?? 0) +
this.constants.getSize() +
this.revertCode.getSerializedLength() +
this.feePayer.size
);
}

toPublicKernelCircuitPublicInputs() {
if (!this.forPublic) {
throw new Error('Private tail public inputs is not for public circuit.');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { makeTuple } from '@aztec/foundation/array';
import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection';
import { Fr } from '@aztec/foundation/fields';
import { BufferReader, FieldReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize';

Expand Down Expand Up @@ -67,6 +68,20 @@ export class PublicAccumulatedData {
public readonly gasUsed: Gas,
) {}

getSize() {
return (
arraySerializedSizeOfNonEmpty(this.newNoteHashes) +
arraySerializedSizeOfNonEmpty(this.newNullifiers) +
arraySerializedSizeOfNonEmpty(this.newL2ToL1Msgs) +
arraySerializedSizeOfNonEmpty(this.noteEncryptedLogsHashes) +
arraySerializedSizeOfNonEmpty(this.encryptedLogsHashes) +
arraySerializedSizeOfNonEmpty(this.unencryptedLogsHashes) +
arraySerializedSizeOfNonEmpty(this.publicDataUpdateRequests) +
arraySerializedSizeOfNonEmpty(this.publicCallStack) +
this.gasUsed.toBuffer().length
);
}

toBuffer() {
return serializeToBuffer(
this.newNoteHashes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export class PartialStateReference {
public readonly publicDataTree: AppendOnlyTreeSnapshot,
) {}

getSize() {
return this.noteHashTree.getSize() + this.nullifierTree.getSize() + this.publicDataTree.getSize();
}

static fromBuffer(buffer: Buffer | BufferReader): PartialStateReference {
const reader = BufferReader.asReader(buffer);
return new PartialStateReference(
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/circuits.js/src/structs/public_call_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export class PublicCallRequest {
public args: Fr[],
) {}

getSize() {
return this.isEmpty() ? 0 : this.toBuffer().length;
}

/**
* Serialize this as a buffer.
* @returns The buffer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export class AppendOnlyTreeSnapshot {
public nextAvailableLeafIndex: UInt32,
) {}

getSize() {
return this.root.size + 4;
}

toBuffer() {
return serializeToBuffer(this.root, this.nextAvailableLeafIndex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export class RollupValidationRequests {
public maxBlockNumber: MaxBlockNumber,
) {}

getSize() {
return this.toBuffer().length;
}

toBuffer() {
return serializeToBuffer(this.maxBlockNumber);
}
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/circuits.js/src/structs/state_reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export class StateReference {
public partial: PartialStateReference,
) {}

getSize() {
return this.l1ToL2MessageTree.getSize() + this.partial.getSize();
}

toBuffer() {
// Note: The order here must match the order in the HeaderLib solidity library.
return serializeToBuffer(this.l1ToL2MessageTree, this.partial);
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/circuits.js/src/structs/tx_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export class TxContext {
this.version = new Fr(version);
}

getSize() {
return this.chainId.size + this.version.size + this.gasSettings.getSize();
}

clone() {
return new TxContext(this.chainId, this.version, this.gasSettings.clone());
}
Expand Down
12 changes: 12 additions & 0 deletions yarn-project/circuits.js/src/structs/validation_requests.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { makeTuple } from '@aztec/foundation/array';
import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection';
import { type Fr } from '@aztec/foundation/fields';
import { BufferReader, FieldReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize';

Expand Down Expand Up @@ -54,6 +55,17 @@ export class ValidationRequests {
public publicDataReads: Tuple<PublicDataRead, typeof MAX_PUBLIC_DATA_READS_PER_TX>,
) {}

getSize() {
return (
this.forRollup.getSize() +
arraySerializedSizeOfNonEmpty(this.noteHashReadRequests) +
arraySerializedSizeOfNonEmpty(this.nullifierReadRequests) +
arraySerializedSizeOfNonEmpty(this.nullifierNonExistentReadRequests) +
arraySerializedSizeOfNonEmpty(this.scopedKeyValidationRequestsAndGenerators) +
arraySerializedSizeOfNonEmpty(this.publicDataReads)
);
}

toBuffer() {
return serializeToBuffer(
this.forRollup,
Expand Down
14 changes: 14 additions & 0 deletions yarn-project/foundation/src/collection/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,17 @@ export function arrayNonEmptyLength<T>(arr: T[], isEmpty: (item: T) => boolean):
export function times<T>(n: number, fn: (i: number) => T): T[] {
return [...Array(n).keys()].map(i => fn(i));
}

/**
* Returns the serialized size of all non-empty items in an array.
* @param arr - Array
* @returns The serialized size in bytes.
*/
export function arraySerializedSizeOfNonEmpty(
arr: (({ isZero: () => boolean } | { isEmpty: () => boolean }) & { toBuffer: () => Buffer })[],
) {
return arr
.filter(x => x && ('isZero' in x ? !x.isZero() : !x.isEmpty()))
.map(x => x!.toBuffer().length)
.reduce((a, b) => a + b, 0);
}
5 changes: 5 additions & 0 deletions yarn-project/foundation/src/fields/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ abstract class BaseField {
return this.toBigInt();
}

/** Returns the size in bytes. */
get size(): number {
return BaseField.SIZE_IN_BYTES;
}

protected constructor(value: number | bigint | boolean | BaseField | Buffer) {
if (value instanceof Buffer) {
if (value.length > BaseField.SIZE_IN_BYTES) {
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/sequencer-client/src/sequencer/sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,10 @@ export class Sequencer {

const toReturn: Tx[] = [];
for (const tx of txs) {
const txSize = tx.getStats().size - tx.proof.toBuffer().length;
const txSize = tx.getSize() - tx.proof.toBuffer().length;
if (totalSize + txSize > maxSize) {
this.log.warn(
`Dropping tx ${tx.getTxHash()} with size ${txSize} due to exceeding ${maxSize} block size limit (currently at ${totalSize})`,
`Dropping tx ${tx.getTxHash()} with estimated size ${txSize} due to exceeding ${maxSize} block size limit (currently at ${totalSize})`,
);
continue;
}
Expand Down

0 comments on commit 1fa7d84

Please sign in to comment.