EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
143
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。+ E, O& V0 l' W) n, H8 o5 j2 ?
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。
1.创建一个结构( l7 W: T" O: G5 f+ M9 [
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。" \) }6 ?3 M# |% B* t
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。
///@abitable1 S! i9 ]7 D; j5 g' V& b
structmystruct
{: c4 L5 R9 X ~7 |
uint64_tkey;
uint64_tsecondid;# H6 c( U: D5 m% d- a1 }: ~
std::stringname;
std::stringaccount;" }0 q; A8 o9 S3 |; f
uint64_tprimary_key()const{returnkey;}//getterforprimarykey
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey
};% z( @/ U Q$ Z* i
这里还要注意两件事:
1.注释:) |) N+ ~& @ r$ w4 I
///@abitable
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。* @, G8 G. z& }# `8 p; \
2.结构名称少于12个字符,而且所有的字符都要小写字母。8 ^; @; I* x# M0 `! T
2.多索引表和定义索引
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:, k1 X8 c+ G y7 p- a
typedefeosio::multi_indexdatastore;& E' q! B* o& |
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:" f- d7 y7 F5 L' B7 q; W
typedefeosio::multi_index>>datastore;
注意:
indexed_by>
参数:
字段的名称转换为整数,N(secondid)( F9 L2 h; L5 X3 h0 C
一个用户定义的密钥调用接口,const_mem_fun7 f" @9 Q0 @2 U( Z6 E( a
来看看有三个索引的情况。
///@abitable G: g' m z( @8 p, s1 \
structmystruct
{
uint64_tkey;
uint64_tsecondid;
uint64_tanotherid;& t" M D, A* m/ z
std::stringname;
std::stringaccount;
uint64_tprimary_key()const{returnkey;}
uint64_tby_id()const{returnsecondid;}
uint64_tby_anotherid()const{returnanotherid;}
};5 Z7 F% o3 c8 b5 F) H- R. W
typedefeosio::multi_index>,indexed_by>>datastore;
更多的就不列了。& w+ i! f3 l2 P; S
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。3 z% d {2 k1 A) s) b
3.创建定义类型的局部变量
//localinstancesofthemultiindexes
pollstable_polls;
votes_votes;
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。9 v7 E, ^5 _7 z) _+ J* J; ?
#include% l ?( Q+ R0 [. Y/ g* [
usingnamespaceeosio; Z' W5 U( q! p- x2 m
classyouvote:publiccontract{+ P7 z- \4 Q5 |; L( d1 b- k
public:! U' N4 v3 C$ t5 F
youvote(account_names):contract(s),_polls(s,s),_votes(s,s)
{}
//publicmethodsexposedviatheABI
//onpollsTable
///@abiaction
voidversion()
{5 x; f S) v' y0 C" t( d; B+ S& y
print("YouVoteversion0.01");
};1 F% D1 v) y9 a1 U2 V0 `6 E
///@abiaction& @& Q$ p$ a8 u7 _3 p7 D% k) [4 |
voidaddpoll(account_names,std::stringpollName)# P! ] U1 f1 c, |; f
{
//require_auth(s);* B3 O! U7 N. ^
print("Addpoll",pollName);% X) k" B: j4 Y6 j
//updatethetabletoincludeanewpoll% c6 S- M r# Q0 J
_polls.emplace(get_self(),[&](auto&p). y$ ^" F$ I' L! H& A& `& v
{
p.key=_polls.available_primary_key();
p.pollId=_polls.available_primary_key();
p.pollName=pollName;
p.pollStatus=0;7 P F8 y2 Y6 y9 O. M
p.option="";& A2 _) S: G7 @; @. A7 e. s
p.count=0;* F5 Q! Q! _7 ]( |
});% D4 v" W0 O, R+ e& y9 L
};
///@abiaction! W1 F2 \& f% T9 ?. `, U: P
voidrmpoll(account_names,std::stringpollName)+ k* { k u! P4 h" p
{
//require_auth(s);" H! \! u" {6 L/ J" ^
print("Removepoll",pollName);" ~+ M6 S( m# z: g' A
std::vectorkeysForDeletion;
//finditemswhichareforthenamedpoll' k. V& m6 t! k" h2 \2 P
for(auto&item:_polls)+ W, p& ]$ V! ?5 r: r S1 u% M; u
{
if(item.pollName==pollName)5 J, h, B; B3 K1 g& e! B/ ^) L# E& W
{
keysForDeletion.push_back(item.key);
}
}- b3 L0 n1 Z) ^5 p# o( ~* ]
//nowdeleteeachitemforthatpoll/ M, Q! {5 _, i$ X
for(uint64_tkey:keysForDeletion)" A9 p: T6 l% R* {2 \
{( n+ J8 a8 u0 w2 S! }
print("removefrom_polls",key);0 F: q" G6 k. ?0 ^4 w
autoitr=_polls.find(key);5 p' U" G5 x9 m! J
if(itr!=_polls.end())
{0 L( ?. \5 V: R( ]. k3 `. g
_polls.erase(itr);. d f- c/ V% H: X
}
}
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain7 j6 Z- h6 X4 A* @% @+ s, _
std::vectorkeysForDeletionFromVotes;
//finditemswhichareforthenamedpoll
for(auto&item:_votes)
{% p/ x, M7 ~ }2 ~. R
if(item.pollName==pollName)9 W' h$ A. Q, u/ _& J' B0 F
{
keysForDeletionFromVotes.push_back(item.key);
}6 ~0 j* l% O0 `0 v
}2 d1 C) P! ]6 W0 `3 s
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletionFromVotes) [; ~6 y( y5 c9 D
{
print("removefrom_votes",key);
autoitr=_votes.find(key);
if(itr!=_votes.end())
{
_votes.erase(itr);+ N, ^2 K9 j+ F$ c6 D: v
}6 C) q: i( @0 p% E$ ]4 h2 D
}
};! ^, w% t7 T2 ^3 Y* {
///@abiaction @$ B8 o! I/ R9 M& g K! V
voidstatus(std::stringpollName) B$ S6 ?* i% Q% l1 V* C
{
print("Changepollstatus",pollName);
std::vectorkeysForModify;. f# t2 Z1 T# E9 p7 {. K
//finditemswhichareforthenamedpoll4 s( {( {8 T( T8 w y: o+ C
for(auto&item:_polls)
{$ b% W2 K0 A( I' E2 i/ g
if(item.pollName==pollName)
{8 m2 t6 u D; {2 t0 N
keysForModify.push_back(item.key);
}
}$ T! \7 Y1 E) y% i n2 ^
//nowgeteachitemandmodifythestatus4 l: w! B+ R& h; t: Q8 P5 V# d
for(uint64_tkey:keysForModify); \3 O9 z5 C. ~
{
print("modify_pollsstatus",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())5 l; L% ]6 W; e8 b8 M
{
_polls.modify(itr,get_self(),[&](auto&p); D$ h7 _8 a" t' S' @
{3 {% p# S# K. h0 x% B
p.pollStatus=p.pollStatus+1;
});
}
}
};+ K4 R; Q1 u& K3 Z& A3 X
///@abiaction* x+ l9 [- j$ Z' g( W9 g! B% T
voidstatusreset(std::stringpollName)3 d" K( I1 ~3 E7 ]; `4 H7 C8 n u9 u
{
print("Resetpollstatus",pollName);
std::vectorkeysForModify;$ k( t* J/ H# ^7 r/ i4 T# d
//findallpollitems
for(auto&item:_polls)
{
if(item.pollName==pollName)8 q/ F. [- t" _$ Z3 ?
{2 `9 ?6 U* o* j" `
keysForModify.push_back(item.key);
}
}* x# R- `; G% T2 Y2 n
//updatethestatusineachpollitem0 g( B: q/ G. \5 I7 `4 v; q
for(uint64_tkey:keysForModify)
{
print("modify_pollsstatus",key);
autoitr=_polls.find(key);" m6 f3 W9 |9 V5 K
if(itr!=_polls.end())
{8 n3 r& u1 H* S1 ~$ b
_polls.modify(itr,get_self(),[&](auto&p)
{
p.pollStatus=0;- ^3 O8 x5 Z# O- q8 D+ R3 o6 A
});8 D2 Q& W5 b7 c4 L1 v
}
}
};
///@abiaction
voidaddpollopt(std::stringpollName,std::stringoption). u/ S& U: d: c' r+ l- R: a
{
print("Addpolloption",pollName,"option",option);
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption
for(auto&item:_polls)
{- u( x# L4 k- s8 w. @9 D
if(item.pollName==pollName)
{
//canonlyaddifthepollisnotstartedorfinished
if(item.pollStatus==0)/ {/ ? p$ K; k
{4 d5 b0 I: w0 k% W0 V/ O, k
_polls.emplace(get_self(),[&](auto&p)
{
p.key=_polls.available_primary_key();
p.pollId=item.pollId;+ M# a0 E2 F. j
p.pollName=item.pollName;
p.pollStatus=0;
p.option=option;
p.count=0;
});& W1 ~- ]8 ?4 ~! t6 ?2 A$ x) ~" n: Q
}9 w4 X* m- @/ n* I5 f3 j
else
{, a. E4 d4 }% e/ X q$ e, c
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");: p, S/ o" i% r/ N
}
break;//soyouonlyadditonce
}* ~8 Z5 i" Z+ U% ^$ k4 C; f4 f
}' w$ f7 G' T% J2 l6 f
};) N: g. i4 o! D' X" j- v
///@abiaction; l+ V Y9 p/ Q1 w V
voidrmpollopt(std::stringpollName,std::stringoption)* I' j3 T$ ^; {' }5 J& P( P
{4 m1 E. V4 q( e
print("Removepolloption",pollName,"option",option);
std::vectorkeysForDeletion;) \9 j/ U% N! W$ T1 G
//findandremovethenamedpoll
for(auto&item:_polls)( E. S+ A! k9 ~2 i9 \' W
{
if(item.pollName==pollName)& G) W% g k$ ? T. N
{) J' J( E @5 {/ h8 n6 i
keysForDeletion.push_back(item.key);' f& D' X/ n# L# {
}
}
for(uint64_tkey:keysForDeletion)9 d# H2 ]" R; ^& g+ ?) @8 O
{
print("removefrom_polls",key);0 C; R) \+ V. X, i0 h! `; d8 d" Z
autoitr=_polls.find(key);! A6 {, S, s5 c
if(itr!=_polls.end())
{; ]9 Q; @! @- s$ c4 J
if(itr->option==option)# o4 a; {- w# ]; }1 z+ F
{2 q% n$ X2 V' x7 P
_polls.erase(itr);* E0 N+ X* j/ e1 K b
}
}$ N! O2 ?8 J7 m! `& [3 M. R
}; C3 i; Y+ R0 V+ \- V
};# Y: |# J+ D- ?; x. H. j8 n) g9 e- W
///@abiaction! I, y5 }% [5 z, E5 {- k' s6 a
voidvote(std::stringpollName,std::stringoption,std::stringaccountName)
{ z. `, n8 E p# ?) G
print("votefor",option,"inpoll",pollName,"by",accountName);
//isthepollopen1 i5 R0 s. [4 R" {0 h
for(auto&item:_polls)+ d1 z5 K g* U
{
if(item.pollName==pollName)
{, M& K8 k$ K3 K. P+ u( h, u
if(item.pollStatus!=1)/ s% V. h# N1 y; a1 p. L
{
print("Poll",pollName,"isnotopen");
return;2 y. w3 \2 \0 x& D! U+ e. r
}# ?+ Y3 e/ L4 l: n5 c
break;//onlyneedtocheckstatusonce
}0 N/ U7 H" n& c& \
}) K2 T) w1 `7 h& k; q
//hasaccountnamealreadyvoted?
for(auto&vote:_votes)
{
if(vote.pollName==pollName&&vote.account==accountName)1 u( H7 a3 w0 e
{3 Q; U- f' W% W% r9 {
print(accountName,"hasalreadyvotedinpoll",pollName); a8 z) }8 ~5 @# w* g
//eosio_assert(true,"AlreadyVoted");; y1 V1 a) u# A! V. }
return;# P( L: K& b) W8 [
}
}
uint64_tpollId=99999;//getthepollIdforthe_votestable: _+ E/ `1 R" j7 X* T+ T5 F' h8 A
//findthepollandtheoptionandincrementthecount
for(auto&item:_polls)
{. A6 g: [3 k& p2 B
if(item.pollName==pollName&&item.option==option)
{4 c( S5 l' \3 H L$ r+ k7 O" Q
pollId=item.pollId;//forrecordingvoteinthispoll- ?- }* M* `$ Q7 r0 {# \9 u! o6 t/ ^8 V
_polls.modify(item,get_self(),[&](auto&p)) ?, c6 Y, _4 \) W; M% _3 ]" F
{; ^: `% Q* k6 V4 O9 N" g
p.count=p.count+1;
});) }- a7 X$ a' }4 l0 L1 z* W, E
}2 r& g: U" n' @2 E$ P4 W( z
}
//recordthataccountNamehasvoted
_votes.emplace(get_self(),[&](auto&pv)2 \) h/ o, h2 k
{* D: j% V6 ?8 v
pv.key=_votes.available_primary_key();
pv.pollId=pollId; N7 e+ w9 W; W$ C. v- o
pv.pollName=pollName;
pv.account=accountName;
});
};
private:
//createthemultiindextablestostorethedata
///@abitable
structpoll8 V+ V* A1 Q' t7 O0 F' Z! M' ?
{* {: M! i K5 J) V$ h1 a7 S
uint64_tkey;//primarykey
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption! ^: B% y3 m/ D+ W Z* {
std::stringpollName;//nameofpoll
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished
std::stringoption;//theitemyoucanvotefor+ X& i6 Z# U9 j5 ^8 X4 |: I ^' M
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable.
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}
};
typedefeosio::multi_index>>pollstable;
///@abitable( v- t# q( @5 y V& D
structpollvotes
{# P) U: X8 A8 X' {6 w
uint64_tkey;; Q8 z2 L# m6 G) p' `" H* w# H% U
uint64_tpollId;: s9 j8 _, Z4 v! v: u, H. J
std::stringpollName;//nameofpoll& Y& s- n _* I* \
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>1
uint64_tprimary_key()const{returnkey;}3 H3 |4 e) q9 G& g; c7 H ~, _: M
uint64_tby_pollId()const{returnpollId;}
};
typedefeosio::multi_index>>votes;- \2 c3 j0 ~% s7 Y7 _
//localinstancesofthemultiindexes5 Q, D! X' u- }
pollstable_polls;
votes_votes;
};8 q( }1 t; U A3 |3 S3 h
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))2 [/ G% f' r' y& }6 P8 q
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人