实训三:实现存证合约

使用Solidity语言实现存证合约,包含一个Evidence合约和一个EvidenceFactory合约。

题目合约内容:

Evidence合约

  1. pragma solidity ^0.4.25;
  2. contract EvidenceSignersDataABI
  3. {
  4. function verify(address addr)public constant returns(bool){}
  5. function getSigner(uint index)public constant returns(address){}
  6. function getSignersSize() public constant returns(uint){}
  7. }
  8. contract Evidence{
  9. string evidence;
  10. address[] signers;
  11. address public factoryAddr;
  12. event addSignaturesEvent(string evi);
  13. event newSignaturesEvent(string evi, address addr);
  14. event errorNewSignaturesEvent(string evi, address addr);
  15. event errorAddSignaturesEvent(string evi, address addr);
  16. event addRepeatSignaturesEvent(string evi);
  17. event errorRepeatSignaturesEvent(string evi, address addr);
  18. function CallVerify(address addr) public constant returns(bool) {
  19. return EvidenceSignersDataABI(factoryAddr)./*请在序号后填入 ,勿删除序号[1-1]*/(addr);
  20. }
  21. constructor(string evi, address addr) {
  22. factoryAddr = /*请在序号后填入 ,勿删除序号[1-2]*/;
  23. if(CallVerify(tx.origin)){
  24. /*请在序号后填入 ,勿删除序号[1-3]*/
  25. newSignaturesEvent(evi,addr);
  26. }else{
  27. errorNewSignaturesEvent(evi,addr);
  28. }
  29. }
  30. function getEvidence() public constant returns(string,address[],address[]){
  31. uint length = EvidenceSignersDataABI(factoryAddr)./*请在序号后填入 ,勿删除序号[1-4]*/;
  32. address[] memory signerList = /*请在序号后填入 ,勿删除序号[1-5]*/(length);
  33. for(uint i= 0 ;i<length ;i++) {
  34. signerList[i] = (EvidenceSignersDataABI(factoryAddr)./*请在序号后填入 ,勿删除序号[1-6]*/(i));
  35. }
  36. return(/*请在序号后填入 ,勿删除序号[1-6]*/,signerList,signers);
  37. }
  38. function addSignatures() public returns(bool) {
  39. for(uint i= 0 ;i</*请在序号后填入 ,勿删除序号[1-7]*/.length ;i++) {
  40. if(tx.origin == signers[i]) {
  41. addRepeatSignaturesEvent(evidence);
  42. return /*请在序号后填入 ,勿删除序号[1-8]*/;
  43. }
  44. }
  45. if(CallVerify(tx.origin)) {
  46. signers./*请在序号后填入 ,勿删除序号[1-9]*/;
  47. addSignaturesEvent(evidence);
  48. return /*请在序号后填入 ,勿删除序号[1-10]*/;
  49. } else {
  50. errorAddSignaturesEvent(evidence,tx.origin);
  51. return /*请在序号后填入 ,勿删除序号[1-11]*/;
  52. }
  53. }
  54. function getSigners()public constant returns(address[])
  55. {
  56. uint length = EvidenceSignersDataABI(factoryAddr)./*请在序号后填入 ,勿删除序号[1-12]*/;
  57. address[] memory signerList = /*请在序号后填入 ,勿删除序号[1-13]*/(length);
  58. for(uint i= 0 ;i<length ;i++) {
  59. signerList[i] = (EvidenceSignersDataABI(factoryAddr)./*请在序号后填入 ,勿删除序号[1-14]*/);
  60. }
  61. return signerList;
  62. }
  63. }

EvidenceFactory合约

  1. pragma solidity ^0.4.25;
  2. import "Evidence.sol";
  3. contract EvidenceFactory{
  4. address[] signers;
  5. event newEvidenceEvent(address addr);
  6. constructor(address[] evidenceSigners){
  7. for(uint i=0; i<evidenceSigners.length; ++i) {
  8. signers./*请在序号后填入 ,勿删除序号[2-1]*/;
  9. }
  10. }
  11. function newEvidence(string evi)public returns(address){
  12. Evidence evidence = /*请在序号后填入 ,勿删除序号[2-2]*/;
  13. newEvidenceEvent(evidence);
  14. return evidence;
  15. }
  16. function getEvidence(address addr) public constant returns(string,address[],address[]){
  17. return Evidence(addr)./*请在序号后填入 ,勿删除序号[2-3]*/;
  18. }
  19. function addSignatures(address addr) public returns(bool) {
  20. return Evidence(addr)./*请在序号后填入 ,勿删除序号[2-4]*/;
  21. }
  22. function verify(address addr)public constant returns(bool){
  23. for(uint i=0; i<signers.length; ++i) {
  24. if (addr == signers[i]) {
  25. return /*请在序号后填入 ,勿删除序号[2-5]*/;
  26. }
  27. }
  28. return /*请在序号后填入 ,勿删除序号[2-6]*/;
  29. }
  30. function getSigner(uint index)public constant returns(address){
  31. uint listSize = signers.length;
  32. if(index < listSize) {
  33. return /*请在序号后填入 ,勿删除序号[2-7]*/;
  34. } else{
  35. return 0;
  36. }
  37. }
  38. function getSignersSize() public constant returns(uint){
  39. return signers./*请在序号后填入 ,勿删除序号[2-8]*/;
  40. }
  41. function getSigners() public constant returns(address[]){
  42. return /*请在序号后填入 ,勿删除序号[2-9]*/;
  43. }
  44. }

实验步骤:

1)理解智能合约的功能

  1. 分别描述Evidence合约和EvidenceFactory的功能
  2. 分别描述Evidence合约中string evidence、address[] signers、address public factoryAddr的作用
  3. 描述Evidence合约中EvidenceSignersDataABI合约的作用

2)完成智能合约空缺部分

将题目合约中的空缺部分/*待填入*/填补,可使用系统自带的智能合约IDE编写智能合约

提交方式:

  • 提交智能合约源码,包含Evidence合约中1-1至1-14共14个空,以及EvidenceFactory合约中2-1至2-9共9个空。

3)编译部署智能合约

填写完合约空缺部分后,通过合约IDE编译合约。

同时,通过创建Alice私钥和Bob私钥,以Alice和Bob私钥的地址为合约构造函数的入参,部署合约

提交方式:

  • 提交合约部署成功后的交易回执截图
  • 提交部署成功后的智能合约截图,截图应包含合约地址
  • 调用合约,获取合约的signer变量的值,提交截图

4)向部署的智能合约发送交易

  • 通过Alice私钥调用EvidenceFactory合约的newEvidence方法创建一个存证,提交交易回执截图,并记录Evidence的地址
  • 调用EvidenceFactory合约getEvidence方法,传入newEvidence获得的Evidence,获取刚创建的存证,提交截图
  • 通过Bob私钥调用EvidenceFactory合约addSignatures方法,提交交易回执截图
  • 再调用EvidenceFactory合约getEvidence方法,获取存证中新增的Bob的签名,提交截图

5)编写应用程序调用合约

  • 编写一个区块链应用程序,可以通过SDK连接区块链节点,并向智能合约发送交易。

提交方式:

  • 提交Asset合约Java类截图
  • 调用Asset的合约Java类send方法的源代码
  • 通过Java调用Asset合约Java类的send方法,向issuer转账1个积分,在控制台输出交易哈希,截图并提交
  • 通过Java调用Asset合约Java类,获取issuer的余额,在控制台输出issuer地址和余额值,截图并提交
  • 通过合约IDE获取issuer余额,截图并提交

参考答案:

1)理解智能合约的功能

  1. 分别描述Evidence合约和EvidenceFactory的功能

Evidence合约记录存证内容和各方签名,EvidenceFactory合约用于管理Evidence存证的生成 (Evidence合约指出了用于保存存证即可,EvidenceFactory指出了用于生成或管理Evidence存证即可)

  1. 分别描述Evidence合约中string evidence、address[] signers、address public factoryAddr的作用

evidence用于存储存证内容、signers用于存储存证签名者的签名、factoryAddr用于记录存证工厂合约的地址 (evidence指出存储存证即可、signers指出是保存签名即可、factoryAddr指出记录工厂合约或管理存证合约的合约地址即可)

  1. 描述Evidence合约中EvidenceSignersDataABI合约的作用

用于调用EvidenceFactory合约中的verify,getSigner,getSignerSize方法 (指出EvidenceSignersDataABI用于获取签名者数据,或signer数据可得分、指出用于调用EvidenceFactory或获取EvidenceFactory签名者数据也可以得分、指出用于EvidenceFactory接口或签名者接口也可以得分。直接翻译verify,getSigner,getSignerSize的中文意思不得分)

2)完成智能合约空缺部分

  • 将空缺的部分天上,并成功编译部署合约
  • 若未成功部署,则提供参考合约

Evidence合约

  1. pragma solidity ^0.4.25;
  2. contract EvidenceSignersDataABI
  3. {
  4. function verify(address addr)public constant returns(bool){}
  5. function getSigner(uint index)public constant returns(address){}
  6. function getSignersSize() public constant returns(uint){}
  7. }
  8. contract Evidence{
  9. string evidence;
  10. address[] signers;
  11. address public factoryAddr;
  12. event addSignaturesEvent(string evi);
  13. event newSignaturesEvent(string evi, address addr);
  14. event errorNewSignaturesEvent(string evi, address addr);
  15. event errorAddSignaturesEvent(string evi, address addr);
  16. event addRepeatSignaturesEvent(string evi);
  17. event errorRepeatSignaturesEvent(string evi, address addr);
  18. function CallVerify(address addr) public constant returns(bool) {
  19. return EvidenceSignersDataABI(factoryAddr).verify(addr);
  20. }
  21. constructor(string evi, address addr) {
  22. factoryAddr = addr;
  23. if(CallVerify(tx.origin)){
  24. evidence = evi;
  25. signers.push(tx.origin);
  26. newSignaturesEvent(evi,addr);
  27. }else{
  28. errorNewSignaturesEvent(evi,addr);
  29. }
  30. }
  31. function getEvidence() public constant returns(string,address[],address[]){
  32. uint length = EvidenceSignersDataABI(factoryAddr).getSignersSize();
  33. address[] memory signerList = new address[](length);
  34. for(uint i= 0 ;i<length ;i++) {
  35. signerList[i] = (EvidenceSignersDataABI(factoryAddr).getSigner(i));
  36. }
  37. return(evidence,signerList,signers);
  38. }
  39. function addSignatures() public returns(bool) {
  40. for(uint i= 0 ;i<signers.length ;i++) {
  41. if(tx.origin == signers[i]) {
  42. addRepeatSignaturesEvent(evidence);
  43. return true;
  44. }
  45. }
  46. if(CallVerify(tx.origin)) {
  47. signers.push(tx.origin);
  48. addSignaturesEvent(evidence);
  49. return true;
  50. } else {
  51. errorAddSignaturesEvent(evidence,tx.origin);
  52. return false;
  53. }
  54. }
  55. function getSigners()public constant returns(address[]) {
  56. uint length = EvidenceSignersDataABI(factoryAddr).getSignersSize();
  57. address[] memory signerList = new address[](length);
  58. for(uint i= 0 ;i<length ;i++) {
  59. signerList[i] = (EvidenceSignersDataABI(factoryAddr).getSigner(i));
  60. }
  61. return signerList;
  62. }
  63. }

EvidenceFactory合约

  1. pragma solidity ^0.4.25;
  2. import "Evidence.sol";
  3. contract EvidenceFactory{
  4. address[] signers;
  5. event newEvidenceEvent(address addr);
  6. constructor(address[] evidenceSigners){
  7. for(uint i=0; i<evidenceSigners.length; ++i) {
  8. signers.push(evidenceSigners[i]);
  9. }
  10. }
  11. function newEvidence(string evi)public returns(address) {
  12. Evidence evidence = new Evidence(evi, this);
  13. newEvidenceEvent(evidence);
  14. return evidence;
  15. }
  16. function getEvidence(address addr) public constant returns(string,address[],address[] {
  17. return Evidence(addr).getEvidence();
  18. }
  19. function addSignatures(address addr) public returns(bool) {
  20. return Evidence(addr).addSignatures();
  21. }
  22. function verify(address addr)public constant returns(bool){
  23. for(uint i=0; i<signers.length; ++i) {
  24. if (addr == signers[i]) {
  25. return true;
  26. }
  27. }
  28. return false;
  29. }
  30. function getSigner(uint index)public constant returns(address){
  31. uint listSize = signers.length;
  32. if(index < listSize) {
  33. return signers[index];
  34. } else {
  35. return 0;
  36. }
  37. }
  38. function getSignersSize() public constant returns(uint){
  39. return signers.length;
  40. }
  41. function getSigners() public constant returns(address[]){
  42. return signers;
  43. }
  44. }

3)编译部署智能合约

若步骤2提交的合约未编译成功,可以使用参考合约进行部署,完成后续操作。

  • 要求提交成功部署合约的截图,截图包含合约的ABI,BIN和部署得到的合约地址

4)向部署的智能合约发送交易

  • 要求通过Alice私钥调用EvidenceFactory合约的newEvidence方法创建一个存证,提交交易回执截图
  • 要求调用EvidenceFactory合约getEvidence方法,传入newEvidence获得的Evidence的地址,获取刚创建的存证,提交截图
  • 要求通过Bob私钥调用EvidenceFactory合约addSignatures方法,提交交易回执截图
  • 要求再调用EvidenceFactory合约getEvidence方法,获取存证中新增的Bob的签名,提交截图

5)编写应用程序调用合约

实现功能的编程语言不限,需要提交源码与调用结果的截图

  • 提交Evidence合约Java类截图,可参考WeBASE导出Java类或导出Java项目
  • 调用Asset的合约Java类send方法的源代码
  • 通过Java调用Asset合约Java类的send方法,向issuer转账1个积分,在控制台输出交易哈希,截图并提交
  • 通过Java调用Asset合约Java类,获取issuer的余额,在控制台输出issuer地址和余额值,截图并提交
  • 通过合约IDE获取issuer余额,截图并提交

下图以WeBASE-Front为例,查看交易回执 ../../../_images/check_trans_hash.png