基于XuperChain,信浦存证平台团队搭建了一套存证系统。目前,该存证系统已完成了与上海市徐汇公证处、上海市张江公证处、苏州市相城公证处、无锡市江南公证处等权威机构的对接,为超过50家机构提供服务,产生存证记录1000多万条。

信浦存证平台团队分享的建设经验分成以下四部分:

一、背景介绍

二、部署go语言智能合约和实现存证功能

三、部署Java语言智能合约和分析存证合约的实现逻辑

四、使用XuperChain部署的智能合约来落地公司业务场景

一、案例背景介绍

信浦存证是存观信息基于“百度超级链”研发的电子证据司法存证服务平台。平台结合多方安全计算产品(Seceum)实现源数据分布式密文存储、可用不可见、可计算不可复制。为了保证存证信息的真实性、合法性、关联性、安全性,联合司法鉴定、审计、公证、仲裁等权威机构共同提供区块链的存证方式,支持电子证据存取证服务,实现电子证据的安全可信和永续性保存。

信浦存证平台应用极大降低了电子证据存证、取证、示证、质证的难度,保障了电子证据的清洁性。

生活中的使用场景

几位摄影师前来咨询,他们的摄影作品上传到自己的blog后总是被其他人盗用,即使使用水印也无法避免图片被截取部分等情况。因此,他们需要一个能证明摄影作品最早是由他们上传且具有法律效力可供维权的工具。

对于解决此问题,区块链的不可篡改等特性很适合存证维权的场景,因此,我们可以通过百度超级链XuperChain来构建一个存取证据的智能合约。

在下面的章节中,我们就来帮助摄影朋友开发一个能存储照片版权,且能用于维权的智能合约。

二、部署go语言智能合约和实现存证功能

搭建xuper节点环境(多节点)

环境准备

  • go 1.12以上

  • git

  • g++4.8.2以上

git和g++已经安装好后,安装下载go环境。(接下来a、b、c介绍如何通过mac安装go语言环境,非mac的小伙伴可以跳过了)

部分代码需要滑动才能查看完整版噢

通过brew安装go

brew install go

这样就安装好了。

这里涉及到一个通过brew下载安装包的速度问题,为了避免下载安装包浪费太多时间,我们需要更换Homebrew源。

a. 替换brew.git

cd "$(brew --repo)"
git remote set-url origin 
https://mirrors.aliyun.com/homebrew/brew.git

b. 替换homebrew-core.git

cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin 
https://mirrors.aliyun.com/homebrew/homebrew-core.git

c. echo $SHELL 看输出结果是/bin/zsh还是/bin/bash

c-1. /bin/zsh替换homebrew-bottles**

echo 'exportHOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrcsource ~/.zshrc

c-2. /bin/bash替换homebrew-bottles

echo 'exportHOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.bash_profilesource ~/.bash_profile

到此, go语言环境已经安装完毕。

既然编译环境准备好了,下面就开始编译xuperchain源码。

下载源码

git clone
https://gitee.com/pingfanrenbiji/xuperchain.git
下载的是master分支,当前版本 v3.9

编译

进入源码目录cd xuperchainmake编译好后


就会在output文件夹下出现编译之后的文件。


这里需要注意,一定要安装master分支,不要安装老的分支
如v3.1分支(pow共识)。


如果一开始就用3.1分支的代码,虽然可部署节点,但使用命令或通过sdk调用和链交互就会有出现问题。
建议选择最新的Release分支!

多节点配置

创建节点目录

mkdir pn1mkdir pn2mkdir pn3
将编译之后的所有文件复制到相应的节点目录
cp -r output/* pn1cp -r output/* pn2cp -r output/* pn3

节点1配置

  • 查看节点1地址

cat pn1/data/keys/addressdpzuVdosQrF2kmzumhVeFQZa1aYcdgFpNdpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN
  • 将该地址配置到 pn1/data/config/xuper.json 里的address

cat pn1/data/config/xuper.json
{    "version": "1",    "predistribution": [        {            "address": "dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN",            "quota": "100000000000000000000"        }    ],    "maxblocksize": "128",    "award": "1000000",    "decimals": "8",    "award_decay": {        "height_gap": 31536000,        "ratio": 1    },    "gas_price": {        "cpu_rate": 1000,        "mem_rate": 1000000,        "disk_rate": 1,        "xfee_rate": 1    },    "new_account_resource_amount": 1000,    "genesis_consensus": {        "name": "tdpos",        "config": {            "timestamp": "1559021720000000000",            "proposer_num": "1",            "period": "3000",            "alternate_interval": "3000",            "term_interval": "6000",            "block_num": "20",            "vote_unit_price": "1",            "init_proposer": {                "1": [                    "dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN"                ]            },            "init_proposer_neturl": {                "1": [                    "/ip4/127.0.0.1/tcp/47101/p2p/QmVxeNubpg1ZQjQT8W5yZC9fD7ZB1ViArwvyGUB53sqf8e"                ]            }        }    }}
  • 复制该文件替换pn2/data/config/ 和 pn3/data/config/ 下的 xuper.json

cp pn1/data/config/xuper.json 
pn2/data/config/xuper.json
cppn1/data/config/xuper.json 
pn3/data/config/xuper.json
  • 依次 cd pn2 和 cd pn3 执行下面两条指令

./xchain-cli account newkeys -f
./xchain-cli netURL gen
此时在pn2和pn3 /data 目录下生成新的keys和netkeys文件夹
通过 more data/keys/address 分别得到pn2和pn3的address
  • 查看p1的地址

cd pn1
./xchain-cli netURL get
"/ip4/127.0.0.1/tcp/47101/p2p/QmVxeNubpg1ZQjQT8W5yZC9fD7ZB1ViArwvyGUB53sqf8e"
得到pn1.url后,复制放入pn2和pn3 data/conf/xchain.yaml文件中的bootNodes
  • 配置pn2和pn3节点(端口号+1)

端口配置

port

metricPort

p2pv2 - port

节点1

37101

37200

47101

节点2

37102

37201

47102

节点3

37103

37202

47103

vim pn2/conf/xchain.yaml

vim pn3/conf/xchain.yaml

多节点运行

依次在pn1、pn2、pn3下面执行
./xchain-cli createChain
注意,这里需要使用解释模式来启动nohup ./xchain --vm ixvm & 而非nohup ./xchain & ,原因在于这是部署go语言合约时所需的。

查看多节点环境是否正常

./xchain-cli status -H 127.0.0.1:37101
查看节点1状态其中peers显示的是节点2和节点3的地址说明多节点环境搭建没有问题


多节点统一查询区块数脚本

  • 脚本内容

vim get_trunkHeight


#!/bin/bash
for((i=1;i<=3;i++));< span="">
do 
     echo -n "node$i:"; 
     ./xchain-cli status -H 
      127.0.0.1:3710$i | grep
       trunkHeight;


done
  • 执行脚本

bash get_trunkHeight

部署并执行存证合约

c++合约源码的编译

在官方源码中
cd xuperchain/core/contractsdk/cpp/example
目前支持c++、go、java、pb语言。

c++合约模版比较多,而且有对应的编译脚本,很方便生成合约文件。


这里举一个简单的实例说明一下如何进行c++语言的编译


c++语言的智能合约依赖docker环境
cd contractsdk/cpp
sh build.sh
到当前目录build,是编译好的合约二进制

编译go语言编写的合约文件(以存证合约为例)

存证合约在go文件夹中xuperchain/core/contractsdk/go/example/eleccert/eleccert.go
  • 安装go语言编译环境

目前,本地是go.14.1版本的,需要再安装一个go1.13版本的,并切换下go环境:

brew install go@1.13brew unlink go@1.14brew switch go@1.13 1.13.9ln -s /usr/local/Cellar/go@1.13/1.13.9/bin/go /usr/local/bin
  • 执行go编译命令

cd xuperchain/core/contractsdk/go/example/eleccertGOOS=jsGOARCH=wasm go build eleccert.go


但是,此时会报错go: github.com/BurntSushi/toml@v0.3.1: Get "https://proxy.golang.org/github.com/%21burnt%21sushi/toml/@v/v0.3.1.mod": dial tcp 172.217.24.17:443: i/o timeout


原因:所下载的库依赖有官方库,而官方被封禁网导致。


处理的方法:设置代理go env -w GOPROXY=https://goproxy.cn设置完之后重新执行即可。


ps: go1.11发布后,还发布一个goproxy提供代理服务,goproxy.cn是专门服务于中国的,依赖于七牛云


github地址:https://github.com/goproxy执行完编译命令之后,将至统一放到指定目录方便进行管理。
cp core/contractsdk/go/example/eleccert/eleccertdata/blockchain/xuper/wasm/
  • 存证合约部署

./xchain-cli wasm deploy --account XC1111111111111111@xuper --cname eleccert -a '{"creator": "someone"}' -A data/acl/addrs -o tx.output --keys data/keys --name xuper -H localhost:37101 /Users/mengfanxiao/Documents/project/company/XinPools_INFO/document/business/baidu/xuperchain/data/blockchain/xuper/wasm/eleccert --fee 5568179 --runtime=go -a '{"owner":"mengfanxiao"}'

  • 存证合约的执行

a. 通过命令行执行

/xchain-cli wasm invoke -a '{"owner": "mengfanxiao","filehash": "xxx11111","timestamp": "111111"}' --method save -H localhost:37101 eleccert --fee 5568179


b. 通过java-sdk代码执行

  • 存证合约的查询

a. 通过命令行执行

./xchain-cli wasm query -a '{"owner": "mengfanxiao","filehash": "xxx11111","timestamp": "111111"}' --method query -H localhost:37101 eleccert


b. 通过java-sdk代码查询

java sdk 源码地址

https://gitee.com/pingfanrenbiji/xuper-java-sdk.git

参考最新版官方文档

https://xuperchain.readthedocs.io/zh/latest/advanced_usage/create_contracts.html#wasm

三、部署Java语言智能合约和分析存证合约的实现逻辑

2020年7月13日,官方更新的版本正式在master分支支持java语言编写的智能合约。目前,官方已更新至版本v3.9。

native模式下java智能合约的部署

java智能合约是native部署的方式,所以需要修改下配置文件以开启native合约部署。

vim每个节点路径/conf/xchain.yaml


#管理native合约的配置
native:    
enable: true

启动命令

nohup ./xchain & 这里没有加--vm ixvm ,这是wasm合约部署的方式。

这里修改了配置,所以需要先删除数据再启动。我们这是在本地环境搭建的,所以节点数据都不太重要,如果是公司的数据,就不能轻易的修改配置了。

编译环境

编译Java sdk:Java版本不低于Java1.8版本

包管理器:maven,mvn版本3.6+

配置maven环境

vim /etc/profile
export M2_HOME=/Users/mengfanxiao/Documents/third_software/maven/apache-maven-3.6.2export PATH=$PATH:$M2_HOME/bin
source /etc/profilemvn -v
编译合约sdk
cd xuperchain/core/contractsdk/javamvn install -f pom.xml
产出二进制文件target/java-contract-sdk-0.1.0.jar,并自动安装到mvn本地仓库下。

编译native合约时,以contractsdk/java/example中的counter合约为例。

cd contractsdk/java/example/counter
mvn package -f pom.xml

产出二进制文件target/counter-0.1.0-jar-with-dependencies.jar,用于合约部署。

合约部署

./xchain-cli native deploy --account XC1111111111111111@xuper --fee 15587517 --runtime java xuperchain/data/javacontract/counter-0.1.0-jar-with-dependencies.jar --cname javacounter

合约调用

  • 命令行调用

./xchain-cli native invoke --method Increase -a '{"key":"test"}' javacounter --fee 10
  • 通过java sdk 发起合约交易

@Test
public void invokeContract() throws Exception {    
   Map args = new Hash Map<>();       args.put("key", "icexin".getBytes());     Transaction tx = client.invokeContract(account, "native", "javacounter", "increase", args);   System.out.println("invoke txid: " + tx.getTxid());    System.out.println("response: " + tx.getContractResponse().getBodyStr());       System.out.println("gas: " + tx.getGasUsed());}
注意这里一定要是native模式。

合约查询

  • 通过Java sdk 查询

@Test
public void queryContractJava() throws Exception {      Map args = new HashMap<>();      args.put("key", "icexin".getBytes());     Transaction tx = client.queryContract(account, "native", "javacounter", "get", args);     System.out.println("response: " + tx.getContractResponse().getBodyStr());     System.out.println("gas: " + tx.getGasUsed());    }
native模式下go语言编写的智能合约部署

以counter合约文件为例

cd contractsdk/go/example/countergo build counter.go
部署合约文件

./xchain-cli native deploy --account XC1111111111111111@xuper -a '{"creator":"XC1111111111111111@xuper"}' --fee 15587517 --runtime go xuperchain/data/gocontract/counter --cname golangcounter
调用合约文件
  • 命令行调用

./xchain-cli native invoke --method Increase -a '{"key":"test"}' golangcounter --fee 10
  • Javasdk调用

@Test
public void invokeContractG0() throws Exception {       Map args = new HashMap<>();    args.put("key", "icexin".getBytes());       Transaction tx = client.invokeContract(account, "native", "golangcounter", "increase", args);       System.out.println("invoke txid: " + tx.getTxid());    System.out.println("response: " + tx.getContractResponse().getBodyStr());       System.out.println("gas: " + tx.getGasUsed());      }
查询合约文件

通过Javasdk查询

@Test


public void queryContractGo() throws Exception {       
     Map args = new HashMap<>();
     args.put("key", "icexin".getBytes());
     Transaction tx = client.queryContract(account, "native", "golangcounter", "get", args);
     System.out.println("response: " + tx.getContractResponse().getBodyStr()); 
     System.out.println("gas: " + tx.getGasUsed());     
  }

可能出现的异常信息:

  • 如果报 contract type native not found 说明没有开启native合约配置。

  • 如果报 context deadline exceeded 说明 你可能用的是旧版本的合约文件,所以需要重新编译下新版本的合约源码生成合约文件。


上面简单描述了截止今年7月15日最新版本的部署过程,以及通过native合约部署的方式分别使用go和java2种语言编写的智能合约的过程,下面结合公司的业务来描述下存证智能合约的实现逻辑。

以下分析go语言版本的存证合约的逻辑

数据结构

user对象的数据结构

{
"Owner":"xiaoming" , # 这个表示用户名
     "UserFiles":{ # 这个是一个map集合       
       "filehash":{ # map集合的key是文件hash                   
       "Timestamp":""  # 时间戳         
       "Hashval":""   # []byte(filehash) 也是hash值 


                 }                       
              }   
}
合约部署的时候数据初始化

在合约部署的时候会调用Initialize方法:

首先,获取到部署命令中的owner参数表示用户名;然后,调用链上的方法GetObject来查询该用户名对应的value。

有两个智能合约调用的链上的方法:一个是PutObject 将key-value保存到链上;另外一个是GetObject 根据key获取对应的value,如果value为空的话,则初始化一个空的user对象,并转换成json字符串上链保存。

合约上链交易的方法

这个方法首先根据owner(代表用户名称)去链上查询对应的value,根据上面的分析,该value保存着一个用户对象,第一次调用的时候该用户对象是里面的属性都没有进行初始化,然后调用putFile方法。

首先,初始化一个UserFile对象,这里面保存了一条上链的信息。

将该对象作为一个元素,保存到 user对象里面的userfiles,这个map集合中 key是filehash value是userFile。

然后,将用户对象转换成json字符串保存到链上。

合约交易查询

通过用户名称到链上查询到了用户对象。

根据filehash遍历该用户对象的userfiles这个map集合,找到对应的userfile元素

截止到这里,这个存证合约模版的逻辑其实很简单。

总结上面的逻辑

智能合约调用链上的两个方法:

  • PutObject 将k-v上链保存

  • GetObject 通过k查询v

一个数据结构:

  • 一个user对象里面有一个map集合,里面的元素是每次上链的数据,可以通过map的key来定位到那一条上链数据。

问题发现

filehash重复。

大家看过上面的代码后,可能会发现一个问题:

圈红的地方是将单次上链数据userFile 放入map集合中,key是filehash,如果2次上传的filehash相同,那么就会把之前的filehash对应的value值给替换掉。

但是,相同的上链数据却返回不同的交易id,内部实现机制是怎样根据公司的业务来定义数据结构以实现智能合约,下一部分将解释这个问题。

四、使用XuperChain部署的智能合约来落地公司业务场景

明确公司存证业务需要上链的数据结构

{"data":"", #这里是一个动态的json字符串"businessId":"", #业务id"fileHash":"", #文件hash"applyNotarization","" #申请组织编号"entityName":"" #公司名称}

业务需求

1、将上面的数据上链

2、可以通过业务id businessId和fileHash查询

官方给的go语言版本的存证合约模版

这个在文章的第一部分已经详细介绍过存证合约模版的实现逻辑。
这里把数据结构贴出来,和自己需要的数据结构进行比对。

{
"Owner":"xiaoming" , # 这个表示用户名"UserFiles":{ # 这个是一个map集合                    "filehash":{ # map集合的key是文件hash                                 "Timestamp":"" # 时间戳                                 "Hashval":""  # []byte(filehash) 也是hash值                                          }                         } }

对比结果

1、filehash这个map的key对应的value是一个对象,对象内容官方模版只有Timestamp和Hashval这2个字段。那么,我们把 data、businessId、fileHash、applyNotarization、entityName 这5个字段加入进去。

2、另外,在上一部分也说过,官方模版是通过owner和filehash确认一条上链数据的。那么,我们需求中增加了一个查询参数 businessId,再添加一个map集合,map集合与元素 key表示businessId valu和一个对象的json字符串,问题就可以解决了。

最终符合业务需求的数据结构

{    
  "Owner":"xiaoming",      "UserFiles":{              "filehash":{                     "Timestamp":"",                     "Hashval":"",                     "data":"",                     "businessId":"",                     "applyNotarization":"",                     "entityName":"",                     "fileHash":""                           }                           },                   "BuisnessUserFiles":{                       "businessId":{                           "Timestamp":"",                           "Hashval":"",                           "data":"",                           "businessId":"",                           "applyNotarization":"",                           "entityName":"",                           "fileHash":""                                            }                                 }  }

存证合约模版代码

  • 数据结构

1、添加了一个map集合 key-value,key为businessId。

2、将那5个业务字段添加进去。

3、需要注意的是,对象里面的参数首字母必须大写,否则,属性赋不了值。

  • 数据上链方法修改

模仿filehash书写的方式和逻辑:

1、给属性赋值

2、给map集合赋值或初始化

  • 查询方法


这2个查询的方法也是模仿官方模版里面的getFile方法。

编译合约

进入到go源码合约文件目录GOOS=js GOARCH=wasm go build -o hello.wasm会编译合约文件生成一个hello.wasm文件

部署合约

./xchain-cli wasm deploy --account XC1111111111111111@xuper --cname hello_last_9  --fee 5574291 --runtime go ./hello-go/hello.wasm -a '{"owner":"mengfanxiao"}'

调用合约

若合约源码问题有问题如何解决

现象是:合约部署成功,但调用合约失败。

那么,就可以认定是自己自定义的合约代码有问题。

如果每次测试合约都需要部署到链上再发起调用会特别麻烦,官方提供了3种可以脱离链上环境运行合约的方式。

为了避免朋友们在坑里待得时间太久耽误了进度,这里是截止20200706的最新官方文档:

官方文档

https://xuperchain.readthedocs.io/zh/latest/development_manuals/XdevManual.html

通过百度超级链官网控制台入口来测试合约源码文件是否有问题

目前仅支持c++语言开发的合约的测试,我们用的是go语言,所以这种方式就用不了。为什么用go语言呢?因为只有go语言才有存证的合约模版。

大致的使用步骤是

a、先注册一个账号登陆控制台

b、充值2元钱

c、创建一个合约账户

d、创建合约

d-1 输入合约名称

d-2 可以选择现有的模版,也可以选择空白的模版

d-2-1 选择空白模版的话 可以将自己的c++编写的合约代码复制进去

空白模版

d-2-2 若是选择的现有的模版,可以基于现有的模版代码进行修改。

通过xdev可执行命令来测试

dev工具是随xuperchain发布的一个合约编译和测试工具

先来运行下官方给的例, 熟悉下流程和确保运行环境没有问题

我们目前的环境是最新版的master版本

使用默认的方式启动的 nohup ./xchain &

使用 xdev 测试c++语言合约

  • 配置环境变量

export PATH=$HOME/xuperchain/output:$PATHexport XDEV_ROOT=$HOME/xuperchain/core/contractsdk/cpp注意这里配置的是cpp目录
  • 初始化代码

xdev init hello-cpp

目录结构和图【空白模版】是对应的。

  • 编译

cd hello-cppxdev build -o hello.wasm
  • 部署下合约

./xchain-cli wasm deploy --account XC1111111111111111@xuper --cname hello  --fee 5200000 --runtime c ./hello-cpp/hello.wasm
  • 调用合约

 ./xchain-cli wasm invoke --method hello --fee 110000 hello
  • 测试

xdev test

合约部署和调用都可以通过。

使用xdev测试go语言存证模版合约

  • 编译

cd xuperchain/core/contractsdk/go/example/eleccertGOOS=js GOARCH=wasm go build -o hello.wasm
  • 合约部署

./xchain-cli wasm deploy --account XC1111111111111111@xuper --cname hello  --fee 5200000 --runtime go ./hello-go/hello.wasm此时会报错使得当前节点挂掉

梳理下问题现象:

1、当前节点环境是通过 nohup ./xchain & 方式启动的。

2、通过wsam部署方式部署c++合约对应的合约文件是可以的。

3、通过wsam部署方式部署go合约对应的合约文件是不可以的 会导致节点挂掉。

调整启动方式

nohup ./xchain --vm ixvm &

然后再执行上面的部署命令是可以的。

结论

目前版本可能还不支持没有指定--vm ixvm虚拟机的情况下通过wasm的方式部署go语言合约,还有一种可能是上面配置的环境变量配置的是cpp,所以猜测这里是需要配置成go?朋友们感兴趣的话,可以尝试下。

  • 测试

  • go和c++合约文件区别

下面通过同样的方式部署下咱们自定义的存证的智能合约

1、先对go源码文件编译生成hello.wasm文件

2、复制到 hello-go 文件夹

3、执行 xdev test命令

使用xdev测试我的合约文件想找出里面是哪里的代码有问题,却告诉我这种结构,遂放弃这种方式。

第三种方式:通过vscode来编译源码文件

这种方式就不演示了,原理就是用的xdev命令对源码进行编译(build)和测试(test)。

因为对vscode编译go不太熟,所以这里简单的记录下步骤,便于下次用vscode再对go编译的时候看看这里就知道了。

1、打开vscode 添加add workspace 工作目录 指定一个文件夹 该文件夹下面包含go源码文件

2、Terminal-Configure Tasks-create task.json

{    // See https://go.microsoft.com/fwlink/?LinkId=733558    // for the documentation about the tasks.json format    "version": "2.0.0",    "tasks": [        {            "label": "xdev build",            "type": "shell",            "command": "xdev build -p",            "options": {                "cwd": "${workspaceFolder}"            },            "group": {                "kind": "build",                "isDefault": true            }        },        {            "label": "xdev test",            "type": "shell",            "command": "xdev test",            "options": {                "cwd": "${workspaceFolder}"            }        }    ]}

3、然后,Terminal-run Build Task时也一直报错说找不到XDEV_ROOT,XCHAIN_ROOT环境变量。

因为原理是利用的xdev来做的,我对xdev已经不抱什么希望了,所以就没有再去解决这个问题。

后来转变了下方向,终于找到了适合的方向。

比较合适的方法【推荐】

我一开始想着既然是合约源码有问题,那么在源码文件中添加一些日志,然后一行一行的进行定位就可以找到问题代码了,后来看了下存证模版源码文件中没有输出日志的代码,所以我就没有采用这种方式。

大家可以试下,添加写日志文件,然后去logs/contract.log日志文件中找下日志,

我最终采用的方式是:

1、一份存证模版文件源码,这个肯定是没有问题的。

2、我基于模版文件源码新写的一份文件。

我在想在模版文件中添加了这么多代码,第一次执行肯定会有问题的,类似于“步子垮大了 容易扯蛋”,“一口不能吃下一个大胖子”。

那么,我将新增的代码一点一点的放入模版文件,每次放入都会经历编译、部署、调用执行的过程,确保每次新增的代码没有问题,很快的解决了这个问题。

手续费去向问题

通过节点账户调用合约发起交易,那么手续费来源节点账户,目的账户是出块节点账户吗?

我们查看交易详情

./xchain-cli tx query 1fcc2d5cc2e6bad345a21d14871bd641167c44b5a5ac69076d3095458ed94784

不查不知道,一查吓一跳,请看蓝色字体。

1、来源账户余额不止这个数怎么是 1000000

2、目的账户怎么是$

大家是不是在担心账户余额要是不够了,是不是发起不了交易了?

这个担心是多余的,原因:

  • 因为当前节点是出块节点,每次出块都会有奖励, 每次奖励的金额可以调整,如果担心的话可以调大点。

  • 再一个就是定时出块机制,每隔3秒出一次奖励一次。

  • 初始金额可以调大些。

如果还不放心的话,可以多个节点账户做备用账户。若一个账户余额不够了,则使用其他的账户来发起合约交易(当然需要对应账户下面的合约账户部署的合约喽)。

自定义合约文件源码地址

https://gitee.com/pingfanrenbiji/xuper-java-sdk/blob/master/src/test/resources/com/baidu/xuperunion/api/eleccert.go

最后

本文讲解了如何在go语言和java语言环境下部署智能合约、存证功能实现的逻辑,并最终落地公司业务场景的过程。

如果有任何问题,欢迎在后台留言,或通过添加小助手加入【百度超级链官方交流群】,我们会及时回复!

 


百度超级链是100%国产自研的区块链系统,性能卓越、安全可控、行业领先,在存证、司法、版权、医疗、数据协同、溯源、智慧城市等领域推出解决方案并应用,已经与北京互联网法院、重庆市、百信银行等政府、大型企业达成深度合作。

如果你对百度超级链技术和解决方案感兴趣,或者有相关合作意向,欢迎添加百度超级链小助手微信(image-baidu)

Logo

XuperCore是百度超级链XuperChain内核技术,也是开放原子开源基金会首个开源项目,拥有623篇核心技术专利,致力于创建“更快、更通用、更好用” 的区块链底层技术。

更多推荐