区块链大学公信宝币须达摩项目wiki

公信宝智能合约开发体验

2018-08-21  本文已影响10人  剑有偏锋

一 下载IDE

mac版 https://gxb-package.oss-cn-hangzhou.aliyuncs.com/gxchain-alpha-0.0.1.dmg
windows版 https://gxb-package.oss-cn-hangzhou.aliyuncs.com/gxchain-alpha%20Setup%200.0.1.exe

二 设计原理

1 合约代码: 暂时⽀持C++,后续会⽀持更多语⾔
2 编译⼯具:llvm + binaryen, 将C++代码编译成wasm代码
3 智能合约执⾏环境: WebAssembly作为底层执⾏VM,VM调⽤封装的API读取
外部状态、读写外部存储。 wasm-jit 地址:

三 合约帐户设计

1 帐户分2种:普通帐户和合约帐户
2 合约帐户,由普通帐户通过部署合约的⽅式创建,合约帐户⽆私钥,资产权限
由合约代码控制
3 合约帐户对象,code字段存储合约代码, abi存储合约代码和abi
4 合约代码不⽀持更新

四 合约的持久化存储

1 定义合约的数据存储格式; 定义线性存储空间,每个元素是⼀个struct类型
2 witness_node运⾏时,合约的持久化存储,放内存;程序退出时,写⼊磁盘;
后期可以考虑优化内存(磁盘+缓存)。
3 封装读写持久化存储的API, 提供读、写、检索⽅法的接⼝供合约调⽤
4 合约只能写⾃⼰的存储空间,可以读其它合约的存储空间,但不可直接写; 同
⼀合约内不同帐户的存储空间,由⽤户合约代码控制权限
5 合约内可以根据区块号获取区块,读取外部状态

五 基本接口

1 部署合约 create_contract
2 调用合约 call_contract

六 手续费计算

1 根据cpu_usage使⽤量和存储使⽤量,计算实际⼿续费
2 每笔交易,设置max_transaction_cpu_usage 单个交易的CPU上限,全局参数
(单个交易的cpu usage上限和单个区块的cpu usage上限)
3 限制合约执⾏deadline, 节点接收交易/打包区块时,验证deadline;验证区
块/replay区块时,不验证deadline
<4 创建合约⼿续费 = KB消息体⼤⼩ * 基准⼿续费
<5 调⽤合约⼿续费 = CPU使⽤量 + 存储使⽤量 + KB消息体⼤⼩ * 基准⼿续费

七 体验总结

image.png

1 语法和EOS类似,
<1 继承合约类
<2 定义action
<3 定义table

2合约不支持同名合约部署。
3 部署过的合约不支持更新,这个看仁看智。我是比较喜欢可更新。
4 体验比eos开发好一点,自带IDE。内置了编译服务器地址配置,还有区块链节点。不需要搭建本地环境即可开发,编译,部署,执行。
5 js开发调用这块,有https://github.com/gxchain/gxbjs库。不过当前没有网页钱包插件(如以太的metamask,eos的scatter)。只有和布洛克城(公信宝手机端应用)绑定开发。做独立网页游戏基本不可能。
6 合约创建的token和公信宝钱包创建的UIA(用户创建资产)是两个东西,不能直接互换。感觉公信宝承认合约创建的token可上交易所,可以普及的更广。毕竟创建UIA要几千几百个GXS,发个合约token最多1个GXS。

八 参考

https://github.com/gxchain/Technical-Documents/blob/master/gxchain_contract_start.md

九 代码示例

#include <graphenelib/asset.h>
#include <graphenelib/contract.hpp>
#include <graphenelib/contract_asset.hpp>
#include <graphenelib/dispatcher.hpp>
#include <graphenelib/global.h>
#include <graphenelib/multi_index.hpp>
#include <graphenelib/system.h>
#include <vector>

using namespace graphene;

class bank : public contract
{
  public:
    bank(uint64_t account_id)
        : contract(account_id)
        , accounts(_self, _self)
    {
    }

    // @abi action
    // @abi payable
    void deposit()
    {
        int64_t asset_amount = get_action_asset_amount();
        uint64_t asset_id = get_action_asset_id();
        contract_asset amount{asset_amount, asset_id};

        uint64_t owner = get_trx_sender();
        auto it = accounts.find(owner);
        if (it == accounts.end()) {
            accounts.emplace(owner, [&](auto &o) {
                o.owner = owner;
                o.balances.emplace_back(amount);
            });
        } else {
            uint16_t asset_index = std::distance(it->balances.begin(),
                                                 find_if(it->balances.begin(), it->balances.end(), [&](const auto &a) { return a.asset_id == asset_id; }));
            if (asset_index < it->balances.size()) {
                accounts.modify(it, 0, [&](auto &o) { o.balances[asset_index] += amount; });
            } else {
                accounts.modify(it, 0, [&](auto &o) { o.balances.emplace_back(amount); });
            }
        }
    }

    // @abi action
    void withdraw(std::string to_account, contract_asset amount)
    {
        int64_t account_id = get_account_id(to_account.c_str(), to_account.size());
        graphene_assert(account_id >= 0, "invalid account_name to_account");

        uint64_t owner = get_trx_sender();
        auto it = accounts.find(owner);
        graphene_assert(it != accounts.end(), "owner has no asset");

        int asset_index = 0;
        for (auto asset_it = it->balances.begin(); asset_it != it->balances.end(); ++asset_it) {
            if ((amount.asset_id) == asset_it->asset_id) {
                graphene_assert(asset_it->amount >= amount.amount, "balance not enough");
                if (asset_it->amount == amount.amount) {
                    accounts.modify(it, 0, [&](auto &o) {
                        o.balances.erase(asset_it);
                    });
                    if (it->balances.size() == 0) {
                        accounts.erase(it);
                    }
                } else {
                    accounts.modify(it, 0, [&](auto &o) {
                        o.balances[asset_index] -= amount;
                    });
                }

                break;
            }
            asset_index++;
        }

        withdraw_asset(_self, account_id, amount.asset_id, amount.amount);
    }

  private:
    //@abi table account i64
    struct account {
        uint64_t owner;
        std::vector<contract_asset> balances;

        uint64_t primary_key() const { return owner; }

        GRAPHENE_SERIALIZE(account, (owner)(balances))
    };

    typedef graphene::multi_index<N(account), account> account_index;

    account_index accounts;
};

GRAPHENE_ABI(bank, (deposit)(withdraw))
上一篇下一篇

猜你喜欢

热点阅读