基于Hyperledger Composer的注册表开发:图像上传集成与智能合约创建
Hey there! Let's tackle your two questions step by step—building a registry with Composer involves balancing on-chain logic with practical off-chain handling for large assets like images, so let's dive in.
1. Integrating Image Upload with Hyperledger Fabric & Composer
First off: never store raw images directly on the Fabric blockchain—it's inefficient, bloats the ledger, and goes against best practices. Instead, we use an off-chain storage solution for the actual image, and store a verifiable reference (like a hash or content ID) on-chain. Here's how to implement this:
Step 1: Define Your Asset Model
In your business network's .cto file, extend your registry asset to include fields for image metadata. For example:
namespace org.example.registry asset RegistryAsset identified by assetId { o String assetId o String name o String imageHash // SHA-256 hash of the image file (for integrity verification) o String imageStorageUrl // URL/address to the off-chain stored image --> Participant owner } participant User identified by userId { o String userId o String fullName }
Step 2: Choose an Off-Chain Storage Solution
Pick a storage system that fits your needs:
- IPFS: Decentralized, content-addressed storage—uploading an image gives you a unique CID (Content Identifier) to store on-chain.
- Cloud Storage (S3/GCS): Centralized, easy to integrate—store the image here and save the public URL on-chain.
- Local File Storage: For testing or private networks—save the image to a server directory and store the accessible file path.
Step 3: Handle Upload & Chain Update in Your Application
Your frontend/backend will manage the image upload first, then trigger a Composer transaction to update the on-chain asset:
- User uploads the image to your chosen off-chain storage.
- Generate a SHA-256 hash of the image file (to ensure anyone can later verify the image matches the on-chain reference).
- Call a Composer transaction to create/update the
RegistryAssetwith theimageHashandimageStorageUrl.
Step 4: Add Transaction Logic (Script.js)
Write a transaction function to validate and create the asset:
/** * Add a new registry asset with image metadata * @param {org.example.registry.AddRegistryAsset} tx * @transaction */ async function addRegistryAsset(tx) { // Verify the requester is a registered user const user = getCurrentParticipant(); if (!user) { throw new Error('Only registered users can add assets to the registry'); } // Create the new asset const factory = getFactory(); const asset = factory.newResource('org.example.registry', 'RegistryAsset', tx.assetId); asset.name = tx.name; asset.imageHash = tx.imageHash; asset.imageStorageUrl = tx.imageStorageUrl; asset.owner = factory.newRelationship('org.example.registry', 'User', user.userId); // Add the asset to the registry const assetRegistry = await getAssetRegistry('org.example.registry.RegistryAsset'); await assetRegistry.add(asset); }
2. Creating the Smart Contract for Your Registry
In Hyperledger Composer, your "smart contract" combines asset/participant definitions, transaction logic, and access control rules. Here's how to build a robust registry contract:
Step 1: Define Core Transactions
Add transactions for key registry operations in your .cto file:
transaction AddRegistryAsset { o String assetId o String name o String imageHash o String imageStorageUrl } transaction UpdateRegistryAsset { o String assetId o String name optional o String imageHash optional o String imageStorageUrl optional } transaction DeleteRegistryAsset { o String assetId }
Step 2: Implement Transaction Logic
Expand your Script.js to handle update/delete operations with validation:
/** * Update an existing registry asset * @param {org.example.registry.UpdateRegistryAsset} tx * @transaction */ async function updateRegistryAsset(tx) { const assetRegistry = await getAssetRegistry('org.example.registry.RegistryAsset'); const asset = await assetRegistry.get(tx.assetId); // Only the asset owner or admin can update it const currentUser = getCurrentParticipant(); if (asset.owner.userId !== currentUser.userId && currentUser.getType() !== 'org.example.registry.Admin') { throw new Error('You do not have permission to update this asset'); } // Update fields if provided if (tx.name) asset.name = tx.name; if (tx.imageHash) asset.imageHash = tx.imageHash; if (tx.imageStorageUrl) asset.imageStorageUrl = tx.imageStorageUrl; await assetRegistry.update(asset); } /** * Delete a registry asset * @param {org.example.registry.DeleteRegistryAsset} tx * @transaction */ async function deleteRegistryAsset(tx) { const assetRegistry = await getAssetRegistry('org.example.registry.RegistryAsset'); const asset = await assetRegistry.get(tx.assetId); const currentUser = getCurrentParticipant(); if (asset.owner.userId !== currentUser.userId && currentUser.getType() !== 'org.example.registry.Admin') { throw new Error('You do not have permission to delete this asset'); } await assetRegistry.remove(asset); }
Step 3: Set Up Access Control (permissions.acl)
Define who can perform which actions with your assets and transactions:
rule AdminFullAccess { description: "Admins can perform all actions on the registry" participant: "org.example.registry.Admin" operation: ALL resource: "org.example.registry.*" action: ALLOW } rule UserManageOwnAssets { description: "Users can add, update, delete their own registry assets" participant: "org.example.registry.User" operation: CREATE, UPDATE, DELETE resource: "org.example.registry.RegistryAsset" condition: (resource.owner.getIdentifier() === participant.getIdentifier()) action: ALLOW } rule UserViewAllAssets { description: "Users can view all registry assets" participant: "org.example.registry.User" operation: READ resource: "org.example.registry.RegistryAsset" action: ALLOW }
Step 4: Test & Deploy
- Use Composer Playground to test your transactions and permission rules.
- Package your business network with
composer archive create -t dir -n ., then deploy it to your Fabric network usingcomposer network installandcomposer network start.
内容的提问来源于stack exchange,提问作者Fam

