From 4656f360369d24a7d9eea3c1c42fa0bb656df3f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 31 Aug 2025 07:56:35 +0200 Subject: [PATCH 1/2] Move some values to chainspec. --- packages/jam/block/gp-constants.ts | 12 -- packages/jam/config/chain-spec.ts | 105 +++++++++++------- packages/jam/config/package.json | 1 + .../jam/transition/accumulate/accumulate.ts | 7 +- .../externalities/fetch-externalities.ts | 15 +-- packages/jam/transition/statistics.test.ts | 6 +- packages/jam/transition/statistics.ts | 5 +- 7 files changed, 76 insertions(+), 75 deletions(-) diff --git a/packages/jam/block/gp-constants.ts b/packages/jam/block/gp-constants.ts index 17d633938..a2e3e2219 100644 --- a/packages/jam/block/gp-constants.ts +++ b/packages/jam/block/gp-constants.ts @@ -17,9 +17,6 @@ import { MAX_NUMBER_OF_WORK_ITEMS } from "./work-package.js"; /** `G_I`: The gas allocated to invoke a work-package’s Is-Authorized logic. */ export const G_I = 50_000_000; -/** `G_R`: The gas allocated to invoke a work-package’s Refine logic. */ -export const G_R = 5_000_000_000; - /** `I`: Maximum number of work items in a package. */ export const I = MAX_NUMBER_OF_WORK_ITEMS; @@ -50,21 +47,12 @@ export const W_B = 13_794_305; /** `W_C`: The maximum size of service code in octets. */ export const W_C = 4_000_000; -/** `W_E`: The basic size of erasure-coded pieces in octets. */ -export const W_E = 684; - /** `W_M`: The maximum number of imports in a work-package. */ export const W_M = 3_072; -/** `W_P`: The number of erasure-coded pieces in a segment. */ -export const W_P = 6; - /** `W_R`: The maximum total size of all output blobs in a work-report, in octets. */ export const W_R = 49_152; -/** `W_G`: W_P * W_E = 4104 The size of a segment in octets. */ -export const W_G = W_P * W_E; - /** `W_T`: The size of a transfer memo in octets. */ export const W_T = 128; diff --git a/packages/jam/config/chain-spec.ts b/packages/jam/config/chain-spec.ts index 510ba01b9..231909428 100644 --- a/packages/jam/config/chain-spec.ts +++ b/packages/jam/config/chain-spec.ts @@ -1,3 +1,4 @@ +import { type U8, type U16, type U32, type U64, tryAsU8, tryAsU16, tryAsU32, tryAsU64 } from "@typeberry/numbers"; import { Compatibility, GpVersion, TestSuite, WithDebug } from "@typeberry/utils"; /** @@ -31,50 +32,58 @@ export const EST_CORES = 341; */ export const EST_EPOCH_LENGTH = 600; +/** `W_G`: W_P * W_E = 4104 The size of a segment in octets. */ +export const EC_SEGMENT_SIZE = 4104; + /** * Additional data that has to be passed to the codec to correctly parse incoming bytes. */ export class ChainSpec extends WithDebug { /** Number of validators. */ - readonly validatorsCount: number; + readonly validatorsCount: U16; /** 1/3 of number of validators */ - readonly thirdOfValidators: number; + readonly thirdOfValidators: U16; /** 2/3 of number of validators + 1 */ - readonly validatorsSuperMajority: number; + readonly validatorsSuperMajority: U16; /** Number of cores. */ - readonly coresCount: number; - /** Duration of a timeslot in seconds. */ - readonly slotDuration: number; - /** Length of the epoch in time slots. */ - readonly epochLength: number; + readonly coresCount: U16; /** - * `R`: The rotation period of validator-core assignments, in timeslots. + * `D`: Period in timeslots after which an unreferenced preimage may be expunged. * - * https://graypaper.fluffylabs.dev/#/5f542d7/417f00417f00 + * https://graypaper.fluffylabs.dev/#/9a08063/445800445800?v=0.6.6 */ - readonly rotationPeriod: number; + readonly preimageExpungePeriod: U32; + /** Duration of a timeslot in seconds. */ + readonly slotDuration: U16; + /** Length of the epoch in time slots. */ + readonly epochLength: U32; /** Length of the ticket contest in time slots. */ - readonly contestLength: number; + readonly contestLength: U32; /** The maximum number of tickets each validator can submit. */ - readonly ticketsPerValidator: number; + readonly ticketsPerValidator: U8; /** The maximum number of tickets that can be included in a single block. */ - readonly maxTicketsPerExtrinsic: number; - /** Number of erasure coding pieces per segment. */ - readonly numberECPiecesPerSegment: number; - + readonly maxTicketsPerExtrinsic: U8; /** - * `D`: Period in timeslots after which an unreferenced preimage may be expunged. + * `R`: The rotation period of validator-core assignments, in timeslots. * - * https://graypaper.fluffylabs.dev/#/9a08063/445800445800?v=0.6.6 + * https://graypaper.fluffylabs.dev/#/5f542d7/417f00417f00 */ - readonly preimageExpungePeriod: number; + readonly rotationPeriod: U16; + /** `W_P`: The number of erasure-coded pieces in a segment. */ + readonly numberECPiecesPerSegment: U32; + /** `W_E`: The basic size of erasure-coded pieces in octets. Computed from `W_E = W_G / W_P`. */ + readonly erasureCodedPieceSize: U32; + /** `G_T`: The total gas allocated across all Accumulation. */ + readonly maxBlockGas: U64; + /** `G_R`: The gas allocated to invoke a work-package’s Refine logic. */ + readonly maxRefineGas: U64; - constructor(data: Omit) { + constructor(data: Omit) { super(); this.validatorsCount = data.validatorsCount; - this.thirdOfValidators = Math.floor(data.validatorsCount / 3); - this.validatorsSuperMajority = Math.floor(data.validatorsCount / 3) * 2 + 1; + this.thirdOfValidators = tryAsU16(Math.floor(data.validatorsCount / 3)); + this.validatorsSuperMajority = tryAsU16(Math.floor(data.validatorsCount / 3) * 2 + 1); this.coresCount = data.coresCount; this.slotDuration = data.slotDuration; this.epochLength = data.epochLength; @@ -84,21 +93,29 @@ export class ChainSpec extends WithDebug { this.maxTicketsPerExtrinsic = data.maxTicketsPerExtrinsic; this.numberECPiecesPerSegment = data.numberECPiecesPerSegment; this.preimageExpungePeriod = data.preimageExpungePeriod; + this.erasureCodedPieceSize = tryAsU32(EC_SEGMENT_SIZE / data.numberECPiecesPerSegment); + this.maxBlockGas = data.maxBlockGas; + this.maxRefineGas = data.maxRefineGas; } } /** Set of values for "tiny" chain as defined in JAM test vectors. */ export const tinyChainSpec = new ChainSpec({ - contestLength: 10, - coresCount: 2, - epochLength: 12, - maxTicketsPerExtrinsic: 3, - rotationPeriod: 4, - slotDuration: 6, - ticketsPerValidator: 3, - validatorsCount: 6, - numberECPiecesPerSegment: 1026, - preimageExpungePeriod: Compatibility.isSuite(TestSuite.JAMDUNA) && Compatibility.is(GpVersion.V0_6_4) ? 6 : 32, // why 32: https://github.com/davxy/jam-test-vectors/tree/v0.6.6/traces#preimage-expunge-delay + validatorsCount: tryAsU16(6), + coresCount: tryAsU16(2), + epochLength: tryAsU32(12), + contestLength: tryAsU32(10), + maxTicketsPerExtrinsic: tryAsU8(3), + rotationPeriod: tryAsU16(4), + slotDuration: tryAsU16(6), + ticketsPerValidator: tryAsU8(3), + numberECPiecesPerSegment: tryAsU32(1026), + // why 32: https://github.com/davxy/jam-test-vectors/tree/v0.6.6/traces#preimage-expunge-delay + preimageExpungePeriod: tryAsU32( + Compatibility.isSuite(TestSuite.JAMDUNA) && Compatibility.is(GpVersion.V0_6_4) ? 6 : 32, + ), + maxBlockGas: tryAsU64(20_000_000), + maxRefineGas: tryAsU64(1_000_000_000), }); /** @@ -106,14 +123,16 @@ export const tinyChainSpec = new ChainSpec({ * Please note that only validatorsCount and epochLength are "full", the rest is copied from "tiny". */ export const fullChainSpec = new ChainSpec({ - contestLength: 500, - coresCount: 341, - epochLength: 600, - maxTicketsPerExtrinsic: 16, - rotationPeriod: 10, - slotDuration: 6, - ticketsPerValidator: 2, - validatorsCount: 1023, - numberECPiecesPerSegment: 6, - preimageExpungePeriod: 19_200, + validatorsCount: tryAsU16(1023), + coresCount: tryAsU16(341), + epochLength: tryAsU32(600), + contestLength: tryAsU32(500), + maxTicketsPerExtrinsic: tryAsU8(16), + rotationPeriod: tryAsU16(10), + slotDuration: tryAsU16(6), + ticketsPerValidator: tryAsU8(2), + numberECPiecesPerSegment: tryAsU32(6), + preimageExpungePeriod: tryAsU32(19_200), + maxBlockGas: tryAsU64(3_500_000_000), + maxRefineGas: tryAsU64(5_000_000_000), }); diff --git a/packages/jam/config/package.json b/packages/jam/config/package.json index 5a5d9e9cb..969c94300 100644 --- a/packages/jam/config/package.json +++ b/packages/jam/config/package.json @@ -7,6 +7,7 @@ "test": "tsx --test $(find . -type f -name '*.test.ts' | tr '\\n' ' ')" }, "dependencies": { + "@typeberry/numbers": "0.0.1", "@typeberry/utils": "0.0.1" }, "author": "Fluffy Labs", diff --git a/packages/jam/transition/accumulate/accumulate.ts b/packages/jam/transition/accumulate/accumulate.ts index 412dddf07..e04f03e4f 100644 --- a/packages/jam/transition/accumulate/accumulate.ts +++ b/packages/jam/transition/accumulate/accumulate.ts @@ -101,9 +101,6 @@ enum PvmInvocationError { /** `G_A`: The gas allocated to invoke a work-report’s Accumulation logic. */ export const GAS_TO_INVOKE_WORK_REPORT = 10_000_000n; -/** `G_T`: The total gas allocated across all Accumulation. */ -export const ACCUMULATE_TOTAL_GAS = 3_500_000_000n; - const logger = Logger.new(import.meta.filename, "accumulate"); const ARGS_CODEC_0_6_4 = codec.object({ @@ -432,7 +429,7 @@ export class Accumulate { /** * A method that calculates the initial gas limit. * - * Please note it cannot overflow because we use `BigInt`, and the final result is clamped to `ACCUMULATE_TOTAL_GAS`. + * Please note it cannot overflow because we use `BigInt`, and the final result is clamped to `maxBlockGas` (W_G). * * https://graypaper.fluffylabs.dev/#/7e6ff6a/18f40118f401?v=0.6.7 */ @@ -441,7 +438,7 @@ export class Accumulate { GAS_TO_INVOKE_WORK_REPORT * BigInt(this.chainSpec.coresCount) + this.state.privilegedServices.autoAccumulateServices.reduce((acc, { gasLimit }) => acc + gasLimit, 0n); const gasLimit = tryAsServiceGas( - ACCUMULATE_TOTAL_GAS > calculatedGasLimit ? ACCUMULATE_TOTAL_GAS : calculatedGasLimit, + this.chainSpec.maxBlockGas > calculatedGasLimit ? this.chainSpec.maxBlockGas : calculatedGasLimit, ); return tryAsServiceGas(gasLimit); diff --git a/packages/jam/transition/externalities/fetch-externalities.ts b/packages/jam/transition/externalities/fetch-externalities.ts index a67463468..ee6ebed17 100644 --- a/packages/jam/transition/externalities/fetch-externalities.ts +++ b/packages/jam/transition/externalities/fetch-externalities.ts @@ -1,7 +1,6 @@ import type { EntropyHash } from "@typeberry/block"; import { G_I, - G_R, K, MAX_REPORT_DEPENDENCIES, N, @@ -11,9 +10,7 @@ import { W_A, W_B, W_C, - W_E, W_M, - W_P, W_R, W_T, W_X, @@ -32,7 +29,7 @@ import { MAX_RECENT_HISTORY, } from "@typeberry/state"; import { Compatibility, GpVersion } from "@typeberry/utils"; -import { ACCUMULATE_TOTAL_GAS, GAS_TO_INVOKE_WORK_REPORT } from "../accumulate/accumulate.js"; +import { GAS_TO_INVOKE_WORK_REPORT } from "../accumulate/accumulate.js"; import { Operand, Operand_0_6_4 } from "../accumulate/operand.js"; import { REPORT_TIMEOUT_GRACE_PERIOD } from "../assurances.js"; import { L } from "../reports/verify-contextual.js"; @@ -92,8 +89,8 @@ function getEncodedConstants(chainSpec: ChainSpec) { E: tryAsU32(chainSpec.epochLength), G_A: tryAsU64(GAS_TO_INVOKE_WORK_REPORT), G_I: tryAsU64(G_I), - G_R: tryAsU64(G_R), - G_T: tryAsU64(ACCUMULATE_TOTAL_GAS), + G_R: tryAsU64(chainSpec.maxRefineGas), + G_T: tryAsU64(chainSpec.maxBlockGas), H: tryAsU16(MAX_RECENT_HISTORY), I: tryAsU16(MAX_NUMBER_OF_WORK_ITEMS), J: tryAsU16(MAX_REPORT_DEPENDENCIES), @@ -106,13 +103,13 @@ function getEncodedConstants(chainSpec: ChainSpec) { R: tryAsU16(chainSpec.rotationPeriod), T: tryAsU16(T), U: tryAsU16(REPORT_TIMEOUT_GRACE_PERIOD), - V: tryAsU16(chainSpec.validatorsCount), + V: chainSpec.validatorsCount, W_A: tryAsU32(W_A), W_B: tryAsU32(W_B), W_C: tryAsU32(W_C), - W_E: tryAsU32(W_E), + W_E: tryAsU32(chainSpec.erasureCodedPieceSize), W_M: tryAsU32(W_M), - W_P: tryAsU32(W_P), + W_P: tryAsU32(chainSpec.numberECPiecesPerSegment), W_R: tryAsU32(W_R), W_T: tryAsU32(W_T), W_X: tryAsU32(W_X), diff --git a/packages/jam/transition/statistics.test.ts b/packages/jam/transition/statistics.test.ts index a4187242a..ad02a5eea 100644 --- a/packages/jam/transition/statistics.test.ts +++ b/packages/jam/transition/statistics.test.ts @@ -11,7 +11,7 @@ import { tryAsValidatorIndex, } from "@typeberry/block"; import { type AssurancesExtrinsic, AvailabilityAssurance } from "@typeberry/block/assurances.js"; -import { I, T, W_G, W_M, W_R, W_X } from "@typeberry/block/gp-constants.js"; +import { I, T, W_M, W_R, W_X } from "@typeberry/block/gp-constants.js"; import type { GuaranteesExtrinsic } from "@typeberry/block/guarantees.js"; import type { PreimagesExtrinsic } from "@typeberry/block/preimage.js"; import { testWorkReportHex } from "@typeberry/block/test-helpers.js"; @@ -20,7 +20,7 @@ import { WorkReport } from "@typeberry/block/work-report.js"; import { BitVec, Bytes, BytesBlob } from "@typeberry/bytes"; import { Decoder } from "@typeberry/codec"; import { FixedSizeArray, asKnownSize } from "@typeberry/collections"; -import { tinyChainSpec } from "@typeberry/config"; +import { EC_SEGMENT_SIZE, tinyChainSpec } from "@typeberry/config"; import { ED25519_SIGNATURE_BYTES } from "@typeberry/crypto"; import { HASH_SIZE } from "@typeberry/hash"; import { isU16, isU32, tryAsU32 } from "@typeberry/numbers"; @@ -48,7 +48,7 @@ describe("Statistics", () => { }); it("max data availability score formula should fit into U32", () => { - assert.strictEqual(isU32(W_R + W_G * ((W_M * 65) / 64)), true); + assert.strictEqual(isU32(W_R + EC_SEGMENT_SIZE * ((W_M * 65) / 64)), true); }); }); diff --git a/packages/jam/transition/statistics.ts b/packages/jam/transition/statistics.ts index 279b0c498..45f05b745 100644 --- a/packages/jam/transition/statistics.ts +++ b/packages/jam/transition/statistics.ts @@ -8,11 +8,10 @@ import { tryAsPerValidator, tryAsServiceGas, } from "@typeberry/block"; -import { W_G } from "@typeberry/block/gp-constants.js"; import type { Preimage, PreimagesExtrinsic } from "@typeberry/block/preimage.js"; import type { WorkReport } from "@typeberry/block/work-report.js"; import type { WorkResult } from "@typeberry/block/work-result.js"; -import type { ChainSpec } from "@typeberry/config"; +import { type ChainSpec, EC_SEGMENT_SIZE } from "@typeberry/config"; import { type U32, tryAsU16, tryAsU32 } from "@typeberry/numbers"; import { ServiceStatistics, type State, StatisticsData } from "@typeberry/state"; import { ValidatorStatistics } from "@typeberry/state"; @@ -109,7 +108,7 @@ export class Statistics { const workPackageLength = availableWorkReports.workPackageSpec.length; const workPackageSegment = Math.ceil((availableWorkReports.workPackageSpec.exportsCount * 65) / 64); - sum += workPackageLength + W_G * workPackageSegment; + sum += workPackageLength + EC_SEGMENT_SIZE * workPackageSegment; /** Available work report score can be up to `W_R + W_G * ((W_M * 65) / 64) = 0x00C4_2180` */ return tryAsU32(sum); From e40d51a4c5230abfb83633f992499a1deb3c6e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 31 Aug 2025 08:12:16 +0200 Subject: [PATCH 2/2] Update locfile. --- package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package-lock.json b/package-lock.json index 0a1a9758b..ea8aa2038 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7273,6 +7273,7 @@ "version": "0.0.1", "license": "MPL-2.0", "dependencies": { + "@typeberry/numbers": "0.0.1", "@typeberry/utils": "0.0.1" } },