距離EOS主網(wǎng)上線還有不到一周,現(xiàn)在持有EOS的人請(qǐng)注意:如果不在交易所的,一定要去注冊(cè)下。近日,區(qū)塊鏈領(lǐng)域?qū)<夜壤蠋熥隽岁P(guān)于EOS部署、智能合約應(yīng)用開(kāi)發(fā)和代幣映射內(nèi)容的技術(shù)分享,引起了眾多同行的關(guān)注。
目前最大的EOS應(yīng)用是區(qū)塊鏈百科(https://everipedia.org/),已獲得7500萬(wàn)美元的融資,它對(duì)標(biāo)的是維基百科。這個(gè)應(yīng)用的大概規(guī)則是:比如當(dāng)你要編輯一個(gè)詞條時(shí),你需要抵押自己的Token,然后每天會(huì)產(chǎn)生限量token激勵(lì),社區(qū)里的事情都要進(jìn)行投票,進(jìn)行自治,大于75%的投票,才可以修改詞條。這是因?yàn)樗膬?nèi)容是存放在IPFS里。當(dāng)然,還有很多EOS應(yīng)用,我只挑了一個(gè)典型的。
EOS如何部署私有環(huán)境?
https://github.com/EOSIO/eos/wiki
編譯命令:https://github.com/EOSIO/eos/wiki/Local-Environment#2-building-eosio
EOS網(wǎng)絡(luò)是由無(wú)數(shù)個(gè)nodes組成的,提供單獨(dú)keosd 錢(qián)包節(jié)點(diǎn),可以單獨(dú)下。相對(duì)而言,以太坊節(jié)點(diǎn)會(huì)自動(dòng)同步數(shù)據(jù),會(huì)很慢。
啟動(dòng)EOS節(jié)點(diǎn)命令:./nodeos -e -p eosio --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin
使用cleos創(chuàng)建錢(qián)包及賬號(hào)(https://github.com/EOSIO/eos/wiki/Programs-&-Tools#cleos),這里要注意EOS錢(qián)包和以太坊錢(qián)包的區(qū)別:EOS主要管理私鑰,不是一個(gè)離線賬號(hào),是建立在EOS節(jié)點(diǎn)上注冊(cè)后的賬號(hào)。
cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ wallet unlock
cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ wallet list
管理2組賬號(hào),第一組賬號(hào)是eosio,其他所有eos賬號(hào)都是在第一個(gè)eosio上派生出來(lái)的。
cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ create key
我們先來(lái)創(chuàng)建私鑰:
cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ wallet import 私鑰
現(xiàn)在就多了一組賬號(hào)。
然后開(kāi)始創(chuàng)建EOS上的賬戶。
以太坊的賬號(hào)是一個(gè)40字符的字符串,很難被記住。EOS權(quán)限分組,owner是最高權(quán)限,active 可以管理賬號(hào)的資產(chǎn)。
cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ create account eosio 唯一名字(可以搶注) OwnerKey ActiveKey
這樣你的唯一名字就注冊(cè)到EOS網(wǎng)絡(luò)上了,別人可以直接給你這個(gè)名字的賬號(hào)里打錢(qián)或者各種操作,以上操作意味著創(chuàng)建賬戶和管理私鑰的內(nèi)容就完成了。
接下來(lái)就是創(chuàng)建合約,先來(lái)講2個(gè)案例:
第一個(gè)案例:飛行寶
飛行寶的具體邏輯是:用戶要坐飛機(jī),在飛行前,用戶買(mǎi)了哪一期的哪一個(gè)航班,EOS提供了一個(gè)多索引的數(shù)據(jù)表結(jié)構(gòu)叫multi_Index,
uint64_t term_Id; 每一天開(kāi)一期
account_name 就是我們剛剛在eos上注冊(cè)的唯一用戶名,代表購(gòu)買(mǎi)者賬號(hào)
uint64_t content; 可以留言
account_name get_poster() const { return account }
fmulti_index多索引,類(lèi)似一個(gè)mysql一個(gè)表名,第一個(gè)字段是表名,后面是列,就是定義了一個(gè)數(shù)據(jù)表。
總共有4個(gè)操作:第一個(gè)操作是購(gòu)買(mǎi)某一天的航班,購(gòu)買(mǎi)就是一個(gè)添加數(shù)據(jù)的過(guò)程;第二操作是獲取購(gòu)買(mǎi)的情況;第三個(gè)操作是查詢你的所有購(gòu)買(mǎi)記錄,返回一個(gè)數(shù)組;第四個(gè)操作是修改操作。
我們來(lái)實(shí)際操作下:
eosiocpp -o flybaby.wast flybaby.cpp
生成一個(gè) webassembly 文件,這是ABI文件(現(xiàn)在EOS網(wǎng)絡(luò)還有一些bug,要手動(dòng)改下某幾處ABI文件才可以運(yùn)行)。
現(xiàn)在開(kāi)始部署合約
cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ set contract 唯一名字 flybaby
和以太坊有區(qū)別的是EOS可以修改智能合約。
接下來(lái)是調(diào)用方法
cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ push action 唯一名字 create '[1, 1, "唯一名字", 3000, "備注"]' -p 唯一名字
說(shuō)明調(diào)用成功
cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ get table 唯一名字 唯一名字 fdata
返回一個(gè)JSON數(shù)據(jù),用一個(gè)新賬號(hào)再來(lái)買(mǎi)一個(gè)。返回2個(gè)飛行寶購(gòu)買(mǎi)記錄,說(shuō)明成功。get 方法是獲取某一天的航班,list方法返回我所有的飛行寶購(gòu)買(mǎi)記錄。
合約源碼:
flybaby.cpp
#include
#include
using namespace eosio;
using std::string;
class flybaby : public eosio::contract {
public:
//self 代表合約擁有者賬號(hào).
flybaby( account_name self ):contract(self){}
/// @abi table
struct record {
uint64_t term_id; //飛行寶期數(shù)+航班ID作為主鍵
account_name customer; //購(gòu)買(mǎi)者賬號(hào)
uint64_t amount; //購(gòu)買(mǎi)數(shù)量
string content; //留言
//客戶在當(dāng)期僅能買(mǎi)一次某航班,但可以買(mǎi)多個(gè)不同航班.
uint64_t primary_key()const { return term_id; }
//根據(jù)客戶篩選出他購(gòu)買(mǎi)的航班列表.
account_name get_poster() const { return customer; }
EOSLIB_SERIALIZE(record, (term_id)(customer)(amount)(content))
};
typedef eosio::multi_index
indexed_by
const_mem_fun
using contract::contract;
/// @abi action
void create(uint64_t term,uint64_t id,account_name user,uint64_t amount, string content) {
require_auth( user ); //驗(yàn)證權(quán)限,只能用自己的賬號(hào)給你自己買(mǎi).
records datable( _self, _self); //定義數(shù)據(jù)庫(kù)對(duì)象,數(shù)據(jù)庫(kù)屬于合約創(chuàng)建者,并且都存在一個(gè)表中.
//簡(jiǎn)化僅表達(dá)意思,沒(méi)做校驗(yàn),注意運(yùn)算符優(yōu)先級(jí).
uint64_t term_id = (term << 32) + id;
datable.emplace(user, [&]( record & d){
eosio::print("ok this is lamda");
//d.term_id = datable.available_primary_key();
d.term_id = term_id;
d.customer = user;
d.amount = amount;
d.content = content;
eosio::print("update");
});//數(shù)據(jù)庫(kù)內(nèi)容創(chuàng)建
}
void get(uint64_t term,uint64_t id,account_name user) {
require_auth(user);
records datable(_self, _self);
uint64_t term_id = (term << 32) + id;
auto info = datable.find(term_id);
eosio::print("Term_id: ", info->term_id,
" Customer: ", name{info->customer},
" Amount: ", info->amount,
" Content: ", info->content.c_str());
}
void list(account_name user) {
require_auth(user);
records datable(_self, _self);
auto poster_index = datable.template get_index
auto pos = poster_index.find( user );
for (; pos != poster_index.end(); pos++)
{
eosio::print("Term_id: ", pos->term_id,
" Customer: ", name{pos->customer},
" Amount: ", pos->amount,
" Content: ", pos->content.c_str());
eosio::print("||");
}
}
void change(account_name user, uint64_t term, uint64_t id, string content)
{
require_auth(user);
records datable( _self, _self);
uint64_t term_id = (term << 32) + id;
auto info = datable.find(term_id);
eosio_assert(info->customer == user, "not your account");
//此處payer不是user
datable.modify(info, _self, [&](auto& p){
if (content != "")
p.content = content;
});
}
void dele(account_name user, uint64_t term, uint64_t id)
{
require_auth(user);
records datable( _self, _self);
uint64_t term_id = (term << 32) + id;
auto info = datable.find(term_id);
eosio::print(info->content.c_str());
eosio_assert(info->customer == user, "not your account");
datable.erase(info);
}
};
EOSIO_ABI(flybaby, (create)(get)(list)(change)(dele))
接下來(lái)講解 Token 的合約
EOS上沒(méi)有ERC20的協(xié)議,來(lái)看下邏輯:
currency_stats代表一個(gè)資產(chǎn)的結(jié)構(gòu)體,有資產(chǎn)的代號(hào)、名稱(chēng);
max_supply 最大發(fā)行量;
issuer 是代幣的發(fā)行者;
填寫(xiě)好Token的名字、代號(hào)、發(fā)行量,做好準(zhǔn)備工作。
require_auth(st.issuer) 只有發(fā)行者可以修改當(dāng)前的發(fā)行量;
token::issue 方法就是發(fā)布出去;
token::transfer 就是轉(zhuǎn)賬功能;
就是對(duì)余額進(jìn)行增加、減少的處理。
合約源碼:
token.cpp
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include "mydogcon.hpp"
namespace eosio {
void token::create( account_name issuer,
asset maximum_supply )
{
require_auth( _self );
auto sym = maximum_supply.symbol;
eosio_assert( sym.is_valid(), "invalid symbol name" );
eosio_assert( maximum_supply.is_valid(), "invalid supply");
eosio_assert( maximum_supply.amount > 0, "max-supply must be positive");
stats statstable( _self, sym.name() );
auto existing = statstable.find( sym.name() );
eosio_assert( existing == statstable.end(), "token with symbol already exists" );
statstable.emplace( _self, [&]( auto& s ) {
s.supply.symbol = maximum_supply.symbol;
s.max_supply = maximum_supply;
s.issuer = issuer;
});
}
void token::issue( account_name to, asset quantity, string memo )
{
auto sym = quantity.symbol;
eosio_assert( sym.is_valid(), "invalid symbol name" );
auto sym_name = sym.name();
stats statstable( _self, sym_name );
auto existing = statstable.find( sym_name );
eosio_assert( existing != statstable.end(), "token with symbol does not exist, create token before issue" );
const auto& st = *existing;
require_auth( st.issuer );
eosio_assert( quantity.is_valid(), "invalid quantity" );
eosio_assert( quantity.amount > 0, "must issue positive quantity" );
eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
eosio_assert( quantity.amount <= st.max_supply.amount - st.supply.amount, "quantity exceeds available supply");
statstable.modify( st, 0, [&]( auto& s ) {
s.supply += quantity;
});
add_balance( st.issuer, quantity, st, st.issuer );
if( to != st.issuer ) {
SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} );
}
}
void token::transfer( account_name from,
account_name to,
asset quantity,
string /*memo*/ )
{
eosio_assert( from != to, "cannot transfer to self" );
require_auth( from );
eosio_assert( is_account( to ), "to account does not exist");
auto sym = quantity.symbol.name();
stats statstable( _self, sym );
const auto& st = statstable.get( sym );
require_recipient( from );
require_recipient( to );
eosio_assert( quantity.is_valid(), "invalid quantity" );
eosio_assert( quantity.amount > 0, "must transfer positive quantity" );
eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
sub_balance( from, quantity, st );
add_balance( to, quantity, st, from );
}
void token::sub_balance( account_name owner, asset value, const currency_stats& st ) {
accounts from_acnts( _self, owner );
const auto& from = from_acnts.get( value.symbol.name() );
eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" );
if( from.balance.amount == value.amount ) {
from_acnts.erase( from );
} else {
from_acnts.modify( from, owner, [&]( auto& a ) {
a.balance -= value;
});
}
}
void token::add_balance( account_name owner, asset value, const currency_stats& st, account_name ram_payer )
{
accounts to_acnts( _self, owner );
auto to = to_acnts.find( value.symbol.name() );
if( to == to_acnts.end() ) {
to_acnts.emplace( ram_payer, [&]( auto& a ){
a.balance = value;
});
} else {
to_acnts.modify( to, 0, [&]( auto& a ) {
a.balance += value;
});
}
}
} /// namespace eosio
EOSIO_ABI( eosio::token, (create)(issue)(transfer) )
token.hpp
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include
#include
#include
namespace eosiosystem {
class system_contract;
}
namespace eosio {
using std::string;
class token : public contract {
public:
token( account_name self ):contract(self){}
void create( account_name issuer,
asset maximum_supply);
void issue( account_name to, asset quantity, string memo );
void transfer( account_name from,
account_name to,
asset quantity,
string memo );
private:
friend eosiosystem::system_contract;
inline asset get_supply( symbol_name sym )const;
inline asset get_balance( account_name owner, symbol_name sym )const;
private:
struct account {
asset balance;
uint64_t primary_key()const { return balance.symbol.name(); }
};
struct currency_stats {
asset supply;
asset max_supply;
account_name issuer;
uint64_t primary_key()const { return supply.symbol.name(); }
};
typedef eosio::multi_index
typedef eosio::multi_index
void sub_balance( account_name owner, asset value, const currency_stats& st );
void add_balance( account_name owner, asset value, const currency_stats& st,
account_name ram_payer );
public:
struct transfer_args {
account_name from;
account_name to;
asset quantity;
string memo;
};
};
asset token::get_supply( symbol_name sym )const
{
stats statstable( _self, sym );
const auto& st = statstable.get( sym );
return st.supply;
}
asset token::get_balance( account_name owner, symbol_name sym )const
{
accounts accountstable( _self, owner );
const auto& ac = accountstable.get( sym );
return ac.balance;
}
} /// namespace eosio
提問(wèn)環(huán)節(jié)
1:講講你的EOS信仰
谷老師:我一般對(duì)EOS失去信心的時(shí)候,我就會(huì)去reddit看下EOS上朋友們的留言,上面的消息是很及時(shí),而且上面的朋友特別友好,給你不割肉的動(dòng)力。比如:big news is coming soon……winter is coming……Image you are one of them……The Dawn is coming……
每當(dāng)我難受的時(shí)候,我就來(lái)這里,我的信仰就是來(lái)自這里。
2:主鏈上線時(shí)間有沒(méi)有風(fēng)險(xiǎn)?
谷老師:現(xiàn)在EOS 1.0 上線已經(jīng)完成 94%,EOS還是可以的,有一定風(fēng)險(xiǎn)會(huì)延遲,F(xiàn)在講一下EOS百萬(wàn)TPS的梗:它一共21個(gè)超級(jí)節(jié)點(diǎn),有點(diǎn)類(lèi)似我們?cè)谟秘?fù)載均衡,比如10臺(tái)機(jī)器,輪訓(xùn)來(lái)分發(fā)流量,如果當(dāng)前有1萬(wàn)交易,會(huì)分到某個(gè)節(jié)點(diǎn)上,由于單臺(tái)服務(wù)器節(jié)點(diǎn)很高,能一次性處理。
另外我推薦ONO這個(gè)區(qū)塊鏈應(yīng)用,未來(lái)隨著區(qū)塊鏈的升級(jí)換代,提升基礎(chǔ)設(shè)施,也許我們后端開(kāi)發(fā)就不像現(xiàn)在這樣去買(mǎi)一臺(tái)云服務(wù)器,而未來(lái)所有的后端就是一個(gè)區(qū)塊鏈,所有應(yīng)用都會(huì)直接構(gòu)建到區(qū)塊鏈上,像聊天、打車(chē)就直接構(gòu)建在像這樣的EOS區(qū)塊鏈上,打車(chē)的結(jié)算公開(kāi)在區(qū)塊鏈上,就不存在殺熟的問(wèn)題。甚至公司的形式也會(huì)發(fā)生變化,而是由使用者來(lái)決定。未來(lái)區(qū)塊鏈就不只是炒幣的功能。
3:如果一個(gè)用戶開(kāi)發(fā)了一個(gè)很好的應(yīng)用,大戶如果抄襲,大戶會(huì)不會(huì)搶走EOS運(yùn)行的資源?
谷老師:根據(jù)你抵押的EOS份額來(lái)租用算力。這是一個(gè)商業(yè)邏輯,如果你的應(yīng)用很火,就會(huì)有資本投你,算力不太可能被壟斷。
谷老師在最后還講到,伴隨夏季的來(lái)臨,航班延誤或取消都進(jìn)入了高發(fā)期。而航空延誤險(xiǎn)則是很多常旅客的必備,而全球區(qū)塊鏈互助社區(qū)HMS,其基于區(qū)塊鏈技術(shù)和底層的風(fēng)險(xiǎn)保障邏輯,設(shè)計(jì)出的全自動(dòng)的智能型全球航空飛行延誤互助保障合約——“飛行寶”現(xiàn)在已完成首例賠付。
一直以來(lái),區(qū)塊鏈技術(shù)和基于區(qū)塊鏈的項(xiàng)目,因?yàn)榕c現(xiàn)實(shí)世界脫節(jié)而蒙上了神秘的面紗。與此同時(shí),底層技術(shù)不夠成熟、缺乏智能合約公鏈平臺(tái),影響了區(qū)塊鏈技術(shù)的發(fā)展以及應(yīng)用化的過(guò)程。HMS一直在探索區(qū)塊鏈技術(shù)和互助業(yè)務(wù)相結(jié)合的創(chuàng)新,為更多的現(xiàn)實(shí)場(chǎng)景提供服務(wù),對(duì)促進(jìn)區(qū)塊鏈?zhǔn)澜缗c現(xiàn)實(shí)世界的進(jìn)一步聯(lián)動(dòng)有深刻意義,他非?春眠@一應(yīng)用。