【学习记录】FISCO BCOS之开发第一个区块链应用

参考教程:开发第一个区块链应用 — FISCO BCOS v2.9.0 文档 (fisco-bcos-documentation.readthedocs.io)

如果您还未搭建区块链网络,或未下载控制台,请先走完教程搭建第一个区块链网络,再回到本教程。

走完《搭建第一个区块链网络》后,将会部署好FISCO BCOS控制台,同时~/fisco等目录也已创建好,官方文档在《开发第一个区块链应用》中的极少数步骤(例如创建fisco目录、下载控制台等)也可以跳过了。

本博客仅用于个人记录学习过程(也就是不管原理、先跑起来再说),对于更详尽全面的教程内容、需求与设计等,请参考官方文档而非本文章。


操作系统:CentOS 7

java版本:1.8

FISCO BCOS控制台版本:2.9.2(在启动控制台时可以查看版本。如何启动?详见搭建第一个区块链网络 — FISCO BCOS v2.9.0 文档

 


目录

 一、源码

二、编译智能合约

 三、区块链应用项目

四、运行应用


 一、源码

创建一个Asset的智能合约,实现注册、转账、查询功能。

打开终端、输入命令,进入对应目录、创建 Asset.sol合约:

$ cd ~/fisco/console/contracts/solidity
$ vi Asset.sol

Asset.sol内容如下,直接拷贝进去:

pragma solidity ^0.4.24;

import "./Table.sol";

contract Asset {
    // event
    event RegisterEvent(int256 ret, string account, uint256 asset_value);
    event TransferEvent(int256 ret, string from_account, string to_account, uint256 amount);

    constructor() public {
        // 构造函数中创建t_asset表
        createTable();
    }

    function createTable() private {
        TableFactory tf = TableFactory(0x1001);
        // 资产管理表, key : account, field : asset_value
        // |  资产账户(主键)      |     资产金额       |
        // |-------------------- |-------------------|
        // |        account      |    asset_value    |
        // |---------------------|-------------------|
        //
        // 创建表
        tf.createTable("t_asset", "account", "asset_value");
    }

    function openTable() private returns(Table) {
        TableFactory tf = TableFactory(0x1001);
        Table table = tf.openTable("t_asset");
        return table;
    }

    /*
    描述 : 根据资产账户查询资产金额
    参数 :
            account : 资产账户

    返回值:
            参数一: 成功返回0, 账户不存在返回-1
            参数二: 第一个参数为0时有效,资产金额
    */
    function select(string account) public constant returns(int256, uint256) {
        // 打开表
        Table table = openTable();
        // 查询
        Entries entries = table.select(account, table.newCondition());
        uint256 asset_value = 0;
        if (0 == uint256(entries.size())) {
            return (-1, asset_value);
        } else {
            Entry entry = entries.get(0);
            return (0, uint256(entry.getInt("asset_value")));
        }
    }

    /*
    描述 : 资产注册
    参数 :
            account : 资产账户
            amount  : 资产金额
    返回值:
            0  资产注册成功
            -1 资产账户已存在
            -2 其他错误
    */
    function register(string account, uint256 asset_value) public returns(int256){
        int256 ret_code = 0;
        int256 ret= 0;
        uint256 temp_asset_value = 0;
        // 查询账户是否存在
        (ret, temp_asset_value) = select(account);
        if(ret != 0) {
            Table table = openTable();

            Entry entry = table.newEntry();
            entry.set("account", account);
            entry.set("asset_value", int256(asset_value));
            // 插入
            int count = table.insert(account, entry);
            if (count == 1) {
                // 成功
                ret_code = 0;
            } else {
                // 失败? 无权限或者其他错误
                ret_code = -2;
            }
        } else {
            // 账户已存在
            ret_code = -1;
        }

        emit RegisterEvent(ret_code, account, asset_value);

        return ret_code;
    }

    /*
    描述 : 资产转移
    参数 :
            from_account : 转移资产账户
            to_account : 接收资产账户
            amount : 转移金额
    返回值:
            0  资产转移成功
            -1 转移资产账户不存在
            -2 接收资产账户不存在
            -3 金额不足
            -4 金额溢出
            -5 其他错误
    */
    function transfer(string from_account, string to_account, uint256 amount) public returns(int256) {
        // 查询转移资产账户信息
        int ret_code = 0;
        int256 ret = 0;
        uint256 from_asset_value = 0;
        uint256 to_asset_value = 0;

        // 转移账户是否存在?
        (ret, from_asset_value) = select(from_account);
        if(ret != 0) {
            ret_code = -1;
            // 转移账户不存在
            emit TransferEvent(ret_code, from_account, to_account, amount);
            return ret_code;

        }

        // 接受账户是否存在?
        (ret, to_asset_value) = select(to_account);
        if(ret != 0) {
            ret_code = -2;
            // 接收资产的账户不存在
            emit TransferEvent(ret_code, from_account, to_account, amount);
            return ret_code;
        }

        if(from_asset_value < amount) {
            ret_code = -3;
            // 转移资产的账户金额不足
            emit TransferEvent(ret_code, from_account, to_account, amount);
            return ret_code;
        }

        if (to_asset_value + amount < to_asset_value) {
            ret_code = -4;
            // 接收账户金额溢出
            emit TransferEvent(ret_code, from_account, to_account, amount);
            return ret_code;
        }

        Table table = openTable();

        Entry entry0 = table.newEntry();
        entry0.set("account", from_account);
        entry0.set("asset_value", int256(from_asset_value - amount));
        // 更新转账账户
        int count = table.update(from_account, entry0, table.newCondition());
        if(count != 1) {
            ret_code = -5;
            // 失败? 无权限或者其他错误?
            emit TransferEvent(ret_code, from_account, to_account, amount);
            return ret_code;
        }

        Entry entry1 = table.newEntry();
        entry1.set("account", to_account);
        entry1.set("asset_value", int256(to_asset_value + amount));
        // 更新接收账户
        table.update(to_account, entry1, table.newCondition());

        emit TransferEvent(ret_code, from_account, to_account, amount);

        return ret_code;
    }
}

Asset.sol所引用的Table.sol已在~/fisco/console/contracts/solidity目录下。Table是系统合约,提供了CRUD接口。

二、编译智能合约

在终端输入命令,切换到fisco/console/目录:

$ cd ~/fisco/console/

由于我的控制台版本是2.9.2,执行以下命令:

# 若控制台版本大于等于2.8.0,编译合约方法如下:
$ bash sol2java.sh -p org.fisco.bcos.asset.contract

如果小于2.8.0,则使用以下命令:

$ ./sol2java.sh org.fisco.bcos.asset.contract

运行成功之后,将会在console/contracts/sdk目录生成java、abi和bin目录,如下所示。

# 其它无关文件省略
|-- abi # 生成的abi目录,存放solidity合约编译生成的abi文件
|   |-- Asset.abi
|   |-- Table.abi
|-- bin # 生成的bin目录,存放solidity合约编译生成的bin文件
|   |-- Asset.bin
|   |-- Table.bin
|-- contracts # 存放solidity合约源码文件,将需要编译的合约拷贝到该目录下
|   |-- Asset.sol # 拷贝进来的Asset.sol合约,依赖Table.sol
|   |-- Table.sol # 实现系统CRUD操作的合约接口文件
|-- java  # 存放编译的包路径及Java合约文件
|   |-- org
|        |--fisco
|             |--bcos
|                  |--asset
|                       |--contract
|                             |--Asset.java  # Asset.sol合约生成的Java文件
|                             |--Table.java  # Table.sol合约生成的Java文件
|-- sol2java.sh

但是注意!编译运行成功后是不会生成contracts目录的!(我当时没注意这里,所以后面没启动成功)

但我复盘时也没想明白,为什么我都没有contracts目录和合约文件,却可以有两个合约对应的java文件?

这里需要自己创建contracts目录、把合约文件拷贝进来。

# 在~/fisco/console/contracts/sdk下创建contracts目录
$ cd ~/fisco/console/contracts/sdk
$ mkdir contracts

# 从solidity目录下拷贝合约文件到sdk/contracts里
$ cd ~/fisco/console/contracts/solidity
$ cp Asset.sol ~/fisco/console/contracts/sdk/contracts
$ cp Table.sol ~/fisco/console/contracts/sdk/contracts

 三、区块链应用项目

因为源码已经引入FISCO BCOS Java SDK配置SDK证书将编译好的Java合约引入项目中完成AssetClient.java类完成调用AssetClient的脚本asset_run.sh配置log,所以我就直接引入源码了(项目名为asset-app):

$ cd ~/fisco
$ curl -#LO https://github.com/FISCO-BCOS/LargeFiles/raw/master/tools/asset-app.tar.gz
$ tar -zxf asset-app.tar.gz

(这里想从零开始写也可以,详细参考官方文档)

四、运行应用

# 编译项目
$ cd ~/fisco/asset-app
$ ./gradlew build

把编译智能合约后生成的Asset.java拷贝到项目对应的目录下:

$ cd ~/fisco  
$ cp console/contracts/sdk/java/org/fisco/bcos/asset/contract/Asset.java asset-app/src/main/java/org/fisco/bcos/asset/contract/Asset.java

检查节点进程是否启动:

$ ps aux |grep -i fisco-bcos

如果没有启动的话,则启动全部节点:

$ cd ~/fisco
$ bash nodes/127.0.0.1/start_all.sh

确认节点全部启动后,部署Asset.sol合约: (如果节点没有启动,这一步会报错)

$ cd dist
$ bash asset_run.sh deploy

如果这里SDK连接节点失败了,可以参考该文档进行排查:SDK连接节点失败排查思路 — FISCO BCOS v2.9.0 文档

部署Asset.sol合约成功后,会出现“deploy Asset success, contract address is ”的提示。

继而可以验证以下功能:

注册资产:

$ bash asset_run.sh register Alice 100000
$ bash asset_run.sh register Bob 100000

查询资产:

$ bash asset_run.sh query Alice
$ bash asset_run.sh query Bob

资产转移:

$ bash asset_run.sh transfer Alice Bob  50000
$ bash asset_run.sh query Alice
$ bash asset_run.sh query Bob

 注册资产、查询资产与资产转移的运行结果如下 :

 

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值