zoukankan      html  css  js  c++  java
  • Solidity合约:玉米生产溯源

    实现思路:

    首先用地址与每个结构进行映射,将关键信息储存在结构体中;或者将关键信息在外部通过json储存,内部储存对应的hash值;

    使用issue函数表示:玉米地中收获足够数量的玉米并进行记录;

    使用transfer函数表示:玉米在源产地与经销商手中流转,最终流转至消费者手中;

    使用getCornCount函数:查询当前该角色所拥有的玉米数量;

    使用IsInHead函数:判断当前该角色是否为玉米源产地;

    使用LeafQuery函数:消费者查询玉米的来路,进行溯源操作;

    使用NodeQueryFloor函数:经销商查询玉米的去路,进行商品去路调研获取数据,以便后期进行分析;

    话不多说,先上代码:

      1 pragma solidity ^0.4.11;
      2 
      3 //注意一些关键原则
      4 //自己不能给自己转玉米:确保不形成自环,且无现实意义;
      5 //每个地址代表一个角色;
      6 
      7 contract FindCorn {
      8     // 三种关键角色 源产地 经销商与消费者
      9     struct Consumer_Dealer_Origin {
     10         uint count;             //当前代表角色玉米总数
     11         //string place;           //当前代表角色地理位置信息
     12         //uint begin_time;        //当前代表角色获得玉米时刻
     13         //uint end_time;          //当前代表角色失去玉米时刻
     14         
     15         //以上多点均为玉米溯源过程中所需信息
     16         //可以根据具体需求进行增减
     17         //重点关注整体的框架设计及信息的流转
     18         address father;         //连接当前父节点
     19         address[] child;        //连接当前节点的子节点
     20     }
     21     
     22     address[] Head;            //存储root节点信息
     23     mapping(address => Consumer_Dealer_Origin) identify;    //当前角色与其地址的映射关系
     24     
     25     // function GetNewNode(string placename) returns(Consumer_Dealer_Origin) {
     26     //     Consumer_Dealer_Origin A = new Consumer_Dealer_Origin({
     27     //       count : 0,
     28     //       place : "",
     29     //       begin_time : 0,
     30     //       end_time : 0,
     31            
     32     //       father : '0x00000000'
     33 
     34     //     });
     35     //     return A;
     36     // }    
     37     
     38     //收获玉米啦,取到多少算多少
     39     function issue(address input,uint count) returns (string, address, uint) {
     40         identify[input].count = identify[input].count + count;
     41     //    identify[input].begin_time = nowtime;
     42         Head.push(input);
     43         return ("add corn success!",input,count);
     44     }    
     45     
     46     //玉米流通啦,卖玉米啦
     47     //地址本身不能进行玉米流通
     48     function transfer(address from1,address to,uint num) returns (string,bool){
     49         if(from1==to){
     50             return ("you can't transfer corn to yourself",false);
     51         }else if(num==0){
     52             return ("you can't transfer zero corn to others",false);
     53         }
     54         if(identify[from1].count>=num){
     55             identify[from1].count = identify[from1].count - num;
     56             identify[to].count = identify[to].count + num;
     57             
     58             //确定玉米流通的流向关系
     59             identify[from1].child.push(to);
     60             identify[to].father = from1;
     61             
     62             return ("add the corn success!",true);
     63         }
     64         return ("this from1 don't have enough corn!",false);
     65     }
     66     
     67     //查询账户剩余玉米数
     68     function getCornCount(address query) returns (address,uint){
     69         return (identify[query].father, identify[query].count);
     70     }
     71     
     72 
     73     function IsInHead(address i) returns (bool){
     74         for(uint j=0;j < Head.length;j++){
     75             if(Head[j]==i)
     76                 return true;
     77         }
     78         return false;
     79     }
     80     
     81     address []addrpath = new address[](1);
     82     //消费者查询:我的玉米从哪里来
     83     function LeafQuery(address consumer) returns (address[]){
     84         addrpath.length = 0;
     85         addrpath[addrpath.length++]=consumer;
     86         while(!IsInHead(addrpath[addrpath.length-1])){
     87             consumer = identify[addrpath[addrpath.length-1]].father;
     88             addrpath[addrpath.length++]=consumer;
     89         }
     90         return addrpath;
     91     }
     92     
     93     //经销商查询:我的玉米从哪里来
     94     function NodeQueryCeil(address corn) returns (address[]) {
     95         return LeafQuery(corn);
     96     }
     97     
     98     //经销商查询:玉米去哪了
     99     address []queue = new address[](1);
    100     uint index1;
    101     uint index2;
    102     function NodeQueryFloor(address corn) returns (address[]){
    103         //对经销商节点开始进行层次遍历,查找出所有的叶子节点
    104         index1=0;
    105         index2=1;
    106         addrpath.length = 0;
    107         queue.length=0;
    108         queue[queue.length++]=corn;
    109         while(index1!=index2){
    110             if(identify[queue[index1]].child.length==0){
    111                 addrpath[addrpath.length++]=queue[index1];
    112             }
    113             index2 = index2+identify[queue[index1]].child.length;
    114             for(uint i=0;i<identify[queue[index1]].child.length;i++){
    115                 queue[queue.length++]=identify[queue[index1]].child[i];
    116             }
    117             index1++;
    118         }
    119         return addrpath;
    120     }
    121 }    

    假设0x1地址是玉米地,其中0x2、0x3、0x6都是玉米经销商,0x4、0x5、0x7、0x8都是玉米消费者,那么他们最后的玉米流转关系图如下图中的树关系:

    首先执行issue方法,给0x1地址冲入玉米,表示从玉米地收获玉米;

    Function [issue] invoking...
    Invoke args:
    From
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c
    To
    0xf90cfc79dda26f368da31dc0b7944d25ca9a2407
    Constant
    false
    Payload
    867904b400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000002710
    Invoke finish
    Result
    0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000001161646420636f726e207375636365737321000000000000000000000000000000
    Decoded
    ["string: add corn success!","address: 0x1","uint256: 10000"]
    TxHash
    0x86930a394106caf46f2aef7d77772d51a6ba2a555a8a1bd24f148f3200cf23a1
    From
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c
    To
    0xf90cfc79dda26f368da31dc0b7944d25ca9a2407

    然后开始转运玉米,包括:

    1到2;1到3;2到4;2到5;3到6;6到7;7到8;

    transfer方法:

    Function [transfer] invoking...
    Invoke args:
    From
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c
    To
    0xf90cfc79dda26f368da31dc0b7944d25ca9a2407
    Constant
    false
    Payload
    beabacc8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000064
    Invoke finish
    Result
    0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000156164642074686520636f726e2073756363657373210000000000000000000000
    Decoded
    ["string: add the corn success!","bool: true"]
    TxHash
    0x356356817753e1ffba1378f9b0f48e0253f56e7dadb75004c53b156b984a983e
    From
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c
    To
    0xf90cfc79dda26f368da31dc0b7944d25ca9a2407

    消费者开始溯源手头的玉米流转流程:

    LeafQuery:

    Function [LeafQuery] invoking...
    Invoke args:
    From
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c
    To
    0xf90cfc79dda26f368da31dc0b7944d25ca9a2407
    Constant
    false
    Payload
    210d7dec0000000000000000000000000000000000000000000000000000000000000008
    Invoke finish
    Result
    0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001
    Decoded
    ["address[]: 0x8, 0x6, 0x3, 0x1"]
    TxHash
    0xd2019faf0ce53479768ed7564d2394dc2bb95a11f641bdbf93b29b3c9c927689
    From
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c
    To
    0xf90cfc79dda26f368da31dc0b7944d25ca9a2407

    经销商0x3查询玉米去哪里了:

    Function [NodeQueryFloor] invoking...
    Invoke args:
    From
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c
    To
    0xf90cfc79dda26f368da31dc0b7944d25ca9a2407
    Constant
    false
    Payload
    ec6d9c640000000000000000000000000000000000000000000000000000000000000003
    Invoke finish
    Result
    0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008
    Decoded
    ["address[]: 0x7, 0x8"]
    TxHash
    0xd5d791fb4a3185aba42dfd30ec371a4e7fcfb66127ce13e3f617811c361389c7
    From
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c
    To
    0xf90cfc79dda26f368da31dc0b7944d25ca9a2407

     修改后完善代码,警告(当前代码的数据可能是仅仅只保存在内存当中的,可能会出现丢失的情况,需要将其完善成固定存储)

      1 pragma solidity ^0.4.11;
      2 
      3 //使用继承的方式书写合约 使得整体逻辑变清晰
      4 contract Corn {
      5     //收获玉米,向源产地对象地址产出的玉米数量进行记录
      6     function harvestCorn(address input, uint count)  returns(string, address, uint){}
      7 
      8     //玉米流通,将玉米在不同角色中流转的数量关系及对象关系进行记录
      9     function transpartCorn(address from1, address to, uint num) returns(string, bool){}
     10 
     11     //获取当前对象地址的玉米数量
     12     function getCornCount(address query) returns(address, uint){}
     13 
     14     //判断当前对象是否属于源产地
     15     function isInHead(address i) returns(bool) {}
     16 
     17     //从当前对象出发查询商品来源
     18     function nodeQueryCeil(address corn) returns(address[]) {}
     19 
     20     //从当前对象出发查询商品流向
     21     function nodeQueryFloor(address corn) returns(address[], address[]) {}
     22 
     23     //消费者查询当前商品来源
     24     function leafQuery(address consumer) returns(address[]){}
     25 }
     26 
     27 contract FindCorn is Corn{
     28     // 三种关键角色 源产地 经销商与消费者
     29     struct Consumer_Dealer_Origin {
     30         uint count; //当前代表角色玉米总数
     31         address father; //连接当前父节点
     32         address[] child; //连接当前节点的子节点
     33     }
     34 
     35     address[] Head; //存储root节点信息 用来代表分片玉米地
     36     mapping(address => Consumer_Dealer_Origin) identify; //当前角色与其地址的映射关系
     37 
     38     //收获玉米啦 对收获的玉米进行数量记录,同时所有收获的玉米属于同一个生产地
     39     function harvestCorn(address input, uint count) returns(string, address, uint) {
     40         identify[input].count = identify[input].count + count;
     41         bool flag = false;
     42         for (uint i = 0; i < Head.length; i++) {
     43             if (input == Head[i]) {
     44                 flag = true;
     45                 break;
     46             }
     47         }
     48         if (!flag) {
     49             Head.push(input);
     50         }
     51 
     52         return ("add corn success!", input, count);
     53     }
     54 
     55     //玉米流通啦,卖玉米啦
     56     //地址本身不能进行玉米流通
     57     function transpartCorn(address from1, address to, uint num) returns(string, bool) {
     58         if (from1 == to) {
     59             return ("you can't transfer corn to yourself", false);
     60         } else if (num == 0) {
     61             return ("you can't transfer zero corn to others", false);
     62         }
     63         if (identify[from1].count >= num) {
     64             identify[from1].count = identify[from1].count - num;
     65             identify[to].count = identify[to].count + num;
     66 
     67             //确定玉米流通的流向关系
     68             identify[from1].child.push(to);
     69             identify[to].father = from1;
     70 
     71             return ("add the corn success!", true);
     72         }
     73         return ("this from1 don't have enough corn!", false);
     74     }
     75 
     76     //查询账户剩余玉米数
     77     function getCornCount(address query) returns(address, uint) {
     78         return (identify[query].father, identify[query].count);
     79     }
     80 
     81 
     82     //判断当前地址所对应的对象是否属于玉米某片地的角色
     83     function isInHead(address i) returns(bool) {
     84         for (uint j = 0; j < Head.length; j++) {
     85             if (Head[j] == i)
     86                 return true;
     87         }
     88         return false;
     89     }
     90 
     91     address[] addrpath = new address[](1);
     92     //消费者查询:我的玉米从哪里来
     93     function leafQuery(address consumer) returns(address[]) {
     94         addrpath.length = 0;
     95         addrpath[addrpath.length++] = consumer;
     96         while (!isInHead(addrpath[addrpath.length - 1])) {
     97             consumer = identify[addrpath[addrpath.length - 1]].father;
     98             addrpath[addrpath.length++] = consumer;
     99         }
    100         return addrpath;
    101     }
    102 
    103     //经销商查询:我的玉米从哪里来
    104     function nodeQueryCeil(address corn) returns(address[]) {
    105         return leafQuery(corn);
    106     }
    107 
    108 
    109     //经销商查询:玉米去哪了
    110     address[] queue = new address[](1);
    111     address[] ans = new address[](1);
    112 
    113     function nodeQueryFloor(address corn) returns(address[], address[]) {
    114         //内存化变量初始化
    115         uint index1;
    116         uint index2;
    117         address temp;
    118         //对经销商节点开始进行层次遍历,查找出所有的叶子节点
    119         index1 = 0;
    120         index2 = 1;
    121         addrpath.length = 0;
    122         queue.length = 0;
    123         queue[queue.length++] = corn;
    124         while (index1 != index2) {
    125             if (identify[queue[index1]].child.length == 0) {
    126                 addrpath[addrpath.length++] = queue[index1];
    127             }
    128             index2 = index2 + identify[queue[index1]].child.length;
    129             for (uint i = 0; i < identify[queue[index1]].child.length; i++) {
    130                 queue[queue.length++] = identify[queue[index1]].child[i];
    131             }
    132             index1++;
    133         }
    134 
    135         ans.length = 0;
    136         for (uint j = 0; j < addrpath.length; j++) {
    137             ans.push(addrpath[j]);
    138             temp = addrpath[j];
    139             while (temp != corn && identify[temp].father != corn) {
    140                 ans.push(identify[temp].father);
    141                 temp = identify[temp].father;
    142             }
    143             ans.push(corn);
    144         }
    145         return (addrpath, ans);
    146     }
    147 }

     参考了一位前辈的经验,对于不同类型物品的溯源,需要做到从频率及价值两个维度进行划分;【网名:netkiller,有自制手札】

      1 pragma solidity ^0.4.10;
      2 
      3 //**
      4 // * Author:         ZJLavender
      5 // * Date:            August 20
      6 // * Update:          fix zero address bug
      7 // * Version:         0.9.02
      8 // * Introduction:   玉米合约用于:消费者溯源玉米来源,源产地及经销商追踪玉米流向,同时提供玉米正常流转记录方法,对常见流转场景进行覆盖,更多需求可以基于其上完善
      9 // * /
     10 contract CornTransport {
     11     
     12     uint256 RETURN_SUCCESS = 0;
     13     
     14     uint256 RETURN_DATAOVERFLOW = 10001;
     15     uint256 RETURN_FROMTOADDRESSSAME = 10002;
     16     uint256 RETURN_TRANSPORTCOUNTZERO = 10003;
     17     uint256 RETURN_CORNCOUNTNOTENOUGH = 10004;
     18     uint256 RETURN_ILLEGAL_ADDRESS = 10005;
     19     
     20     struct Consumer_Dealer_Origin {
     21         uint count;
     22         address addr_from;
     23         address[] addr_to;
     24     }
     25     
     26     address[] FieldsOfCornAddr;
     27     address[] addrpath;
     28     address[] queue;
     29     address[] ans;
     30     address NULL;
     31     
     32     mapping(address => Consumer_Dealer_Origin) identify;
     33     
     34     
     35     //functionName: harvestCorn
     36     //input:
     37     //         cornFieldAddr  address  Use address to replace cornField
     38     //         count  uint256  The number of corn this cornField havest
     39     //return:
     40     //         Return_Code  uint256  The Result Of invoke harvestCorn
     41     //         TheAddress address The input cornFieldAddr
     42     //         addrCornSum  The Sum of corn this Corn Field have
     43     function harvestCorn(address cornFieldAddr, uint256 count) returns(uint256 Return_Code, address TheAddress, uint256 addrCornSum) {
     44         if(cornFieldAddr == NULL){
     45            return (RETURN_ILLEGAL_ADDRESS, cornFieldAddr, identify[cornFieldAddr].count); 
     46         }else if( identify[cornFieldAddr].count + count >= identify[cornFieldAddr].count){
     47             identify[cornFieldAddr].count = identify[cornFieldAddr].count + count;    
     48         }else{
     49             return (RETURN_DATAOVERFLOW, cornFieldAddr, identify[cornFieldAddr].count);
     50         }
     51         
     52         bool flag = false;
     53         for (uint i = 0; i < FieldsOfCornAddr.length; i++) {
     54             if (cornFieldAddr == FieldsOfCornAddr[i]) {
     55                 flag = true;
     56                 break;
     57             }
     58         }
     59         if (!flag)
     60             FieldsOfCornAddr.push(cornFieldAddr);
     61         return (RETURN_SUCCESS, cornFieldAddr, identify[cornFieldAddr].count);
     62 
     63     }
     64 
     65     //functionName: transportCorn
     66     //input:
     67     //         fromAddr  address  the address who output corn
     68     //         toAddr  address  the address who input corn
     69     //          count   uint256 the transport number
     70     //return:
     71     //         Return_Code  uint256  The Result Of invoke transportCorn
     72     //         isSuccess bool The Result Of invoke transportCorn
     73     function transportCorn(address fromAddr, address toAddr, uint256 count) returns(uint256 Return_Code, bool isSuccess) {
     74         if(fromAddr == NULL || toAddr == NULL){
     75            return (RETURN_ILLEGAL_ADDRESS, false); 
     76         }else if (fromAddr == toAddr) {
     77             return (RETURN_FROMTOADDRESSSAME, false);
     78         } else if (count == 0) {
     79             return (RETURN_TRANSPORTCOUNTZERO, false);
     80         }
     81         
     82         if (identify[fromAddr].count >= count) {
     83             identify[fromAddr].count = identify[fromAddr].count - count;
     84             identify[toAddr].count = identify[toAddr].count + count;
     85 
     86             identify[fromAddr].addr_to.push(toAddr);
     87             identify[toAddr].addr_from = fromAddr;
     88 
     89             return (RETURN_SUCCESS, true);
     90         }
     91         return (RETURN_CORNCOUNTNOTENOUGH, false);
     92         
     93     }
     94 
     95     //functionName: getCornCount
     96     //input:
     97     //         query  address  the address query how much corn
     98     //return:
     99     //         cornCount  uint256  The number of corn count 
    100     function getCornCount(address query) returns(uint256 cornCount){
    101         return (identify[query].count);
    102     }
    103     
    104     
    105     //functionName: isInHead
    106     //input:
    107     //         isInHeadAddress  address  query address whether in Head 
    108     //return:
    109     //         bool  address whether in Head 
    110     function isInHead(address isInHeadAddress) returns(bool) {
    111         for (uint j = 0; j < FieldsOfCornAddr.length; j++) {
    112             if (FieldsOfCornAddr[j] == isInHeadAddress)
    113                 return true;
    114         }
    115         return false;
    116     }
    117 
    118     //functionName: dealer_consumerQuery
    119     //input:
    120     //         consumer  address  input address query where corn from 
    121     //return:
    122     //         Answer   bool  invoke Answer 
    123     //          Return_Code uint256 Return_Code
    124     //          address[]   the path of where corn from
    125     function dealer_consumerQuery(address consumer) returns(bool Answer, uint256 Return_Code, address[]){
    126         addrpath.length = 0;
    127         addrpath[addrpath.length++] = consumer;
    128         while (!isInHead(addrpath[addrpath.length - 1])) {
    129             consumer = identify[addrpath[addrpath.length - 1]].addr_from;
    130             addrpath[addrpath.length++] = consumer;
    131             
    132             if(addrpath.length == 3 && addrpath[2] == addrpath[1]){
    133                 return (false, RETURN_ILLEGAL_ADDRESS, addrpath);
    134             }
    135         }
    136         return (true, RETURN_SUCCESS, addrpath);
    137     }
    138 
    139     //functionName: origin_dealer_QueryCornTo
    140     //input:
    141     //         corn  address  input address query where corn to 
    142     //return:
    143     //         Answer   bool  invoke Answer 
    144     //          Return_Code uint256 Return_Code
    145     //          address[]   the node of where corn to
    146     //          address[]   the path of where corn to
    147     function origin_dealer_QueryCornTo(address corn) returns(bool, uint256, address[], address[]){
    148         uint index1;
    149         uint index2;
    150         address temp;
    151 
    152         index1 = 0;
    153         index2 = 1;
    154         addrpath.length = 0;
    155         queue.length = 0;
    156         queue[queue.length++] = corn;
    157         if(identify[corn].addr_to.length == 0){
    158             return(false, RETURN_ILLEGAL_ADDRESS, ans, ans);
    159         }
    160         
    161         while (index1 != index2) {
    162             if (identify[queue[index1]].addr_to.length == 0) {
    163                 addrpath[addrpath.length++] = queue[index1];
    164             }
    165             index2 = index2 + identify[queue[index1]].addr_to.length;
    166             for (uint i = 0; i < identify[queue[index1]].addr_to.length; i++) {
    167                 queue[queue.length++] = identify[queue[index1]].addr_to[i];
    168             }
    169             index1++;
    170         }
    171 
    172         ans.length = 0;
    173         for (uint j = 0; j < addrpath.length; j++) {
    174             ans.push(addrpath[j]);
    175             temp = addrpath[j];
    176             while (temp != corn && identify[temp].addr_from != corn) {
    177                 ans.push(identify[temp].addr_from);
    178                 temp = identify[temp].addr_from;
    179             }
    180             ans.push(corn);
    181         }
    182         
    183         return (true, RETURN_SUCCESS, addrpath, ans);
    184     }
    185     
    186 }
    bug fix 9.02
  • 相关阅读:
    攻防世界wp--web robots
    kubernetes二: kubernetes 重要组件安装和集群管理
    kibana配置页面跳转
    二进制安装的k8s添加新的node节点
    分布式和微服务的区别
    kubernetes一: 二进制安装k8s集群
    kibana导入导出dashborad
    elk 创建一个只读用户
    x-pack模式下修改es集群密码
    docker基础命令
  • 原文地址:https://www.cnblogs.com/tianxia2s/p/9258078.html
Copyright © 2011-2022 走看看