食品溯源合约 -- 智能合约实例

前提

Roles: 实现对用户地址的角色权限管控,添加、删除角色。

Producer: 生产商角色管控。

...

FoodInfoItem: 食品信息管控。生产商、中间商、超市添加食品信息。

Trace:食品溯源合约,主要负责对以上几个合约的统筹协

Roles

// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;

//角色库(管理所有角色地址)
// 1. 实现增加角色地址
// 2. 移除角色地址
// 3. 判断角色地址是否被授权
library Roles{
    struct Role{
        mapping (address =>bool) bearer;
    }
    // 在 Solidity 中,映射(mapping)不能在函数内部声明为局部变量,
    // 也不能在当前版本(0.8.0)中作为库(library)的成员变量。
   

    // 假如role 显示声明storage,那么算是合约中的状态变量,而且不能是memory
    function add(Role storage role,address account) internal {   
        require(!has(role,account),"Roles:account already has role");
        role.bearer[account] = true;
    }

    function remove(Role storage role,address account) internal {
        require(!has(role,account),"Roles:account has no role ");
        role.bearer[account] = false;
    }

    function has(Role storage role,address account) internal  view returns(bool){
        require(account != address(0),"Roles: account cannot be zero address");
        return role.bearer[account];
    }

}

Producer

PS:这下面这三个都是代表角色,代码几乎一样的,看会这个,其他都会。

// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;
import "./Roles.sol";
/**
*@title Producer
*@dev 
*/
contract Producer {
    using Roles for Roles.Role;

    event ProducerAdded(address indexed account);
    event ProducerRemoved(address indexed account);

    Roles.Role private _producers; // 使用这个相当于使用库

    constructor(address producer){ // 初始化给账户添加权限
        _addProducer(producer);
    }

    // 关于下面这几个函数为什么要拆分?提高代码可读性。


    modifier onlyProducer(){
        require(
            isProducer(msg.sender),
            "Producer:caller has no Producer role"
        );
        _;
    }

     // 用户是否拥有权限
      function isProducer(address account) public view returns (bool) {
        return _producers.has(account);
    }

    function addProducer(address account) public onlyProducer {
        _addProducer(account); // 不是很理解,为什么设置只有生产者角色才能为地址添加生产者角色权限
    }

    function removeRroducer(address account) public  {
        _removeProducer(account);
    }


     function _addProducer(address account) internal {
        _producers.add(account); 
        // 我们看向Roles的add()其实还有一个参数,但是我们 using for 了那个参数就相当于 _producers本身
        emit ProducerAdded(account);
    }

    function _removeProducer(address account) internal {
        _producers.remove(account);
        emit ProducerRemoved(account);
    }
    
}

Retailer

// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;
import "./Roles.sol";

// 超市
contract Retailer {
     using Roles for Roles.Role;

    event RetailerAdded(address indexed account);
    event RetailerRemoved(address indexed account);

    Roles.Role private _retailers; // 使用这个相当于使用库

    constructor(address retailer){ // 初始化给账户添加权限
        _addRetailer(retailer);
    }

    // 关于下面这几个函数为什么要拆分?提高代码可读性。


    modifier onlyRetailer(){
        require(
            isRetailer(msg.sender),
            "Retailer:caller has no Retailer role"
        );
        _;
    }

     // 用户是否拥有权限
      function isRetailer(address account) public view returns (bool) {
        return _retailers.has(account);
    }

    function addRetailer(address account) public onlyRetailer {
        _addRetailer(account); 
    }

    function removeRroducer(address account) public  {
        _removeRetailer(account);
    }


     function _addRetailer(address account) internal {
        _retailers.add(account); 
        // 我们看向Roles的add()其实还有一个参数,但是我们 using for 了那个参数就相当于 _Retailers本身
        emit RetailerAdded(account);
    }

    function _removeRetailer(address account) internal {
        _retailers.remove(account);
        emit RetailerRemoved(account);
    }
    
}

Distributor

// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;
import "./Roles.sol";
// 中间商
contract Distributor {
     using Roles for Roles.Role;

    event DistributorAdded(address indexed account);
    event DistributorRemoved(address indexed account);

    Roles.Role private _distributors; // 使用这个相当于使用库

    constructor(address distributor){ // 初始化给账户添加权限
        _addDistributor(distributor);
    }

    // 关于下面这几个函数为什么要拆分?提高代码可读性。


    modifier onlyDistributor(){
        require(
            isDistributor(msg.sender),
            "Distributor:caller has no Distributor role"
        );
        _;
    }

     // 用户是否拥有权限
      function isDistributor(address account) public view returns (bool) {
        return _distributors.has(account);
    }

    function addDistributor(address account) public onlyDistributor {
        _addDistributor(account); 
    }

    function removeRroducer(address account) public  {
        _removeDistributor(account);
    }


     function _addDistributor(address account) internal {
        _distributors.add(account); 
        // 我们看向Roles的add()其实还有一个参数,但是我们 using for 了那个参数就相当于 _Distributors本身
        emit DistributorAdded(account);
    }

    function _removeDistributor(address account) internal {
        _distributors.remove(account);
        emit DistributorRemoved(account);
    }
    
}

FoodInfoItem

// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;
pragma experimental ABIEncoderV2;

//食品信息管理合约
// 1.	保存食品基本信息:时间戳(流转过程中),用户名(流转过程中),用户地址信息(流转过程中),食品质量(流转过程中),食物名称,当前用户名称,质量,状态.
// 2.	对食品基本信息进行初始化
// 3.	实现两个方法:中间商添加食品信息;超市添加食品信息
// 4.	实现显示食品信息的方法

contract FoodInfoItem {
    uint[] _timestamp;     //保存食品流转过程中各个阶段的时间戳
    string[] _traceName;    //保存食品流转过程各个阶段的用户名
    address[] _traceAddress; //保存食品流转过程各个阶段的用户地址信息(和用户一一对应)
    uint8[] _traceQuality;  //保存食品流转过程中各个阶段的质量
    string _name;  //食品名称
    string _currentTraceName;  //当前用户名称
    uint8 _quality; //质量(0=优质 1=合格 2=不合格)
    uint8 _status; //状态(0:生产 1:分销 2:出售)
    address  _owner;

   // 初始化食品,创建者是生产商
    constructor(string memory name,string memory traceName,uint8 quality,address producer) public  {
        _name = name;
        _currentTraceName = traceName;
        _quality = quality;
        _owner = producer;
        _status = 0;
        // 不多说,看上面状态变量都能明白
        _timestamp.push(block.timestamp); 
        _traceName.push(traceName);
        _traceAddress.push(producer);
        _traceQuality.push(quality);
    }

   // 中间商添加食品信息
    function addTraceInfoByDistributor(
        string memory traceName,
        uint8 quality,
        address distributor
    ) public returns(bool){
        require(_status == 0, "FoddIndo: caller must be distributor");
        _currentTraceName = traceName;
        _quality = quality;
        _status = 1;

        _timestamp.push(block.timestamp); 
        _traceName.push(traceName);
        _traceAddress.push(distributor);
        _traceQuality.push(quality);

        return true;
    }


    // 超市添加食品信息
    function addTraceInfoByRetailer(
        string memory traceName,
        uint8 quality,
        address retailer
    )public returns(bool){
        require(_status == 1, "FoddIndo: caller must be retailer");
        _currentTraceName = traceName;
        _quality = quality;
        _status = 2;

        _timestamp.push(block.timestamp); 
        _traceName.push(traceName);
        _traceAddress.push(retailer);
        _traceQuality.push(quality);
        return true;
    }

    // 拿到食品流转的全部信息
    function getTraceInfo() public view  returns(uint[] memory,string[] memory,address[] memory,uint8[] memory){
        return (
            _timestamp,
            _traceName,
            _traceAddress,
            _traceQuality
        );
    }

    // 拿到生产商一开始添加食品信息
    function getFood() public view returns(uint,string memory,address,uint8,string memory){
        return (
            _timestamp[0],
            _traceName[0],
            _traceAddress[0],
            _traceQuality[0],
            _name
        );
    }

}


Trace

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
pragma experimental ABIEncoderV2; // 开启实验性功能,包括对map,数组的编码和解码等
import "./FoodInfoItem.sol";
import "./Distributor.sol";
import "./Producer.sol";
import "./Retailer.sol";

//食品溯源合约(负责具体食品溯源信息的生成)
//  1.实现生产食品的方法(新建食品信息)
//  2.实现食品分销过程中增加溯源信息的接口
//  3.实现食品出售过程中增加溯源信息的接口
//  4.实现获取食品溯源信息接口

contract Trace is Distributor,Producer,Retailer {
    mapping(uint256 => address) foods; //食品溯源id到 -> 具体食品溯源合约的映射表
    uint[] foodList; // 食品溯源id数组

    //构造函数初始化,一起把父类角色初始化
    constructor(
        address producer,
        address distributor,
        address retailer
    )    Producer(producer) Distributor(distributor) Retailer(retailer) {}

    // 生产商调用,调用添加食品信息
    function newFood(
        string memory name,
        uint256 traceNumber, // 溯源id
        string memory traceName,
        uint8 quality
    ) public onlyProducer returns (address) {
        require(foods[traceNumber] == address(0), "Trace:traceNumber already exist"); // 检测溯源id对应食品合约是否已经存在,已存在id不能用。
        FoodInfoItem food = new FoodInfoItem( // 初始化食品合约
            name,
            traceName,
            quality,
            msg.sender
        );
        foods[traceNumber] = address(food); // 往映射表添加地址
        foodList.push(traceNumber); // 往食品溯源数组添加溯源id
        return address(food);
    }

   // 中间商调用,添加食品信息
    function addTraceInfoByDistributor(
        uint256 traceNumber,
        string memory traceName,
        uint8 quality
    ) public onlyDistributor returns (bool) {
        require(foods[traceNumber] != address(0), "Trace:traceNumber does not exist"); // id 对应食品合约没存在,代表没食品
        return
            FoodInfoItem(foods[traceNumber]).addTraceInfoByDistributor(traceName,quality,msg.sender); // 调用对应的食品合约方法
    }

   // 超市调用,添加食品信息
    function addTraceInfoByRetailer(
        uint256 traceNumber,
        string memory traceName,
        uint8 quality
    ) public onlyRetailer returns (bool) {
        require(foods[traceNumber] != address(0), "Trace:traceNumber does not exist");
        return
            FoodInfoItem(foods[traceNumber]).addTraceInfoByRetailer(traceName,quality,msg.sender);
    }

    // 拿到所有食品信息
    function getTraceInfo(
        uint256 traceNumber
    ) public view returns (uint[] memory,string[] memory,address[] memory,uint8[] memory) {
        require(foods[traceNumber] != address(0), "Trace:traceNumber does not exist");
        return FoodInfoItem(foods[traceNumber]).getTraceInfo();
    }

    //拿到单条食品信息
    function getFood(
        uint256 traceNumber
    ) public view returns (uint,string memory,address,uint8,string memory) {
        require(foods[traceNumber] != address(0), "Trace:traceNumber does not exist");
        return FoodInfoItem(foods[traceNumber]).getFood();
    }

    // 拿到全部食品的溯源id数组
    function getAllFood() public view returns (uint[] memory) {
        return foodList;
    }

}

核心流程演示

1.创建Trace合约,赋予三个地址生产商、中间商、超市权限。

2.利用上述producer地址,调用newFood接口

结果成功,我就不演示了。

3.利用上述distributor地址,调用addTraceInfoByDistributor接口

4.利用上述retailer地址,调用addTraceInfoByRetailer接口

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
超级账本是一种基于区块链技术的分布式账本平台,它提供了一种安全、透明、可靠的方式来记录和管理数据。在农产品溯源领域,超级账本可以帮助实现农产品的全生命周期管理,包括种植、采摘、运输、加工、销售等环节的信息记录和追溯。 智能合约是超级账本核心功能之一,它可以在区块链上自动执行预先设定的程序代码,实现数据的自动验证、转移和管理。在农产品溯源中,智能合约可以用于管理农产品信息、监控农产品流通、验证农产品质量等方面。 具体来说,农产品溯源智能合约可以包括以下功能: 1. 农产品信息管理:智能合约可以记录农产品的基本信息,如品种、产地、生产日期、生产者、采摘日期等,方便消费者查询和验证。 2. 农产品流通管理:智能合约可以记录农产品在运输、加工、销售等环节中的信息,如运输路线、加工工艺、销售渠道等,方便监控农产品流通情况。 3. 农产品质量验证:智能合约可以实现农产品质量检测和验证,如对农产品进行化验、检测、鉴定等,确保农产品质量符合标准要求。 4. 农产品溯源追溯:智能合约可以记录农产品的全生命周期信息,方便消费者通过区块链追溯农产品的来源、生产过程、流通情况等,保证农产品的安全和可靠性。 总之,农产品溯源智能合约的开发可以实现农产品的全生命周期管理和追溯,提高消费者对农产品的信任度和满意度,促进农产品的健康发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

本郡主是喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值