公信宝智能合约开发体验

作者: 剑有偏锋 | 来源:发表于2018-08-21 12:25 被阅读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))
    

    相关文章

      网友评论

        本文标题:公信宝智能合约开发体验

        本文链接:https://www.haomeiwen.com/subject/itidiftx.html