You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在Composer中订阅资产创建事件?及替代实现方案咨询

Answers to Your Hyperledger Fabric Event & Function Trigger Questions

Absolutely, both of your needs are fully achievable in Hyperledger Fabric—let’s walk through each scenario step by step:

1. Receiving Events on Asset Creation to Execute Actions

This is not only feasible but also a common pattern for integrating external systems or triggering post-creation workflows. Here’s how to implement it:

Step 1: Emit an Event from Your Chaincode

When your chaincode’s asset creation function (e.g., CreateAsset) successfully writes the asset to the ledger, use the chaincode stub to emit a custom event with relevant asset details.

Example Go chaincode snippet:

func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, assetID string, value string) error {
    // Check if asset already exists
    exists, err := s.AssetExists(ctx, assetID)
    if err != nil {
        return err
    }
    if exists {
        return fmt.Errorf("the asset %s already exists", assetID)
    }

    asset := Asset{
        ID:    assetID,
        Value: value,
    }
    assetJSON, err := json.Marshal(asset)
    if err != nil {
        return err
    }

    // Write asset to ledger
    err = ctx.GetStub().PutState(assetID, assetJSON)
    if err != nil {
        return err
    }

    // Emit custom event with asset data
    err = ctx.GetStub().SetEvent("AssetCreated", []byte(assetID))
    if err != nil {
        return err
    }

    return nil
}

Step 2: Listen for the Event via Node SDK

Use the Fabric Node SDK to register a listener for the AssetCreated event. You can listen at the contract level or block level, depending on your needs.

Example Node SDK code:

const { Gateway, Wallets } = require('fabric-network');
const path = require('path');

async function listenForAssetEvents() {
    const walletPath = path.join(__dirname, 'wallet');
    const wallet = await Wallets.newFileSystemWallet(walletPath);
    
    const gateway = new Gateway();
    const connectionProfile = path.join(__dirname, 'connection-org1.json');
    const connectionOptions = {
        wallet,
        identity: 'user1',
        discovery: { enabled: true, asLocalhost: true }
    };

    await gateway.connect(connectionProfile, connectionOptions);
    const network = await gateway.getNetwork('mychannel');
    const contract = network.getContract('mychaincode');

    // Register a contract listener for the AssetCreated event
    const listener = async (event) => {
        const assetID = event.payload.toString();
        console.log(`Received AssetCreated event for asset: ${assetID}`);
        
        // Execute your custom action here (e.g., update external database, send notification)
        await performPostCreationAction(assetID);
    };

    // Start listening (use 'unregister()' later to stop)
    await contract.addContractListener('assetCreatedListener', 'AssetCreated', listener);
}

async function performPostCreationAction(assetID) {
    // Your custom business logic goes here
    console.log(`Executing post-creation action for asset ${assetID}`);
}

listenForAssetEvents().catch(err => {
    console.error(`Error listening for events: ${err}`);
    process.exit(1);
});

Key notes:

  • Events are only emitted after the transaction is successfully committed to the ledger, so you don’t have to worry about handling uncommitted transactions.
  • Remember to handle listener reconnection logic if the connection drops—you can wrap the listener setup in a retry loop.

2. Alternative: Trigger a Specific Function When an Asset is Added

If you prefer to handle the workflow entirely within the chaincode (no external listeners), you can directly call a dedicated function after asset creation. This keeps all logic within the distributed ledger’s transaction context.

Option 1: Direct Function Call in Chaincode

Modify your CreateAsset function to invoke a post-processing function immediately after writing the asset. Since this happens in the same transaction, any failure in the post-processing will roll back the entire asset creation (which is useful for maintaining data consistency).

Example Go chaincode snippet:

func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, assetID string, value string) error {
    // ... (existing asset creation logic)

    // After successful asset write, call post-processing function
    err = s.OnAssetCreated(ctx, assetID, value)
    if err != nil {
        return err
    }

    return nil
}

// Dedicated function to run on asset creation
func (s *SmartContract) OnAssetCreated(ctx contractapi.TransactionContextInterface, assetID string, value string) error {
    // Your custom logic here: e.g., update related assets, log audit info, trigger other business rules
    fmt.Printf("Processing new asset %s with value %s\n", assetID, value)
    
    // Example: Write an audit entry to the ledger
    auditEntry := AuditEntry{
        AssetID: assetID,
        Timestamp: time.Now().UTC().String(),
        Action: "CREATED",
    }
    auditJSON, err := json.Marshal(auditEntry)
    if err != nil {
        return err
    }
    return ctx.GetStub().PutState(fmt.Sprintf("audit_%s", assetID), auditJSON)
}

Option 2: Use a Generic Entry Function (Advanced)

If you want more flexibility, you can create a generic Invoke function that routes to specific handlers based on the operation type, including triggering post-creation logic. However, this is more complex and usually unnecessary unless you need dynamic routing.


内容的提问来源于stack exchange,提问作者Stefan Bates

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:57:24