Blockchain for Traceability and Transparency in Supply Chain Management

Supply chains often struggle with limited visibility, data manipulation, and difficulty in verifying the origins of products. Blockchain technology addresses these issues by recording every transaction in a tamper-proof, shared ledger accessible to all participants. Each product’s movement can be traced from source to destination with complete accuracy and transparency. This approach fosters trust among suppliers, manufacturers, and consumers while minimizing fraud, delays, and compliance risks throughout the process.



Prerequisites

Before starting, ensure you have:


  • Development Environment: Docker (v20+), Node.js (v14+), npm/yarn, Go (v1.18+ for Fabric chaincode), and Git.

  • Hyperledger Fabric: Download Fabric samples and binaries (v2.5.x recommended) from the official GitHub repo.

  • Blockchain Knowledge: Basics of distributed ledgers, smart contracts (chaincode in Fabric), and consensus mechanisms.

  • IDE: VS Code with Fabric extensions or Hyperledger Composer (deprecated; use Fabric SDKs).

  • Test Tools: Postman for API testing; access to a cloud provider like AWS Blockchain or IBM Blockchain Platform for deployment.

  • Additional: IoT simulation tools (e.g., Node-RED) for real-world data feeds.


Install Fabric:


curl -sSLO https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/bootstrap.sh

chmod +x bootstrap.sh

./bootstrap.sh 2.5.0

export PATH=${PWD}/bin:$PATH

Step 1: Design the Blockchain System

Core Components

  • Assets: Represent products (e.g., drug batches) with attributes like ID, origin, batch number, and expiration date.

  • Participants: Roles such as Supplier, Manufacturer, Distributor, Retailer; each with digital identities (MSPs in Fabric).

  • Transactions (Chaincode Functions):

    1. CreateAsset: Initialize a product record.

    2. UpdateAsset: Log events like shipment or inspection (e.g., temperature check).

    3. QueryAsset: Retrieve history for traceability.

    4. TransferAsset: Hand over custody with endorsements.

  • Channels: Private sub-networks for confidential data sharing (e.g., a channel for suppliers only).

  • Data Flow:

    1. Supplier creates an asset on the blockchain.

    2. Manufacturer updates with production details.

    3. IoT sensors feed real-time data (e.g., GPS for shipment).

    4. Retailer queries for verification; smart contracts automate alerts for anomalies.


For our example: Track a drug batch. Use Fabric's endorsement policy to require multi-party approval for updates.

Architecture

  • Off-Chain Integration: IoT devices, ERP systems (e.g., SAP) feed data via APIs.

  • On-Chain: Immutable log of events; off-chain storage (e.g., IPFS) for large files like certificates.

Step 2: Implement the Chaincode (Smart Contracts)

We'll implement chaincode in Go for Fabric. Create a basic asset_transfer chaincode for product tracking.


Set Up the Project:


mkdir supply-chain-blockchain && cd supply-chain-blockchain

mkdir chaincode && cd chaincode

go mod init supplychain


Define the asset structure in asset.go:


package main


import (

    "encoding/json"

    "fmt"

    "github.com/hyperledger/fabric-contract-api-go/contractapi"

)


type SmartContract struct {

    contractapi.Contract

}


type Product struct {

    ID            string `json:"id"`

    Owner         string `json:"owner"`

    BatchNumber   string `json:"batchNumber"`

    Origin        string `json:"origin"`

    Status        string `json:"status"` // e.g., "Manufactured", "Shipped"

    Timestamp     string `json:"timestamp"`

    History       []Event `json:"history"`

}


type Event struct {

    Type     string `json:"type"`

    Location string `json:"location"`

    Data     string `json:"data"`

}


// Create a new product asset

func (s *SmartContract) CreateProduct(ctx contractapi.TransactionContextInterface, id string, batchNumber string, origin string) error {

    exists, err := s.AssetExists(ctx, id)

    if err != nil {

        return err

    }

    if exists {

        return fmt.Errorf("product %s already exists", id)

    }


    product := Product{

        ID:          id,

        Owner:       ctx.GetClientIdentity().GetID(),

        BatchNumber: batchNumber,

        Origin:      origin,

        Status:      "Created",

        Timestamp:   ctx.GetStub().GetTxTimestamp().AsString(),

        History:     []Event{},

    }

    productJSON, err := json.Marshal(product)

    if err != nil {

        return err

    }


    return ctx.GetStub().PutState(id, productJSON)

}


// Update product status (e.g., shipment)

func (s *SmartContract) UpdateProduct(ctx contractapi.TransactionContextInterface, id string, newStatus string, location string, data string) error {

    productJSON, err := ctx.GetStub().GetState(id)

    if err != nil {

        return fmt.Errorf("failed to read from world state: %v", err)

    }

    if productJSON == nil {

        return fmt.Errorf("product %s does not exist", id)

    }


    var product Product

    err = json.Unmarshal(productJSON, &product)

    if err != nil {

        return err

    }


    event := Event{Type: newStatus, Location: location, Data: data}

    product.History = append(product.History, event)

    product.Status = newStatus

    product.Owner = ctx.GetClientIdentity().GetID()

    product.Timestamp = ctx.GetStub().GetTxTimestamp().AsString()


    productJSON, err = json.Marshal(product)

    if err != nil {

        return err

    }


    return ctx.GetStub().PutState(id, productJSON)

}


// Query product history for traceability

func (s *SmartContract) GetProductHistory(ctx contractapi.TransactionContextInterface, id string) (*Product, error) {

    productJSON, err := ctx.GetStub().GetState(id)

    if err != nil {

        return nil, fmt.Errorf("failed to read from world state: %v", err)

    }

    if productJSON == nil {

        return nil, fmt.Errorf("product %s does not exist", id)

    }


    var product Product

    err = json.Unmarshal(productJSON, &product)

    if err != nil {

        return nil, err

    }


    return &product, nil

}


// Check if asset exists

func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {

    productJSON, err := ctx.GetStub().GetState(id)

    if err != nil {

        return false, err

    }

    return productJSON != nil, nil

}


func main() {

    assetChaincode, err := contractapi.NewChaincode(&SmartContract{})

    if err != nil {

        fmt.Printf("Error creating supplychain chaincode: %v", err)

        return

    }

    if err := assetChaincode.Start(); err != nil {

        fmt.Printf("Error starting supplychain chaincode: %v", err)

    }

}

Key Notes on Code

  • Endorsement: In Fabric, transactions require endorsements from specific peers (e.g., manufacturer and distributor must agree on updates).

  • Privacy: Use private data collections for sensitive info (e.g., pricing).

  • Events: Emit Fabric events for off-chain notifications (e.g., via Kafka).

  • Security: Validate inputs; use Fabric's MSP for identity management.

Step 3: Deploy and Test the Chaincode

Deployment with Fabric

Start a Test Network:


cd fabric-samples/test-network

./network.sh up createChannel


Package and Install Chaincode:


peer lifecycle chaincode package supplychain.tar.gz --path ../chaincode --lang golang

# Install on peers (follow Fabric docs for full lifecycle)

peer lifecycle chaincode install supplychain.tar.gz

peer lifecycle chaincode approveformyorg ...

peer lifecycle chaincode commit ...


Invoke Chaincode:


peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -C mychannel -n supplychain --peerAddresses localhost:7051 --tlsRootCertFiles peers/tls/ca.crt -c '{"function":"CreateProduct","Args":["PHARM001","BATCH123","SupplierA"]}'

Testing

Use Fabric's test network or write Go tests in chaincode_test.go:


func TestCreateProduct(t *testing.T) {

    // Mock transaction context and test CreateProduct

    // Use fabric-contract-api-go's mock for simulation

}


  • Run: go test ./chaincode.

  • Query via CLI: peer chaincode query -C mychannel -n supplychain -c '{"function":"GetProductHistory","Args":["PHARM001"]}'.

  • Simulate multi-party: Use different client identities for updates.

Step 4: Integrate with Frontend and External Systems

SDK Integration: Use Fabric Node.js SDK for applications.


Example (Node.js client):


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

const fs = require('fs');

const path = require('path');


async function main() {

    const walletPath = path.join(process.cwd(), 'wallet');

    const wallet = await Wallets.newFileSystemWallet(walletPath);

    const gateway = new Gateway();

    await gateway.connect(ccpPath, { wallet, identity: 'manufacturer', discovery: { enabled: true } });

    const network = await gateway.getNetwork('mychannel');

    const contract = network.getContract('supplychain');

    await contract.submitTransaction('CreateProduct', 'PHARM001', 'BATCH123', 'SupplierA');

    console.log('Transaction complete.');

    await gateway.disconnect();

}

main();


Frontend: Build a dashboard with React/Vue.js and Fabric SDK. Display traceability timelines (e.g., using D3.js for visualizations). IoT/ERP Integration:


  • Use MQTT or APIs to feed sensor data (e.g., temperature logs) into the chaincode.

  • Integrate with legacy systems via middleware (e.g., MuleSoft) that translates events to blockchain transactions.


Standards Compliance: Adopt GS1 EPCIS for event data; use IPFS for storing proofs (e.g., lab tests).

Comments

Popular posts from this blog

Blockchain-based Voting Systems for Electoral Transparency

Securing Electronic Health Records with Blockchain

Blockchain Frameworks for Real-time IoT Device Management