ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Shardeum 序列化与 AJV Schema 自动生成工作流:基于 prompt.md 的类型注册协议详解

Shardeum 序列化与 AJV Schema 自动生成工作流:基于 prompt.md 的类型注册协议详解 Shardeum 序列化与 AJV Schema 自动生成工作流基于 prompt.md 的类型注册协议详解【免费下载链接】shardeumShardeum is an EVM based autoscaling blockchain项目地址: https://gitcode.com/GitHub_Trending/sh/shardeum本篇文章聚焦 Shardeum 仓库中 src/utils/serialization/prompt.md 定义的一套由类型声明驱动生成 AJV 校验 Schema、注册依赖、并配套 serialize/deserialize 函数的代码生成协议。该协议被用于 Shardeum 网络中大量交易类型、证书与请求体的运行时校验读者读完后将掌握如何按协议为任意 TypeScript 类型编写schema*变量、addSchemaDependencies()与addSchemas()注册函数理解addSchemaDependency/addSchema辅助函数的契约并能将这套模式与仓库中 SchemaHelpers.ts、VectorBufferStream.ts 及 src/types/ajv 目录下的真实实现一一对应。一、prompt.md 在 Shardeum 中的定位Shardeum 是一个基于 EVM 的自动扩容区块链Autoscaling Blockchain其节点间需要校验海量结构化数据——交易Transaction、质押证书StakeCert、加入请求JoinAppData、惩罚数据PenaltyTX等。这类校验不能手写大量if/else而是统一交给 AJVJSON Schema 校验器完成每个类型对应一份 JSON Schema运行时将负载送入编译后的校验函数命中即通过、未命中即返回错误列表。prompt.md正是为这一目标而存在的生成器提示词它定义了从 TypeScript 类型生成 AJV Schema 与序列化代码的标准化协议包括如何声明用于生成 Schema 的示例类型如Foo2、FooParent必须生成哪些产物schema*变量、addSchemaDependencies()、addSchemas()、verify*函数、serialize/deserialize 函数辅助函数addSchemaDependency与addSchema的确切签名与语义一套首轮回答 ok、后续逐类型生成代码的两阶段交互约定。它可以被 AI 编码助手或开发者直接使用把某个类型粘贴进来按协议即可得到对应的 Schema 注册代码而无需手工拼接 AJV 配置。二、协议定义示例类型与辅助函数契约2.1 类型声明示例协议以如下形式给出用于 Schema 生成的示例类型//example types used for schema generation: export type Foo2 { someData: number someName: string } export type FooParent { someName: string arrayOfFoo: Foo2[] }这里展示了协议的两条核心语义每个类型对应一个schemaTypeName变量默认值为undefined即先声明、后填充类型之间允许嵌套与数组引用FooParent内嵌Foo2[]嵌套关系正是依赖注册addSchemaDependency的触发条件。2.2 辅助函数契约协议约定存在两个被导入的辅助函数签名如下export function addSchemaDependency(name: string, schema: object, requiredBy: string): void export function addSchema(name: string, schema: object): void二者的职责划分是理解整套机制的关键函数语义在 Shardeum 仓库中的对应实现addSchemaDependency(name, schema, requiredBy)声明类型name被父类型requiredBy依赖用于在 AJV 中登记子 Schema 与父 Schema 的引用关系见下文ChangeConfigTxSchema等文件的模式addSchema(name, schema)将一份 Schema 以name为键注册进全局 Schema 映射SchemaHelpers.ts 中的同名函数关于依赖注册协议特别强调了一条规则it is ok to call addSchemaDependency multiple times for the same class as long as the parent is different.即同一个子类型可以被多个不同的父类型依赖因此允许对同一name多次调用addSchemaDependency只要每次的requiredBy父类型不同即可。这是多对多引用关系在注册层的直接体现。2.3 需要生成的注册函数协议要求为每个类型生成如下两个顶层函数//This is an example of the function to generate: export function addSchemaDependencies(): void { //all dependencies are added here (for types being worked on in this response) addSchemaDependency(Foo2, FooParent) //FooParent is the type that requires this } //This is an example of the function to generate: export function addSchemas(): void { //register schemas here: (for types being worked on in this response) addSchema(Foo2, schemaFoo2) //here we register Foo2 addSchema(FooParent, schemaFooParent) //here we register FooParent }addSchemaDependencies()集中登记本次响应所涉及类型的全部依赖关系注释中标明FooParent是依赖方父类型addSchemas()集中把schemaFoo2、schemaFooParent等变量注册进全局 Schema 映射。这种依赖注册与 Schema 注册分离的设计保证了 AJV 在编译父 Schema 时其引用的子 Schema 已经可用。2.4 AJV 对象 Schema 校验与 verify* 函数协议还要求对每个出现的类型生成对应的verifyTypeName函数如verifyFooParent用于校验对象是否符合 Schema。同时有一条版本演进约束When versions change these should be updated to verify only the latest version.即在 Shardeum 这类存在版本化数据结构的系统中verify*函数应当随版本升级只校验最新版本避免旧版本 Schema 长期堆叠造成校验漂移——这与仓库 src/versioning 目录下按版本号组织的迁移思路是一致的。三、协议的三步执行流程与两阶段交互约定3.1 生成流程概览按协议一次完整的生成过程包括输入类型粘贴一个或多个 TypeScript 类型声明生成 Schema 定义为每个类型生成schemaType变量默认undefined随后填充为 JSON Schema 对象生成注册函数编写addSchemaDependencies()与addSchemas()按依赖关系逐个调用辅助函数生成序列化函数为每个类型编写serialize与deserialize函数生成校验函数为每个类型编写verify*函数或登记 Schema 供getVerifyFunction编译。其中关于 AJV 实例化协议做了明确简化you do not need to generate a verify* function or actually instantiate ajv, just handle the above mentioned registration tasks for the schema.也就是说在注册阶段只负责把 Schema 登记好真正的 AJV 实例化与编译由运行时的SchemaHelpers完成见下文 4.2 节。3.2 两阶段交互约定协议定义了一个非常具体的聊天气泡式协作流程you do not need to generate any output other than ok at the end of this first query. Follow up queries Following this when you see a type pasted, please write the serialize and deserialize functions. Also please generate the ajv schemas and register them per the addSchemaDependencies example remember you can just reply ok to this first statement, then provide generated code when types are listed in follow up requests.第一阶段首条查询只回复ok不生成任何代码——相当于确认协议已就绪第二阶段随后每粘贴一个类型立即生成对应的 serialize/deserialize 函数并按addSchemaDependencies示例注册 AJV Schema输出约束所有产物放入单个文件中please put all output in a single file便于统一管理。这种交互约定保证了在批量生成大量交易类型时产物命名一致、注册顺序可控且不会因 AJV 实例化副作用污染纯代码生成过程。四、仓库中的真实实现从协议到生产代码prompt.md描述的并非空中楼阁src/utils/serialization 与 src/types/ajv 目录给出了它的生产级落地。4.1 SchemaHelpers.tsaddSchema 与 verify 的运行时底座SchemaHelpers.ts 实现了协议约定的addSchema并补充了协议未提及但必需的运行时能力const schemaMap: Mapstring, object new Map() const verifyFunctions: Mapstring, Ajv.ValidateFunction new Map() export function addSchema(name: string, schema: object): void { if (schemaMap.has(name)) { throw new Error(error already registered ${name}) } schemaMap.set(name, schema) } export function initializeSerialization(): void { for (const [name, schema] of schemaMap.entries()) { ajv.addSchema(schema, name) } } export function getVerifyFunction(name: string): Ajv.ValidateFunction { const existingFn verifyFunctions.get(name) if (existingFn) return existingFn const schema schemaMap.get(name) if (!schema) throw new Error(error missing schema ${name}) const verifyFn ajv.compile(schema) verifyFunctions.set(name, verifyFn) return verifyFn }几个值得注意的实现细节重名保护addSchema对重复注册直接抛错error already registered name防止初始化阶段 Schema 被静默覆盖统一编译initializeSerialization()把schemaMap中全部 Schema 一次性登记进全局ajv实例ajv.addSchema(schema, name)呼应了协议注册任务集中处理的约定校验函数缓存getVerifyFunction首次编译后缓存于verifyFunctions避免同一 Schema 反复编译对缺失的 Schema 抛出error missing schema name便于定位注册遗漏BigInt 支持文件头部通过ajv.addKeyword(isBigInt, ...)注册了自定义关键字适配区块链场景下常见的大整数类型。4.2 Helpers.ts所有 Schema 的初始化编排入口src/types/ajv/Helpers.ts 是协议的总装线它逐一声明导入各类型 Schema 模块的init*函数并在initAjvSchemas()中按序调用export function initAjvSchemas(): void { initSign() initInjectTxReq() initPenaltyTX() initJoinAppData() initStakeResp() initStakeCert() initRemoveNodeCert() initApplyChangeConfigTx() initApplyNetworkParamTx() initChangeConfigTx() initChangeNetworkParamTx() initClaimRewardTx() initInitNetworkTx() initInitRewardTimesTx() initSetCertTimeTx() initStakeTx() initUnstakeTx() initTransferFromSecureAccountTx() }每个initXxx内部正是按协议生成的模式先调用私有addSchemaDependencies()登记依赖再调用addSchemas()通过addSchema注册到全局映射。Helpers.ts还提供了verifyPayloadT(name, payload)统一校验入口获取校验函数、执行校验失败时通过parseAjvErrors把 AJV 的ErrorObject[]转成可读的错误消息数组。Schema 名称统一收敛在 src/types/enum/AJVSchemaEnum.ts 的AJVSchemaEnum枚举中如QueryCertReq、InjectTxReq、PenaltyTx、StakeCert、ChangeConfigTx等 27 个条目注册时以枚举值作为addSchema的键避免字符串硬编码导致的拼写漂移。4.3 三种真实 Schema 文件形态对照协议仓库中的各 Schema 文件完整呈现了三种典型形态形态一无依赖的叶子 SchemaSignSchema.tsexport function initSign(): void { addSchemaDependencies() addSchemas() } function addSchemaDependencies(): void { // No dependencies } function addSchemas(): void { addSchema(AJVSchemaEnum.Sign, schemaSign) }schemaSign是纯叶子对象owner/sig两个字符串字段因此addSchemaDependencies()为空注释——与协议示例中为类型工作中涉及的依赖登记一一对应。形态二有依赖的内部交易 SchemaChangeConfigTxSchema.tsconst schemaChangeConfigTx { type: object, properties: { isInternalTx: { type: boolean, enum: [true] }, internalTXType: { enum: [InternalTXType.ChangeConfig] }, type: { type: string }, from: { type: string }, cycle: { type: number }, config: { type: string }, timestamp: { type: number, exclusiveMinimum: 0 }, chainId: { type: string }, sign: { type: array, items: schemaSign, }, }, required: [isInternalTx, internalTXType, from, cycle, config, timestamp, chainId], additionalProperties: false, }这里schemaSign被内联为sign数组的items——即依赖SignSchema其addSchemaDependencies()会登记对Sign的依赖。同时展示了 Shardeum 内部交易 Schema 的常见约束isInternalTx固定为true、internalTXType限定枚举值、timestamp要求正数、additionalProperties: false严格禁止未声明字段。形态三可空嵌套 SchemaJoinAppData.tsexport const schemaAppJoinData { type: object, properties: { version: { type: string }, stakeCert: { anyOf: [StakeCert, { type: null }] }, adminCert: { anyOf: [schemaAdminCert, { type: null }] }, isAdminCertUnexpired: { type: boolean }, }, required: [version], additionalProperties: false, }节点加入网络时的应用数据其stakeCert、adminCert字段通过anyOf: [子Schema, { type: null }]表达可为空语义——这是依赖注册与 AJV 组合 Schema 的典型配合。五、配套序列化层VectorBufferStream 与 serialize/deserialize协议要求在生成 Schema 的同时编写 serialize/deserialize 函数Shardeum 的序列化底座是 VectorBufferStream.ts写入侧writeString先写 4 字节长度再写 UTF-8 内容、writeUInt32、writeBigInt64、writeFixedBuffer等内部通过ensureCapacity实现缓冲区的动态扩容容量不足时按max(len * 2, pos size)翻倍读取侧readString先读长度再切片、readUInt32、readBigInt64、readFixedBuffer(length)等全部基于游标position顺序推进构造方式new VectorBufferStream(initialSize)创建可写流VectorBufferStream.fromBuffer(buffer)从已有 Buffer 恢复读取流getBuffer()返回[0, position)的有效切片。在 src/types/BaseAccount.ts 中可以观察到标准用法——serializeBaseAccount(stream, obj, root)向流中依次写入字段deserializeBaseAccount(stream)按相同顺序读取并还原对象该文件从shardeum-foundation/core导入VectorBufferStream说明序列化层同时被抽取为核心基础库。序列化与 Schema 校验形成互补serialize/deserialize 负责网络与磁盘上的字节流转AJV Schema 负责对象语义层面的合法性校验二者都由同一套类型声明驱动生成保证字段顺序与类型约束永远同步。六、协议正确性如何被测试保证test/unit/src/utils/serialization/SchemaHelpers.test.ts 用单元测试锁定了协议落地后的运行时行为初始化路径addSchema两次注册后调用initializeSerialization()断言 AJV 的addSchema被调用两次——验证注册表 → AJV的全量搬运逻辑重名防护对同一名字二次addSchema断言抛出error already registered name校验函数getVerifyFunction返回函数类型对未注册名字抛出error missing schema name语义正确性用{ age: 25, name: test }类对象验证类型正确且字段齐全才通过age: 25类型错误、缺字段、空对象均被判定失败嵌套 Schema多层嵌套对象user.address.street/city验证 AJV 的递归校验行为缺深层字段时同样失败。此外 test/unit/src/types/ajv 目录下为QueryCertReq、JoinAppData、PenaltyTXSchema、Helpers等 Schema 文件提供了逐类型的测试用例可直接作为按协议生成 Schema 后如何验证的范例。七、实践要点与注意事项把prompt.md协议应用到新的类型上时建议遵循以下要点先声明后注册schemaType变量默认undefined在addSchemas()中统一填充并注册避免散落注册导致初始化顺序失控依赖只登记、不编译addSchemaDependencies()只做登记addSchemaDependencyAJV 的实例化与编译交给initializeSerialization()/getVerifyFunction()一个文件一个产物包serialize、deserialize、schema、注册函数放入同一文件与仓库 src/types/ajv 的文件组织方式保持一致命名走枚举注册键使用 AJVSchemaEnum 枚举值而非裸字符串版本只验最新版本升级时更新verify*只校验最新版本避免旧 Schema 长期滞留引用可空类型用anyOf: [SubSchema, { type: null }]表达可空嵌套字段严格模式交易类 Schema 建议开启additionalProperties: false防止未声明字段注入Shardeum 交易 Schema 的通行做法重复依赖是合法的同一子类型被多个父类型引用时可以多次调用addSchemaDependency只要requiredBy不同。若需在本地运行相关测试可执行仓库 package.json 中声明的 jest 测试命令重点覆盖test/unit/src/utils/serialization与test/unit/src/types/ajv两个目录下的用例即可验证协议产物与运行时行为的一致性。结语src/utils/serialization/prompt.md表面上是一份提示词文档实质上是 Shardeum 序列化与校验体系的一等公民设计文档它以最小化的函数契约addSchema/addSchemaDependency、标准化的生成清单schema*/addSchemaDependencies/addSchemas/verify*/ serialize/deserialize和清晰的交互约定让类型即 Schema成为可批量执行的工程流程。理解它就等于掌握了 Shardeum 全量交易与证书数据校验体系的入口——无论你是要为网络新增一种内部交易类型还是想复刻这套 AJV 注册模式到自己的链上项目都可以从这份协议与 SchemaHelpers.ts、Helpers.ts 的对应实现中找到完整的答案。【免费下载链接】shardeumShardeum is an EVM based autoscaling blockchain项目地址: https://gitcode.com/GitHub_Trending/sh/shardeum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表