全部产品
  • 首页 > 
  • 数据存证写入

数据存证写入

数据分类

为维护数据的可读性,区块链预先配置了不同业务场景下对应的数据分类,作为所有用户的存证数据格式约定。上链数据必须满足规范要求。

前置条件

在阅读此 开发示例 前,请与您所在的区块链的 管理员 沟通确定已配置的数据分类,如果您是管理员,请参考 配置数据分类 一节完成数据分类的配置;管理员完成数据分类配置后,就可以下载并解压SDK包,完成本文各示例讲解的功能开发。

SDK包下载方式为,登陆BaaS平台,在左侧导航栏选择 区块链列表,在列表中找到您希望访问的区块链,鼠标选中右侧 更多,并点击 下载签名证书下载SDK

notary_chain_download

您可以在client-sdk.zip包内的 schema.txt 文件中查看区块链的数据分类。一条区块链可以包含多个业务数据分类(Category),链上会为每个分类分配一个Category ID,分类配置完成后,用户可以通过识别数据的Category ID在链上检索和过滤存证数据。

开发示例

这里通过一个简单的schema.txt文件示例来演示如何构造、读取存证数据,请对照您自己的文件内容,将GuestInfo类型替换为您实际的数据分类。文件声明了一个名为GuestInfo的Category,包含三个成员,分别是姓名、生日和邮件地址,均为字符串类型,注释中说明了成员数据须满足的约束条件。

请注意:实际开发时,请将GuestInfo替换为您本地schema.txt中实际定义的Category。

   
  1. // schema.txt定义:商家顾客信息
  2. GuestInfo {
  3. String userName; // 姓名,要求非空,长度在20以内
  4. String birthday; // 生日,要求非空
  5. String email; // 邮件地址,要求非空,符合电子邮件格式
  6. }

对照规范要求,在client代码中调用GuestInfoBuilder构造一条存证数据。

   
  1. // client代码
  2. // 构造存证数据
  3. GuestInfoBuilder builder = new GuestInfoBuilder();
  4. byte[] bizData = builder.buildUserName("Bob")
  5. .buildBirthday("2000-01-01")
  6. .buildEmail("bob@inc.com")
  7. .build();

存证数据构造完成了,接下来构造上链的payload,这里用户需要了解一个枚举类——BizCategory。SDK根据schema.txt的约定,预先生成了这一枚举类型,帮助用户标识不同的Category。本例中的BizCategory如下所示。

   
  1. // SDK的BizCategory声明
  2. public class BizCategory {
  3. public static final int GuestInfo = 0x00010001;
  4. ...
  5. }

接下来我们把存证数据传入payload,指定Category为BizCategory.GuestInfo,构造一个数据存证交易,并通过client发送出去,存证上链的过程就完成了。

   
  1. // client代码
  2. // 创建ContentOnlyNotary Transaction
  3. TransactionDO tx = TransactionBuilder.getContentOnlyNotaryPayloadBuilder()
  4. .setContent(bizData)//设置需要存证的数据
  5. .setTimestamp(System.currentTimeMillis())//设置业务时间
  6. .setCategory(BizCategory.GuestInfo)//通过BizCategory设置业务分类
  7. .build();//build Transaction
  8. // 发送Transaction
  9. Response<TransactionDO> response = client.sendTransaction(tx);

存证数据上链后,需要等待一段时间才能成块,出块后就可以查询数据了。在读取数据时,用户也同样通过BizCategory.GuestInfo来识别数据对象类型,将存证数据转换回对象。获取块数据有两种模式,模式一是监听成块消息,处理新数据块;模式二是通过定时任务,每隔一段时间拉取新的数据块。详情可参见 最佳实践

下面展示几个完整的示例。

例1. 简单的存证数据写入

   
  1. // 加载client配置文件
  2. Properties p = new Properties();
  3. p.load(new FileInputStream("sdk.properties"));
  4. ClientConfig config = new ClientPropertyConfig(p);
  5. // 使用指定client配置初始化client
  6. Client client = new Client(config);
  7. // 构造存证数据
  8. GuestInfoBuilder builder = new GuestInfoBuilder();
  9. byte[] bizData = builder.buildUserName("Bob")
  10. .buildBirthday("2000-01-01")
  11. .buildEmail("bob@inc.com")
  12. .build();
  13. // 创建ContentOnlyNotary Transaction
  14. TransactionDO tx = TransactionBuilder.getContentOnlyNotaryPayloadBuilder()
  15. .setContent(bizData)//设置需要存证的数据
  16. .setTimestamp(System.currentTimeMillis())//设置业务时间
  17. .setCategory(BizCategory.GuestInfo)//设置业务分类
  18. .build();//build Transaction
  19. // 发送Transaction
  20. Response<TransactionDO> response = client.sendTransaction(tx);
  21. if(response.isSuccess()){
  22. // 发送成功,业务系统保留Transaction Hash与业务数据关联
  23. return tx.getTxHashValue();
  24. }else{
  25. // 发送失败,抛异常。业务系统应该重试,rpc调用失败时区块链的状态是未知的。
  26. throw new RuntimeException("写入区块链失败");
  27. }

例2. 存证数据读取

   
  1. // 获取当前最新区块header
  2. final Response<BlockHeader> blockHeader = client.getLatestBlockHeader();
  3. if(!blockHeader.isSuccess()) {
  4. LOGGER.error("Get block header fail: ", blockHeader.getErrorMsg());
  5. return;
  6. }
  7. // oldHeight = 当前本地区块高度;
  8. long beginHeight = oldHeight + 1;
  9. long finalHeight = blockHeader.getData().getHeight();
  10. // 发现新块则开始拉取
  11. while(beginHeight < finalHeight) {
  12. long endHeight = Math.min(beginHeight + FETCH_LIMIT - 1, finalHeight);
  13. Response<List<Block>> response = client.getBlocks((int)beginHeight, (int)endHeight);
  14. if (!response.isSuccess()) {
  15. LOGGER.error("Get response fail: ", response.getErrorMsg());
  16. return;
  17. }
  18. ConstructUtil constructUtil = new ConstructUtil();
  19. List<Block> blocks = response.getData();
  20. for (Block block : blocks) {
  21. // 获取区块的存证交易
  22. List<TransactionDO> transactions = block.getTransactions();
  23. for (TransactionDO transaction : transactions) {
  24. // 获取payload
  25. if (ContentOnlyNotaryPayloadDO.class.isInstance(transaction.getPayload())) {
  26. ContentOnlyNotaryPayloadDO contentOnlyNotaryPayloadDO =
  27. ContentOnlyNotaryPayloadDO.class.cast(transaction.getPayload());
  28. // 判断payload的业务数据分类
  29. if (contentOnlyNotaryPayloadDO.getCategory() == BizCategory.GuestInfo) {
  30. // 构造数据对象
  31. GuestInfo renter = GuestInfo.class.cast(constructUtil.construct(
  32. contentOnlyNotaryPayloadDO.getContent(), GuestInfo.class));
  33. // 读取renter数据
  34. System.out.println(renter.getUserName());
  35. }
  36. }
  37. }
  38. beginHeight = block.getHeader().getHeight() + 1;
  39. }
  40. }

最后如果用户的系统要退出,建议在退出前调用shutdown,client会在shutdown中优雅的关闭线程池。

   
  1. client.shutdown();

更多

蚂蚁区块链使用Transaction(存证交易模型)进行数据存证,以上示例使用了ContentOnlyNotaryPayload和EncryptShareNotaryPayload两种存证模型,业务系统还可以根据具体场景,使用其它类型的Transaction写数据上链,详情请参考 存证交易模型