您正在查看: EOS-智能合约 分类下的文章

EOS智能合约产生随机数

先基本记录下,稍后整理,测试,总结

1. How can I generate random numbers inside a smart contract?

if( !is_zero(prev_reveal.reveal) ) {
    checksum256 result;
    sha256( (char *)&game_itr->player1, sizeof(player)*2, &result);
    auto prev_revealer_offer = idx.find( offer::get_commitment(prev_reveal.commitment) );
    int winner = result.hash[1] < result.hash[0] ? 0 : 1;
    if( winner ) {
        pay_and_clean(*game_itr, *curr_revealer_offer, *prev_revealer_offer);
    } else {
        pay_and_clean(*game_itr, *prev_revealer_offer, *curr_revealer_offer);
    }
}

2. EOSDACRandom

    #include "eosdacrandom.hpp"
    #include <eosiolib/system.h>
    #include <eosiolib/stdlib.hpp>
    #include <eosiolib/action.hpp>
    #include <eosiolib/symbol.hpp>
    #include "../eosdactoken/eosdactoken.hpp"

    using namespace eosio;

    eosdacrandom::eosdacrandom(account_name name)
            : contract(name),
              _seeds(_self, name),
              _geters(_self, name)
    {
    }

    eosdacrandom::~eosdacrandom()
    {
    }

    void eosdacrandom::setsize(uint64_t size)
    {
        require_auth(_self);

        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        if (existing != config.end()) {
            if (existing->hash_count == existing->target_size) {
                if (existing->hash_count != existing->seed_match) {
                    eosio_assert(false, "do not set size during sendseed period");
                }
            }

            config.modify(existing, _self, [&](auto& c){
                c.target_size = size;
            });
        } else {
            config.emplace(_self, [&](auto& c){
                c.owner = _self;
                c.target_size = size;
            });
        }
    }

    void eosdacrandom::sendseed(name owner, int64_t seed, string sym)
    {
        eosio_assert(is_account(owner), "Invalid account");
        symbol_type symbol(string_to_symbol(4, sym.c_str()));
        eosio::asset fromBalance = eosdactoken(N(eosdactoken)).get_balance(owner, symbol.name());
        eosio_assert(fromBalance.amount > 0, "account has not enough OCT to do it");

        eosio::asset selfBalance = eosdactoken(N(eosdactoken)).get_balance(_self, symbol.name());
        eosio_assert(selfBalance.amount > 0, "contract account has not enough OCT to do it");

        require_auth(owner);

        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        eosio_assert(existing != config.end(), "target size must set first");
        const auto& cfg = *existing;

        const auto& sd = _seeds.find(owner);
        if (cfg.hash_count < cfg.target_size) {
            if (sd != _seeds.end()) {
                _seeds.erase(sd);
                config.modify(cfg, _self, [&](auto& c){
                    c.hash_count --;
                });
            }
            eosio_assert(false, "hash size not fulled");
        }

        string h = cal_sha256_str(seed);
        eosio_assert(sd->seed != seed, "you have already send seed");
        if (sd->hash != h) {
            //SEND_INLINE_ACTION( eosdacvote, vote, {_self,N(active)}, {_self, owner, selfBalance, false} );
            for (auto itr = _seeds.cbegin(); itr != _seeds.cend(); ) {
                itr = _seeds.erase(itr);
            }
            config.modify(cfg, _self, [&](auto& c){
                c.hash_count = 0;
            });
            return;
        }

        _seeds.modify(sd, _self, [&](auto& a){
            a.seed = seed;
        });

        config.modify(cfg, _self, [&](auto& c){
            c.seed_match = c.seed_match + 1;
            print(c.seed_match);
        });

        // if all seeds match
        if (seedsmatch()) {
            dispatch_request(owner);
        }
    }

    void eosdacrandom::sendhash(name owner, string hash, string sym)
    {
        eosio_assert(is_account(owner), "Invalid account");

        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        eosio_assert(existing != config.end(), "target size must set first");
        const auto& cfg = *existing;

        eosio_assert(cfg.hash_count < cfg.target_size, "seeds is full");

        symbol_type symbol(string_to_symbol(4, sym.c_str()));
        eosio::asset fromBalance = eosdactoken(N(eosdactoken)).get_balance(owner, symbol.name());
        eosio_assert(fromBalance.amount > 0, "account has not enough OCT to do it");

        require_auth(owner);

        auto s = _seeds.find(owner);
        if (s == _seeds.end()) {
            _seeds.emplace(_self, [&](auto& a){
                a.owner = owner;
                a.hash = hash;
            });

            config.modify(cfg, _self, [&](auto& c){
                c.hash_count++;
            });
        } else {
            _seeds.modify(s, _self, [&](auto& a){
                a.hash = hash;
            });
        }
    }

    void eosdacrandom::regrequest(name owner, uint64_t index)
    {
        eosio_assert(is_account(owner), "Invalid account");

        uint64_t cur = current_time();
        auto it = _geters.find(owner);
        request_info req {index, cur};
        if (it == _geters.end()) {
            _geters.emplace(_self, [&](auto& a){
                a.owner = owner;
                a.requestinfo.push_back(req);
            });
        } else {
            _geters.modify(it, _self, [&](auto& a){
                bool same_idx = false;
                for (auto ri = a.requestinfo.begin(); ri != a.requestinfo.end(); ++ri) {
                    if (ri->index == index) {    // if index equals former index.
                        *ri = req;
                        same_idx = true;
                        break;
                    }
                }

                if (!same_idx) {
                    a.requestinfo.push_back(req);
                }
            });
        }
    }

    int64_t eosdacrandom::random()
    {
        // use _seeds to generate random number
        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        eosio_assert(existing != config.end(), "target size must set first");
        eosio_assert(existing->hash_count == existing->target_size, "seed is not full");

        // how to generate random number?
        int64_t  seed = 0;
        for (auto it = _seeds.cbegin(); it != _seeds.cend();) {
            seed += it->seed;
            it = _seeds.erase(it);
        }

        config.modify(existing, _self, [&](auto& c){
            c.hash_count = 0;
            c.seed_match = 0;
        });

        checksum256 cs = cal_sha256(seed);
        return (((int64_t)cs.hash[0] << 56 ) & 0xFF00000000000000U)
            |  (((int64_t)cs.hash[1] << 48 ) & 0x00FF000000000000U)
            |  (((int64_t)cs.hash[2] << 40 ) & 0x0000FF0000000000U)
            |  (((int64_t)cs.hash[3] << 32 ) & 0x000000FF00000000U)
            |  ((cs.hash[4] << 24 ) & 0x00000000FF000000U)
            |  ((cs.hash[5] << 16 ) & 0x0000000000FF0000U)
            |  ((cs.hash[6] << 8 ) & 0x000000000000FF00U)
            |  (cs.hash[7] & 0x00000000000000FFU);
    }

    bool eosdacrandom::seedsmatch()
    {
        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        eosio_assert(existing != config.end(), "target size must set first");
        const auto& cfg = *existing;

        if (cfg.hash_count != cfg.target_size) {
            return false;
        }

        if (cfg.hash_count == cfg.seed_match) {
            return true;
        }

        return false;
    }

    checksum256 eosdacrandom::cal_sha256(int64_t word)
    {
        checksum256 cs = { 0 };
        char d[255] = { 0 };
        snprintf(d, sizeof(d) - 1, "%lld", word);
        sha256(d, strlen(d), &cs);

        return cs;
    }

    string eosdacrandom::cal_sha256_str(int64_t word)
    {
        string h;
        checksum256 cs = cal_sha256(word);
        for (int i = 0; i < sizeof(cs.hash); ++i) {
            char hex[3] = { 0 };
            snprintf(hex, sizeof(hex), "%02x", static_cast<unsigned char>(cs.hash[i]));
            h += hex;
        }

        return h;
    }

    void eosdacrandom::dispatch_request(name owner)
    {
        print("all seeds matched.");
        uint64_t cur = current_time();
        int64_t num = random();
        static int expiraion = 3000; // ms
        std::vector<std::vector<request_info>> reqs;

        for (auto i = _geters.cbegin(); i != _geters.cend();) {
            std:vector<request_info> tmp(i->requestinfo);
            for (auto j = tmp.begin(); j != tmp.end();) {
                if (cur - j->timestamp >= expiraion) {
                    dispatch_inline(i->owner, string_to_name("getrandom"),
                                    {permission_level(_self, N(active))},
                                    std::make_tuple(j->index, num));
                    j = tmp.erase(j);
                } else {
                    ++j;
                }
            }

            if (tmp.size()) {
                reqs.push_back(tmp);
            }

            i = _geters.erase(i);
        }

        if (reqs.size()) {
            for (auto r = reqs.cbegin(); r != reqs.cend(); ++r) {
                _geters.emplace(_self, [&](auto& a){
                    a.owner = owner;
                    a.requestinfo = *r;
                });
            }
        }
    }

    EOSIO_ABI( eosdacrandom, (setsize) (sendseed) (sendhash) (regrequest) )

3. eoscraper

    #include "scraper.hpp"

    #include <set>
    #include <map>
    #include <vector>

    #include "Proof.hh"
    #include "Ecc.hh"

    //count of participants for random generation (min 4)
    constexpr static uint8_t participant_cnt = 10;

    static const UInt256 seed_for_g = fromString("21343453542133456453212");
    static const UInt256 seed_for_m = fromString("56987654354236234435425");

    static const Point base_point { Secp256k1, Secp256k1.G.x, Secp256k1.G.y };
    static const Point gen_g = base_point.scalarMult(seed_for_g);
    static const Point gen_m = base_point.scalarMult(seed_for_m);


    struct binuint256_t {
        checksum256 data;
    };

    struct binpoint {
        binuint256_t x, y;
    };

    struct binproof {
        binpoint g,m,h,z,a,b;
        binuint256_t c, r;
    };

    UInt256 fromBin(binuint256_t const & data) {
        UInt256 x;
        memcpy(x.data, data.data.hash, sizeof(data.data));
        return std::move(x);
    }

    Point fromBin(binpoint const &data) {
        Point point {Secp256k1, fromBin(data.x), fromBin(data.y)};
        eosio_assert(point.isOnCurve(), "Point not in curve");

        return std::move(point);
    }

    Proof fromBin(binproof const &data) {
        return {
            fromBin(data.g), fromBin(data.m),
            fromBin(data.h), fromBin(data.z),
            fromBin(data.a), fromBin(data.b),
            fromBin(data.c), fromBin(data.r)
        };
    }


    // @abi table
    struct encshare {
        uint64_t id;
        account_name from;
        account_name to;

        binpoint data;
        binpoint commitment;
        binproof proof;
        uint64_t dec_id;

        auto primary_key() const { return id; }

        EOSLIB_SERIALIZE(encshare, (id)(from)(to)(data)(commitment)(proof)(dec_id));
    };

    // @abi table
    struct decshare {
        uint64_t id;
        binpoint s;
        binproof proof;

        auto primary_key() const { return id; }

        EOSLIB_SERIALIZE(decshare, (id)(s)(proof));
    };

    // @abi table
    struct random {
        enum state : uint8_t {
            wait_joins = 0,
            wait_enc_shares,
            wait_dec_shares,
            done,
            error,
        };

        uint64_t id;
        uint8_t state;
        uint8_t joined_cnt;
        std::vector<account_name> participants;

        uint32_t pushed_cnt;
        std::vector<uint64_t> enc_ids;
        std::vector<uint8_t> dec_cnts;

        auto primary_key()const { return id; }

        EOSLIB_SERIALIZE(random, (id)(state)(participants)(enc_ids)(dec_cnts));
    };

    // @abi table
    struct account {
        account_name owner;
        binpoint pubkey;

        auto primary_key()const { return owner; }

        EOSLIB_SERIALIZE(account, (owner)(pubkey));
    };

    class scraper : public eosio::contract {
    public:
        scraper( account_name self ) :
            contract(self),
            _accounts(_self, _self),
            _randoms( _self, _self),
            _encshares(_self, _self),
            _decshares(_self, _self)
        { }

        // @abi action
        void bindkey(account_name sender, binpoint pubkey) {
            require_auth(sender);
            auto acc = _accounts.find(sender);
            if (acc != _accounts.end())
                _accounts.modify(acc, sender, [&] (auto & acc) {
                    acc.pubkey = pubkey;
                });
            else
                _accounts.emplace(sender, [&](auto & acc) {
                    acc.owner = sender;
                    acc.pubkey = pubkey;
                });
        }

        // @abi action
        void initrand(account_name sender) {
            require_auth(sender);
            auto acc = _accounts.find(sender);
            eosio_assert(acc != _accounts.end(), "Need to bind public key");

            _randoms.emplace(sender, [&](auto & rand) {
                rand.id = _randoms.available_primary_key();
                rand.state = random::state::wait_joins;
                rand.participants.reserve(participant_cnt);
                rand.enc_ids.reserve(participant_cnt*participant_cnt);
                rand.dec_cnts.reserve(participant_cnt);
                rand.participants[0] = sender;
                rand.joined_cnt = 1;
                rand.pushed_cnt = 0;
                for(auto k = 0; k < participant_cnt * participant_cnt; ++k)
                    rand.enc_ids[k] = -1;
            });
        }

        // @abi action
        void joinrand(uint64_t rand_id, account_name sender) {
            require_auth(sender);
            auto acc = _accounts.find(sender);
            eosio_assert(acc != _accounts.end(), "Need to bind public key");

            auto rand_it = _randoms.find(rand_id);
            eosio_assert(rand_it != _randoms.end(), "Rand not found");

            eosio_assert(participantId(*rand_it, sender) != -1, "Already joinded");
            eosio_assert(rand_it->state == random::state::wait_joins, "Invalid state");

            _randoms.modify(rand_it, sender, [&](auto & rand) {
                rand.participants[rand.joined_cnt++] = sender;
                if (rand.joined_cnt == participant_cnt)
                    rand.state = random::state::wait_enc_shares;
            });
        }

        // @abi action
        void pushencshare(uint64_t rand_id, account_name sender, account_name receiver,
                          binpoint data, binpoint commitment, binproof proof)
        {
            require_auth(sender);
            auto senderAccIt = _accounts.find(sender);
            eosio_assert(senderAccIt != _accounts.end(), "Sender not found");

            auto receiverAccIt = _accounts.find(receiver);
            eosio_assert(receiverAccIt != _accounts.end(), "Receiver not found");

            auto rand_it = _randoms.find(rand_id);
            eosio_assert(rand_it != _randoms.end(), "Rand not found");

            auto senderPartId = participantId(*rand_it, sender);
            eosio_assert(senderPartId != -1, "Sender is not participant");

            auto receiverPartId = participantId(*rand_it, receiver);
            eosio_assert(receiverPartId != -1, "Receiver is not participant");

            eosio_assert(rand_it->enc_ids[(uint32_t)senderPartId * participant_cnt + receiverPartId] == -1, "share already pushed");

            auto pk = fromBin(receiverAccIt->pubkey);
            auto pr = fromBin(proof);
            eosio_assert(gen_g == pr.g, "Invalid proof (gen_g != g)");
            eosio_assert(pk == pr.m, "Invalid proof (pk != m)");
            eosio_assert(pr.verify(), "Proof validate failed");

            uint64_t new_share_id;
            _encshares.emplace(sender, [&](auto & share) {
                new_share_id = _encshares.available_primary_key();
                share.id = new_share_id;
                share.from = sender;
                share.to = receiver;
                share.data = data;
                share.commitment = commitment;
                share.proof = proof;
                share.dec_id = (uint64_t)-1;
            });

            _randoms.modify(rand_it, sender, [&](auto & rand) {
                rand.enc_ids[(uint32_t)senderPartId * participant_cnt + receiverPartId] = new_share_id;
                rand.pushed_cnt++;

                if (rand.pushed_cnt == (uint32_t)participant_cnt * participant_cnt)
                    rand.state = random::state::wait_dec_shares;
            });
        }

        // @abi action
        void pushdecshare(uint64_t rand_id, account_name sender, account_name from,
                          binpoint s, binproof proof)
        {
            require_auth(sender);
            auto senderAccIt = _accounts.find(sender);
            eosio_assert(senderAccIt != _accounts.end(), "Sender not found");

            auto fromAccIt = _accounts.find(from);
            eosio_assert(fromAccIt != _accounts.end(), "From not found");

            auto rand_it = _randoms.find(rand_id);
            eosio_assert(rand_it != _randoms.end(), "Rand not found");

            eosio_assert(rand_it->state == random::state::wait_dec_shares, "Invalid state");

            auto senderPartId = participantId(*rand_it, from);
            eosio_assert(senderPartId != -1, "Sender is not participant");

            auto receiverPartId = participantId(*rand_it, sender);
            eosio_assert(receiverPartId != -1, "Receiver is not participant");

            auto enc_id = rand_it->enc_ids[(uint32_t)senderPartId * participant_cnt + receiverPartId];
            auto encshare_it = _encshares.find(enc_id);
            eosio_assert(encshare_it != _encshares.end(), "Share not found");
            eosio_assert(encshare_it->dec_id == -1, "Already pushed");

            auto encdata = fromBin(encshare_it->data);
            auto pk = fromBin(senderAccIt->pubkey);
            auto ss = fromBin(s);
            auto pr = fromBin(proof);
            eosio_assert(gen_g == pr.g, "Invalid proof (gen_g != g)");
            eosio_assert(encdata == pr.z, "Invalid proof (encdata != g)");
            eosio_assert(ss == pr.m, "Invalid proof (m != s)");
            eosio_assert(pk == pr.h, "Invalid proof (pk != h)");
            eosio_assert(pr.verify(), "Proof validate failed");

            uint64_t new_dec_id;
            _decshares.emplace(sender, [&](auto & obj) {
                new_dec_id = _decshares.available_primary_key();
                obj.id = new_dec_id;
                obj.s = s;
                obj.proof = proof;
            });

            _encshares.modify(encshare_it, sender, [&](auto & obj) {
                obj.dec_id = new_dec_id;
            });

            _randoms.modify(rand_it, sender, [&](auto & rand) {
                rand.dec_cnts[from]++;
            });
        }

    private:
        eosio::multi_index<N(accounts), account> _accounts;
        eosio::multi_index<N(randoms), random> _randoms;
        eosio::multi_index<N(encshare), encshare> _encshares;
        eosio::multi_index<N(decshare), decshare> _decshares;

    private:
        uint8_t participantId(random const & obj, account_name acc) {
            for (uint8_t i = 0; i < participant_cnt; ++i)
                if (obj.participants[i] == acc)
                    return i;
            return -1;
        }
    };

    EOSIO_ABI( scraper, (bindkey)(initrand)(joinrand)(pushencshare)(pushdecshare))

零基础部署测试合约(三)---合约部署

下面开始编译合约


进入合约目录 /License

  1. 生成ABI
    eosiocpp -g License.abi License.cpp
  2. 生成WAST
    eosiocpp -o License.wast License.cpp

    执行完成后


开始部署合约

部署测试合约(一)---前准备中,已经创建dapp.token,dapp.exec账号

下面开始在dapp.token账户部署合约

cleos set contract dapp.token License/ -p dapp.token


开始执行合约
  1. 执行合约setuserinfo 修改用户信息
    cleos push action dapp.token setuserinfo '["dapp.exec","区块链技能学习", "bcskill.com"]' -p dapp.exec

  2. 查看用户信息
    cleos get table dapp.token dapp.token accounts

  3. 执行合约makeproject 创建项目
    cleos push action dapp.token makeproject '["dapp.exec","testcontract"]' -p dapp.exec

  4. 查看项目信息
    cleos get table dapp.token dapp.token projecttable

  5. 执行合约 buylicense购买项目授权
    cleos push action dapp.token buylicense '["dapp.exec","testcontract"]' -p dapp.exec

  6. 查看项目信息
    cleos get table dapp.token dapp.token projecttable

零基础部署测试合约(二)---合约编译

下面演示EOS智能合约编写,实例将涉及对链上多索引(multi_index)的增删改查。

实例为License合约,主要功能为

  • 客户设置自己的信息
  • 客户创建自己的项目
  • 客户购买项目授权
  • 验证项目授权
    (由于演示二级索引,项目名称为索引唯一,所以实例为用户单项目)
    上面的权限都是基于客户自身的权限验证,创建是创建的系统子账户,可用于系统币转账

合约代码基于C++语言,源代码分为源文件(.cpp)和头文件(.hpp)
//License.hpp

#include <eosiolib/asset.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>

class License : public eosio::contract {
    public:
        License( account_name self )
        :eosio::contract(self)
        ,accounts(_self, _self)
        ,projecttable(_self, _self){}

        void setuserinfo(account_name owner, const std::string& company_name, const std::string& contact_info);
        void makeproject(account_name owner, const std::string& project_name);
        void buylicense(account_name owner, const std::string& project_name);
        void testlicense(account_name owner, const std::string& project_name);

    private:
        //@abi table accounts i64
        struct account{
            account_name name;
            std::string company_name;
            std::string contact_info;
            uint8_t level;
            uint64_t primary_key()const { return name; }
            EOSLIB_SERIALIZE(account, (name)(company_name)(contact_info)(level))
        };

        typedef eosio::multi_index<N(accounts),account> account_table;
        account_table accounts;

        //@abi table projecttable i64
        struct project{
            uint32_t pkey;
            account_name owner_name;
            std::string project_name;
            std::string company_name;
            std::string contact_info;
            uint8_t      status;

            uint64_t primary_key()const { return pkey; }
            uint64_t getowner_name() const{return owner_name;}
            EOSLIB_SERIALIZE(project, (pkey)(owner_name)(project_name)(company_name)(contact_info)(status))
        };
        //contracts/eosiolib/multi_index.hpp
        //multi_index用于封装智能合约对数据库的管理,增、删、改、查
        //eosio::multi_index<N(表名),数据类型> 
        //一个multi_index最多支持16个二级索引
        //定义二级索引使用eosio::indexed_by模板。N(byowner_name)为索引的名称
        //project表数据类型,uint64_t索引类型即索引函数返回的类型(只支持uint64_t,uint128_t,double,long double,key256类型),&project::getowner_name索引函数。
        typedef eosio::multi_index<N(projecttable),project, eosio::indexed_by<N(byowner_name), eosio::const_mem_fun<project, account_name, &project::getowner_name> >> projecttable_type;
        projecttable_type projecttable;
};
EOSIO_ABI(License, (setuserinfo)(makeproject)(buylicense)(testlicense))

//License.cpp

#include <License.hpp>

void License::setuserinfo(account_name owner, const std::string& company_name, const std::string& contact_info){
    eosio::print("License::setuserinfo line 4");
    require_auth(owner);
    auto account_itr = accounts.find(owner);
    if(account_itr == accounts.end()){
        account_itr = accounts.emplace(_self, [&](auto& account){
            account.name = owner;
            account.company_name = company_name;
            account.contact_info = contact_info;
        });
    }
    else{
        accounts.modify(account_itr, 0, [&](auto& account) {
            account.company_name = company_name;
            account.contact_info = contact_info;
        });
    }
}

void License::makeproject(account_name owner, const std::string& project_name){
    require_auth(owner);
    //二级索引查找
    auto customer_index = projecttable.template get_index<N(byowner_name)>();
    account_name customer_acct = owner; //如果是string 可以用 eosio::string_to_name 转换
    auto cust_itr = customer_index.find(customer_acct);
    if (cust_itr != customer_index.end() && cust_itr->owner_name == customer_acct) {
        customer_index.modify(cust_itr, 0, [&](auto& project) {
            project.project_name = project_name;
            project.status = cust_itr->status; //初始化未授权,须另购买
            auto account_itr = accounts.find(owner);
            if(account_itr != accounts.end()){
                project.project_name = project_name;
                project.company_name = account_itr->company_name;
                project.contact_info = account_itr->contact_info;

            }
        });
    } 
    else{
        auto project_itr = projecttable.emplace(_self, [&](auto& project){
                project.owner_name = owner;
                project.project_name = project_name;
                auto account_itr = accounts.find(owner);
                if(account_itr != accounts.end()){
                    project.company_name = account_itr->company_name;
                    project.contact_info = account_itr->contact_info;
                    project.status = 0; //初始化未授权,须另购买
                }
            });
    }
}

void License::buylicense(account_name owner, const std::string& project_name){
    require_auth(owner);
    bool bFind = false;
    //二级索引查找
    auto customer_index = projecttable.template get_index<N(byowner_name)>();
    account_name customer_acct = owner; //如果是string 可以用 eosio::string_to_name 转换
    auto cust_itr = customer_index.find(customer_acct);
    while (cust_itr != customer_index.end() && cust_itr->owner_name == customer_acct) {
        if(cust_itr->project_name == project_name){
            if(cust_itr->status == 0){
                //TODO 判断当前账户余额,购买转账等操作
                customer_index.modify(cust_itr, 0, [&](auto& project) {
                    project.status = 1;
                });
            }
            else{
                eosio_assert(false, "The current project is authorized" );
            }
            bFind = true;
            break;
        }
        cust_itr++;
    } 
    eosio_assert(bFind, "owner with project not exists" );
}

void License::testlicense(account_name owner, const std::string& project_name){
    require_auth(owner);
    bool bFind = false;
    for( const auto& project : projecttable ) {
        if(project.project_name == project_name && project.owner_name == owner){
            eosio_assert((project.status == 1), "The current project is not authorized" );
            bFind = true;
            break;
        }
    }
    eosio_assert(bFind, "owner with project not exists" );
}

Github

零基础部署测试合约(一)---前准备

经过前面的三步

EOS 节点部署,BP出块(一)-->前期准备
EOS 节点部署,BP出块(二)-->节点连接
EOS 节点部署,BP出块(三)-->开始部署
已经完成了EOS链服务器相关配置,下面开始部署合约相关配置

  1. 打开eosio节点终端,创建dapp.token,dapp.exec账号
账号 公钥 私钥
dapp.token EOS7STj8j1LDXBVhttRm9FiyME1fDDn77UfjsFu1XQ2ybF2sYpwAM 5J87thFoJVD9fNos9i9QvLYFxZqCWMX4xJ3gGUGkweDbEn5WY2d
dapp.exec EOS5rzFj2sd4hmpAco8ujmDMDxZwWWTSvcS5BJYWpCcen6YbtNFAN 5JC9FdRjX3c3fsB62S5Tz22LgTuRHegb1XEV16uft8u3njmm9E5
//导入私钥
cleos wallet import 5J87thFoJVD9fNos9i9QvLYFxZqCWMX4xJ3gGUGkweDbEn5WY2d
cleos wallet import 5JC9FdRjX3c3fsB62S5Tz22LgTuRHegb1XEV16uft8u3njmm9E5
//创建账号
cleos system newaccount eosio dapp.token EOS7STj8j1LDXBVhttRm9FiyME1fDDn77UfjsFu1XQ2ybF2sYpwAM EOS7STj8j1LDXBVhttRm9FiyME1fDDn77UfjsFu1XQ2ybF2sYpwAM  --stake-net '50.00 SYS' --stake-cpu '50.00 SYS' --buy-ram-kbytes 10000
cleos system newaccount eosio dapp.exec EOS5rzFj2sd4hmpAco8ujmDMDxZwWWTSvcS5BJYWpCcen6YbtNFAN EOS5rzFj2sd4hmpAco8ujmDMDxZwWWTSvcS5BJYWpCcen6YbtNFAN  --stake-net '50.00 SYS' --stake-cpu '50.00 SYS' --buy-ram-kbytes 10000
//如果提示 Error 3080001: account using more than allotted RAM usage
cleos system buyram eosio dapp.token '100000.0000 SYS' -p eosio

部署测试合约(二)---合约编译
部署测试合约(三)---合约部署

EOS智能合约内部调用EOS币转账功能

1、调用currency::inline_transfer静态方法,方法定义如下:
static void inline_transfer( account_name from, account_name to, extended_asset amount, string memo = string(), permission_name perm = N(active) ) {
     action act( permission_level( from, perm ), amount.contract, N(transfer), transfer{from,to,amount,memo} );
     act.send();
}

解释:from,to分别是转账者,接收者。amount是一种扩展资产结构,结构内contract字段为资产属于那个合约。我们要实现内部调用EOS币转账功能,所以contranct应该设置成 N(eosio.token)

调用方式:

extended_asset amount(100,S(4,EOS));
amount.contranct = N(eosio.token);
cuurency::inline_transfer(from,to,amount);
2、定义action,直接发送。其实currency::inline_transfer也是通过定义action实现的。
action(
      permission_level{ _self, N(active) },
      N(eosio.token), N(transfer),  //调用 eosio.token 的 Transfer 合约
      std::make_tuple(_self, to, quantity, std::string(""))).send();