DECAF的超高压燃料合同
用 TypeScript 写的 Hyperledger Fabric 的链码侧构件 。 该模块提供寄存器、CRUD合同(对象和序列化的JSON)、ERC20样本合同、Fabric背接序列、事件排放和上下文记录。 它使DECAF的数据访问模式适应了Fabric的世界状态,这样你就可以用DECAF其他地方使用的相同的存储器/模型抽象来写出智能合同.
2025-11-26. 发布docs刷新. 见 工作文件/报告/报告 罚单摘要.
现有文件 这里
说明
本模块侧重于@decaf-ts/ for-fabric的链码(合同)一面. 它将DECAF的存储器/模型/Adapter抽象化为Hyperledger Fabric的世界状态和执行背景,这样你就可以用熟悉的模式和最小的锅炉板执行智能合同.
主要想法:
- 保留您的域名模式为注释类( 使用 @ decaf- ts/ decorator- validation) .
- 通过Fabric-aware适配器使用存储器来持续/读取/平滑模型.
- 编写可重复使用的CRUD合同和公用事业,而不是手写分机电话.
- 从寄存器操作中释放出一等Fabric事件.
- 在执行期间利用上下文感知到的日志和打入的旗帜.
行业合同/合同中确定的合同组成部分:
- 核心背景和类型
- Fabric Contact Context:扩展了通用上下文,从分类账中曝光出Fabric特有的属性(stub,客户身份,日志)和时间戳分辨率.
- FabricContractFlags:接口扩展 RepositoryFlags 并有分贝,客户端身份和对合同呼叫的日志.
- 日志
- ContractLogger:与Fabric合同上下文相匹配的小型Logger. 它尊重日志水平,并转发给基本的Fabric日志.
- 适配器和存储器
- FabricContactAdapter:可执行CRUD,批量操作,原始芒果查询,结果迭代,模型制备/重置,复合键前缀等功能的链码侧适配器,并进行序列创建. Bridges DECAF抽象到Fabric(ChancodeStub,客户端身份)和CouchDB风格的查询.
- Fabric Contract Repositor:用于链码内部模型的 Repositor. 支持创建,更新,创建All,更新All,读取/读取All,原始查询(芒果),选择预测,以前缀为主的批量操作,并通过观察者汉德勒发布事件.
- Fabric Contact Repository Observatory Handler:通过 stub. setEvent 发布 Fabric 事件的观察家 Handler 使用生成 FabricEvent 生成的名称Name.
- 顺序
- FabricContractDBSequence:由Fabric支持的以当前,下行和范围执行序列. 通过 Fabric Contact Repository 在世界状态存储值, 并支持数字或 BigInt 序列的可配置启动 由来.
- CRUD合同
- FabricCrud Contract: Base smart Contract 曝光 CRUD 端点(创建,读取,更新,删除,创建All,readAll,更新All,删除All,生取,入取,健康检查)为模型类型. 使用DeterministicSerializer和幕后FabricContractAdapter/存储器,并提供logFor(ctx).
- 序列化Crud Contract:与FabricCrud Contract相同的端点,但取/回JSON字符串(去)被序列化为模型类. 这简化了客户端的相互作用,用于测试.
- ERC20样本
- ERC20Token, ERC20Wallet,"津贴":ERC20类代币的样本域模型,钱包和津贴.
- Fabric Statement <M,R>:一个可切入式DB状态桥,通过FabricContactAdapter运行芒果查询,在需要时处理主密钥投影.
- FabricERC20 Contract:一个完整的ERC20智能合同显示基于寄存器的持久性和算术辅助. 执行初始化、 检查初始化、 托肯Name、 符号、 十进制、 总供应、 平衡、 转账、 转出、 批准、 津贴、 薄荷、 燃烧、 BurnFrom、 客户账户注册、 客户账户ID 和一个内部 转账帮助器 .
设计注释 :
- 定型序列化用于确保世界态写作的稳定字节.
- db-decors的创建/创建Update hooks被适配器所利用来设定主键和创建/拥有元数据.
- 芒果查询(CouchDB)通过GetQueryResultWithPagination用于丰富的查询.
- 事件排放是通过Fabric Contract Repositor Obbservatory Handler支持的Events列表选择每个操作类型的.
使用这些组件,您可以构建强大的链码,同时保持代码简洁,可测试,并与DECAF的架构保持一致.
如何使用
安装
npm install @decaf-ts/for-fabric
客户端用户端
连接到 Fabric 网络
import { FabricAdapter, PeerConfig } from "@decaf-ts/for-fabric";
// Configure connection to a Fabric peer
const config: PeerConfig = {
mspId: "Org1MSP",
peerEndpoint: "localhost:7051",
channelName: "mychannel",
chaincodeName: "mycc",
contractName: "mycontract",
tlsCertPath: "/path/to/tls/cert",
certDirectoryPath: "/path/to/cert/dir",
keyDirectoryPath: "/path/to/key/dir",
cryptoPath: "/path/to/crypto",
peerHostAlias: "peer0.org1.example.com",
caEndpoint: "localhost:7054",
caTlsCertificate: "/path/to/ca/tls/cert",
caCert: "/path/to/ca/cert",
caKey: "/path/to/ca/key",
ca: "ca.org1.example.com",
};
// Create an adapter instance
const adapter = new FabricAdapter(config, "org1-adapter");
// Use the adapter to interact with the Fabric network
async function createAsset() {
const asset = { id: "asset1", value: "Asset 1 Value" };
return await adapter.create("assets", "asset1", asset, {}, mySerializer);
}
async function readAsset(id: string) {
return await adapter.read("assets", id, mySerializer);
}
async function updateAsset(id: string, newValue: string) {
const asset = await readAsset(id);
asset.value = newValue;
return await adapter.update("assets", id, asset, {}, mySerializer);
}
async function deleteAsset(id: string) {
return await adapter.delete("assets", id, mySerializer);
}
async function queryAssets(owner: string) {
const query = {
selector: {
owner: owner,
},
};
return await adapter.raw(query, true);
}
正在收听链码事件
import { FabricAdapter, FabricDispatch } from "@decaf-ts/for-fabric";
async function setupEventListener(config: PeerConfig) {
// Create a client
const client = await FabricAdapter.getClient(config);
// Create a dispatch instance
const dispatch = new FabricDispatch(client);
// Configure the dispatch with peer configuration
dispatch.configure(config);
// Register an observer for a specific table and event
dispatch.observe("assets", "create", (id) => {
console.log(`Asset created: ${id}`);
// Fetch the new asset or update UI
});
// Start listening for events
await dispatch.start();
// When done, close the connection
// await dispatch.close();
}
使用身份和证书
import {
getIdentity,
getSigner,
readFile,
getCAUser,
} from "@decaf-ts/for-fabric";
async function setupIdentity() {
// Read a certificate file
const tlsCert = await readFile("/path/to/tls/cert");
// Get an identity from a certificate directory
const identity = await getIdentity("Org1MSP", "/path/to/cert/dir");
// Get a signer from a key directory
const signer = await getSigner("/path/to/key/dir");
// Create a CA user
const user = await getCAUser(
"user1",
privateKeyPem,
certificatePem,
"Org1MSP"
);
return { identity, signer, user };
}
链码开发
创建模式
import { Model, id, property, table } from "@decaf-ts/decorator-validation";
@table("assets")
export class Asset extends Model {
@id()
id: string;
@property()
value: string;
@property()
owner: string;
@property()
createdAt: number;
}
创建 CRUD 合同
import { FabricCrudContract } from "@decaf-ts/for-fabric";
import { Context, Contract, Info, Transaction } from "fabric-contract-api";
import { Asset } from "./asset";
@Info({
title: "AssetContract",
description: "Smart contract for trading assets",
})
export class AssetContract extends FabricCrudContract<Asset> {
constructor() {
super("AssetContract", Asset);
}
// The base class already provides standard CRUD operations:
// create, read, update, delete, createAll, readAll, updateAll, deleteAll
// Add custom methods as needed
@Transaction()
async getAssetHistory(ctx: Context, id: string): Promise<any[]> {
const stub = ctx.stub;
const iterator = await stub.getHistoryForKey(id);
const results = [];
let result = await iterator.next();
while (!result.done) {
const value = result.value;
results.push({
txId: value.txId,
timestamp: value.timestamp,
value: JSON.parse(value.value.toString("utf8")),
});
result = await iterator.next();
}
await iterator.close();
return results;
}
@Transaction()
async transferAsset(
ctx: Context,
id: string,
newOwner: string
): Promise<Asset> {
const asset = await this.read(ctx, id);
asset.owner = newOwner;
return await this.update(ctx, asset);
}
}
直接使用合同适配器
import { FabricContractAdapter } from "@decaf-ts/for-fabric";
import { Context, Contract, Transaction } from "fabric-contract-api";
export class CustomContract extends Contract {
private adapter: FabricContractAdapter;
constructor() {
super("CustomContract");
this.adapter = new FabricContractAdapter();
}
@Transaction()
async createRecord(ctx: Context, id: string, data: string): Promise<any> {
const record = { id, data, timestamp: Date.now() };
return await this.adapter.create(
"records",
id,
record,
{},
{ stub: ctx.stub, logger: ctx.logging }
);
}
@Transaction(false)
async queryRecords(ctx: Context, owner: string): Promise<any[]> {
const query = {
selector: {
owner: owner,
},
};
return await this.adapter.raw(query, true, {
stub: ctx.stub,
logger: ctx.logging,
});
}
}
接待和处理事件
import {
FabricContractRepositoryObservableHandler,
generateFabricEventName,
parseEventName,
} from "@decaf-ts/for-fabric";
import { Context } from "fabric-contract-api";
import { OperationKeys } from "@decaf-ts/db-decorators";
// In chaincode: Emit an event
async function emitEvent(ctx: Context, tableName: string, id: string) {
const handler = new FabricContractRepositoryObservableHandler();
const logger = ctx.logging.getLogger("EventHandler");
await handler.updateObservers(logger, tableName, OperationKeys.CREATE, id, {
stub: ctx.stub,
});
}
// In client: Parse an event name
function handleEvent(eventName: string, payload: Buffer) {
const { table, event, owner } = parseEventName(eventName);
const data = JSON.parse(payload.toString());
console.log(`Received ${event} event for ${table} with ID ${data.id}`);
if (owner) {
console.log(`Event owner: ${owner}`);
}
}
关于更详细的实例和API文档,请参见: API 参考。 。 。 .
合同 APIs (Chaincode)
以下例子取材于成品/弧/合同中的合同,并反映了单位/整合测试所用的模式.
FabricCrud 合同
说明:Base Contracting 揭发CRUD一模范类的终点. 它在引擎盖下使用Repository和DeterministicSerializer.
import { Context, Transaction, Contract } from "fabric-contract-api";
import { model, ModelArg, required } from "@decaf-ts/decorator-validation";
import { BaseModel, pk } from "@decaf-ts/core";
import { FabricCrudContract } from "@decaf-ts/for-fabric/contracts";
@model()
class Person extends BaseModel {
@pk({ type: "Number" })
id!: number;
@required() name!: string;
constructor(arg?: ModelArg<Person>) {
super(arg);
}
}
export class PersonContract extends FabricCrudContract<Person> {
constructor() {
super("PersonContract", Person);
}
@Transaction(false)
async ping(ctx: Context): Promise<string> {
// Uses FabricCrudContract.logFor
this.logFor(ctx).info("ping");
return "pong";
}
}
测试中的用法: 参见测试/单位/合同. test.ts模式,其中行使序列化Crud Contract子类; FabricCrud Contract相似,但取回对象而不是JSON字符串.
序列化 合同
描述: 与 FabricCrud Contract 相同的端点, 但取回 JSON 字符串 。 对简单的客户端有用. 根据测试/单位/合同.t.
import { Context } from "fabric-contract-api";
import { model, ModelArg, required } from "@decaf-ts/decorator-validation";
import { BaseModel, pk } from "@decaf-ts/core";
import { SerializedCrudContract } from "@decaf-ts/for-fabric/contracts";
@model()
class TestModel extends BaseModel {
@pk({ type: "Number" }) id!: number;
@required() name!: string;
@required() nif!: string;
constructor(arg?: ModelArg<TestModel>) {
super(arg);
}
}
export class TestModelContract extends SerializedCrudContract<TestModel> {
constructor() {
super("TestModelContract", TestModel);
}
}
// Example invocation (mirrors unit test usage)
async function createExample(contract: TestModelContract, ctx: Context) {
const payload = new TestModel({
name: "Alice",
nif: "123456789",
}).serialize();
const resultJson = await contract.create(ctx, payload);
const created = new TestModel(JSON.parse(resultJson));
return created;
}
包料存储器
说明:链码-侧存储器在合同方法内用于坚持和查询模型.
import { Context } from "fabric-contract-api";
import { Repo } from "@decaf-ts/core";
import { model, required, ModelArg } from "@decaf-ts/decorator-validation";
import { BaseModel, pk } from "@decaf-ts/core";
import { FabricContractRepository } from "@decaf-ts/for-fabric/contracts";
@model()
class Asset extends BaseModel {
@pk() id!: string;
@required() owner!: string;
constructor(arg?: ModelArg<Asset>) {
super(arg);
}
}
export class AssetContract extends Contract {
private repo: Repo<Asset, any, any, any, any>;
constructor() {
super("AssetContract");
this.repo = new FabricContractRepository<Asset>(
new (require("@decaf-ts/for-fabric").contracts.FabricContractAdapter)(),
Asset
);
}
@Transaction()
async Create(ctx: Context, id: string, owner: string): Promise<void> {
const m = new Asset({ id, owner });
await this.repo.create(m, ctx as any);
}
@Transaction(false)
async Read(ctx: Context, id: string): Promise<Asset> {
return this.repo.read(id, ctx as any);
}
@Transaction(false)
async QueryByOwner(ctx: Context, owner: string): Promise<Asset[]> {
return this.repo.raw({ selector: { owner } } as any, true, ctx as any);
}
}
工艺合同DB序列
说明:用于生成递增值的世界状态后置序列.
import { Context } from "fabric-contract-api";
import { FabricContractDBSequence } from "@decaf-ts/for-fabric/contracts";
import { FabricContractAdapter } from "@decaf-ts/for-fabric/contracts";
const adapter = new FabricContractAdapter();
export class OrderContract extends Contract {
private orderSeq = new FabricContractDBSequence(
{
name: "orderSeq",
type: "Number",
startWith: 1,
incrementBy: 1,
},
adapter
);
@Transaction()
async CreateOrder(ctx: Context): Promise<number> {
const next = await this.orderSeq.next(ctx as any);
// use next as order id
return next as number;
}
@Transaction(false)
async NextRange(ctx: Context, count: number): Promise<number[]> {
return (await this.orderSeq.range(count, ctx as any)) as number[];
}
}
配置状态<M,R>
描述:通过Fabric适配器运行芒果查询的桥并取回打入的型号;由寄存器内部使用并直接用于高级病例. 见测试/单元/erc20contract.ts 嘲弄 CouchDB状态处理.
import { FabricStatement } from "@decaf-ts/for-fabric/contracts";
import { FabricContractAdapter } from "@decaf-ts/for-fabric/contracts";
import { FabricContractContext } from "@decaf-ts/for-fabric/contracts";
import { MangoQuery } from "@decaf-ts/for-couchdb";
import { Model } from "@decaf-ts/decorator-validation";
class MyModel extends Model {}
const adapter = new FabricContractAdapter();
async function query(ctx: FabricContractContext) {
const stmt = new FabricStatement<MyModel, MyModel[]>(adapter, ctx);
const models = await stmt.raw<MyModel[]>({
selector: { type: "MyModel" },
} as MangoQuery);
return models;
}
合同
描述: 联系到 Fabric 的上下文, 尊重日志级别 .
import { Context, Transaction } from "fabric-contract-api";
import { Contract } from "fabric-contract-api";
import { ContractLogger } from "@decaf-ts/for-fabric/contracts";
export class LoggableContract extends Contract {
@Transaction()
async DoWork(ctx: Context): Promise<void> {
const log = new ContractLogger(
"LoggableContract",
{ level: "info" },
ctx as any
);
log.info("Starting work");
// ... work ...
log.debug("Finished");
}
}
制造合同存储器
描述: Emits Fabric 事件用于寄存器操作. 也可以直接使用它来发布自定义事件.
import { FabricContractRepositoryObservableHandler } from "@decaf-ts/for-fabric/contracts";
import { OperationKeys } from "@decaf-ts/db-decorators";
import { FabricContractContext } from "@decaf-ts/for-fabric/contracts";
import { MiniLogger } from "@decaf-ts/logging";
async function emitExample(ctx: FabricContractContext) {
const handler = new FabricContractRepositoryObservableHandler();
const log = new MiniLogger("obs");
await handler.updateObservers(
log as any,
"assets",
OperationKeys.CREATE,
"asset1",
ctx
);
}
合同文本
说明:在合同内有特定内容.
import { FabricContractContext } from "@decaf-ts/for-fabric/contracts";
function readContext(ctx: FabricContractContext) {
const ts = ctx.timestamp; // Date from stub.getDateTimestamp()
const id = ctx.identity.getID();
ctx.logger.info(`Tx by ${id} at ${ts.toISOString()}`);
}
FabricERC20 合同(样本)
说明:测试中使用的ERC20全面实施(见测试/单元/erc20contract.ts.
import { FabricERC20Contract } from "@decaf-ts/for-fabric/contracts";
import { FabricContractContext } from "@decaf-ts/for-fabric/contracts";
const contract = new FabricERC20Contract("TestToken");
async function initAndRead(ctx: FabricContractContext) {
const created = await contract.Initialize(ctx, "TestToken", "TT", 18);
if (created) {
const name = await contract.TokenName(ctx);
const decimals = await contract.Decimals(ctx);
return { name, decimals };
}
throw new Error("Init failed");
}
关于试验的说明作为例子
- 测试/单位/合同.test.ts显示创建了串行化的Crud Contact,并用被嘲笑的Fabric上下文调用创建(ctx,jsonPayload).
- 测试/单元/erc20contract.test.ts演示ERC20合同初始化并读取了TokenName.
- 测试/整合/序列化-Contact.test.ts显示基于JSON的端到端CRUD流经序列化合同,包括创建,读取,更新和丰富的查询.
上述例子反映了这些模式,以确保正确性和与存储器测试套件的一致性.
编码原则
- 在文件夹中分组类似的功能( 与命名空间对应, 但没有任何命名空间声明)
- 每个文件一个类别;
- 每个文件一个接口(除非接口只是用作类型);
- 组合类型作为每个文件夹的.ts文件类型中的其他接口;
- 每个文件夹中的常数或常数组;
- 每个文件夹中的装饰器组;
- 总是从特定文件导入, 绝不从文件夹或索引文件导入( 其他软件包的依赖性除外 );
- 在适用的情况下,更倾向于使用既定的设计样板:
- Singleton(可以是反派. * 谨慎使用;
- 工厂;
- 观察员;
- 战略;
- 建造者;
- 诸如此类;
释放文档钩
通过审查与自动释放管道保持一致 发布注释 财务报告和审定财务报表 依赖关系 在尝试这些食谱后(更新于2025-11-26).
相关
社会
语文
获得帮助
如果您有错误报告, 请回答问题或建议 创建一个新问题。 。 。 .
捐款
我感谢对这一项目作出的任何贡献。 请阅读 这个 要开始.
支助
第一种最简单的方法就是支持它 捐款. 甚至在文档中找到打字很重要.
财政支持总是受到欢迎,帮助我和该项目保持生命和健康.
所以,如果你可以, 如果这个项目以任何方式。 要么通过学习 要么只是帮助你 节省宝贵的时间, 请考虑捐赠.
许可证
这个项目将在 Mozilla 公共许可证2.0。 。 。 .
由开发者为开发者...