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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM