实训一:运行第一个智能合约

使用Solidity语言编写一个HelloWorld合约,合约包含一个string变量、一个get方法和一个set方法。

  1. 构造函数初始化该变量为”Hello world!”
  2. 提供get方法获取变量string的值
  3. 提供set方法设置变量string的值

例:

  1. pragma solidity >=0.4.25 <0.6.11;
  2. contract HelloWorld {
  3. string name;
  4. constructor() public ...
  5. function get() public ...
  6. function set() public ...
  7. }

实验步骤:

1)准备好区块链运行环境

使用FISCO BCOS搭建4节点的区块链,也可用系统自带的区块链。

2)编写智能合约

可使用系统自带的智能合约IDE编写智能合约

提交方式:

  • 提交智能合约源码

3)编译部署智能合约

合约IDE进行编译、部署

提交方式:

  • 部署成功后的交易回执截图
  • 部署成功后的智能合约截图,截图应包含合约地址

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

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

提交方式:

  • 提交初始化SDK连接节点源码代码
  • 提交HelloWorld合约Java类截图
  • 提交调用合约Java类set方法的源代码
  • 通过Java调用HelloWorld合约set方法,将变量设置为“Hello From Java!”,在控制台输出交易哈希,截图并提交
  • 通过合约IDE调用合约,获取string变量的值,其值应为“Hello From Java!”,截图返回结果并提交

5)通过区块链浏览器查看交易

发送的交易(交易哈希)可通过系统自带的区块链浏览器展示,确认在哪个区块中。

提交方式:

  • 区块链浏览器中交易回执/交易详情的截图

参考答案:

1)智能合约:

  • 要求constructor构造函数初始化string变量
  • 要求get方法是查询交易view/constant/pure中的一种,返回string变量的值
  • 要求set方法设置string变量

源码参考(实现方式不唯一):

  1. pragma solidity >=0.4.25 <0.6.11;
  2. contract HelloWorld {
  3. string name;
  4. constructor() public
  5. {
  6. name = "Hello, World!";
  7. }
  8. function get() public view returns (string memory){
  9. return name;
  10. }
  11. function set(string memory n) public {
  12. name = n;
  13. }
  14. }

2)调用端:

以Java语言为例,从Solidity智能合约,生成合约Java类,并传入调用set方法所需参数。

  • 要求加载SDK的Client实例连接节点截图
  • 要求合约Java类的源码截图,可通过工具将Solidity源码转为Java类
  • 要求传入合约地址、SDK连接实例及私钥对来初始化/加载一个HelloWorld合约实例
  • 要求调用合约实例的set方法,入参为”Hello sent from Java!”
  • 要求输出/打印/记录调用set方法返回的交易回执,或打印交易回执的交易哈希

合约Java类参考:

  1. package com.sx.demo;
  2. // import内容,略
  3. public class HelloWorld extends Contract {
  4. // BIN和ABI内容略
  5. public static final String[] BINARY_ARRAY = {""};
  6. public static final String BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", BINARY_ARRAY);
  7. public static final String[] SM_BINARY_ARRAY = {""};
  8. public static final String SM_BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);
  9. public static final String[] ABI_ARRAY = {""};
  10. public static final String ABI = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", ABI_ARRAY);
  11. public static final String FUNC_SET = "set";
  12. public static final String FUNC_GET = "get";
  13. protected HelloWorld(String contractAddress, Client client, CryptoKeyPair credential) {
  14. super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
  15. }
  16. public static String getBinary(CryptoSuite cryptoSuite) {
  17. return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
  18. }
  19. public TransactionReceipt set(String n) {
  20. final Function function = new Function(
  21. FUNC_SET,
  22. Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(n)),
  23. Collections.<TypeReference<?>>emptyList());
  24. return executeTransaction(function);
  25. }
  26. public String get() throws ContractException {
  27. final Function function = new Function(FUNC_GET,
  28. Arrays.<Type>asList(),
  29. Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}));
  30. return executeCallWithSingleValueReturn(function, String.class);
  31. }
  32. public static HelloWorld load(String contractAddress, Client client, CryptoKeyPair credential) {
  33. return new HelloWorld(contractAddress, client, credential);
  34. }
  35. }

合约Java类调用源码参考,以单元测试代码为例(SDK连接节点端的Client实例初始化代码以截图为准)。

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest(classes = Application.class)
  3. @WebAppConfiguration
  4. public class RawServiceTest {
  5. // 获取SDK连接节点的Client实例
  6. @Autowired
  7. private Client client;
  8. @Test
  9. public void testHello() throws Exception {
  10. // 合约地址
  11. String contractAddress = "0xb2b3f596797c37745fbe92e52f0e39837230c25b";
  12. // 创建一个私钥对
  13. CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();
  14. // 加载HelloWorld合约
  15. HelloWorld helloWorld = HelloWorld.load(contractAddress, client, keyPair);
  16. // 调用HelloWorld合约set方法
  17. TransactionReceipt receipt = helloWorld.set("Hello sent from Java!");
  18. // 打印交易回执的交易哈希
  19. System.out.println(receipt.getTransactionHash());
  20. }
  21. }

3)区块链浏览器查看上链结果:

根据步骤2可以得到在Java端调用HelloWorld的set方法后,得到的交易哈希。拿到交易哈希后,可以通过区块链浏览器,查看交易哈希对应的交易回执的详情。

  • 要求区块链浏览器上查询的交易哈希与上文调用的交易哈希一致、交易的被调用方to为上文部署的合约地址
  • 要求交易回执的状态为成功(此处为0x0)

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