EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
113
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。. Q9 b3 z& P) L( P! W# f
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。2 K" V2 z1 S5 R2 v% _. U2 E5 O- Y
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。
1.创建一个结构
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。
///@abitable: a$ U3 P' D7 a1 S" R- P! l
structmystruct: V& H1 X1 F; \3 M O$ L$ h9 y
{7 D' D! e0 I* W8 e# X
uint64_tkey;! n Z; E8 C1 S
uint64_tsecondid;
std::stringname;
std::stringaccount;
uint64_tprimary_key()const{returnkey;}//getterforprimarykey+ v+ P& }( x3 G
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey+ m0 Q# u" F! w5 U8 u
};7 f7 I5 G# |. S3 n' w
这里还要注意两件事:/ H: Q! H* L. z
1.注释:$ {. K0 u" Y, }5 y
///@abitable' f/ o `8 W$ V2 w0 b
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。0 D) q/ Y; r6 |8 l5 f
2.结构名称少于12个字符,而且所有的字符都要小写字母。
2.多索引表和定义索引9 U. L; @4 V7 v8 n
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:
typedefeosio::multi_indexdatastore;
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。. w2 {& b9 x; a0 L' b/ P7 B
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:
typedefeosio::multi_index>>datastore;6 ?. C" y+ ]! i
注意:- i1 j# R- n/ R# N) M
indexed_by>
参数:* i2 Z7 v' w: j% B/ O
字段的名称转换为整数,N(secondid)- F$ X6 r& k$ q
一个用户定义的密钥调用接口,const_mem_fun
来看看有三个索引的情况。, u8 ~- q& L& A* ] R( u
///@abitable. X! f4 A% x0 S& n! \! S
structmystruct
{3 Y% h; |& J) i/ d1 L) K7 F6 u7 H
uint64_tkey;
uint64_tsecondid;
uint64_tanotherid;3 p9 j0 c4 i5 |1 ~3 {) N
std::stringname;
std::stringaccount;
uint64_tprimary_key()const{returnkey;}, e- e- v0 R) {
uint64_tby_id()const{returnsecondid;}+ \( y( p( n0 U
uint64_tby_anotherid()const{returnanotherid;}( G. ?3 a4 K' ?0 ~0 j
};4 F* R& M1 I2 S: [6 c+ K
typedefeosio::multi_index>,indexed_by>>datastore;
更多的就不列了。
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。
3.创建定义类型的局部变量
//localinstancesofthemultiindexes. f0 H+ T4 K. j' V6 s( s2 V1 u
pollstable_polls;
votes_votes;0 t. P5 O2 T/ @
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。
#include
usingnamespaceeosio;# E7 K+ ?+ n9 f0 y: l
classyouvote:publiccontract{
public:' w% J. ^2 I$ X. n+ P% c k& C
youvote(account_names):contract(s),_polls(s,s),_votes(s,s)7 C9 b* ~- O9 ^4 Q a
{}/ x- m& c9 u: ?) _
//publicmethodsexposedviatheABI
//onpollsTable% t2 _" c$ j: R
///@abiaction5 y, L' B4 @. T
voidversion()8 c" N- N8 g2 V* T; \( `) \9 k8 H
{* {8 l5 |+ Y* V' P0 I
print("YouVoteversion0.01");
};& C; Z5 J. |1 d. t: c, V" F" w# Y
///@abiaction' [" n2 y& |. \
voidaddpoll(account_names,std::stringpollName). W! |7 b; @6 z$ x" x4 \( K
{
//require_auth(s);9 b. q% B% H: A- |
print("Addpoll",pollName);
//updatethetabletoincludeanewpoll
_polls.emplace(get_self(),[&](auto&p)
{
p.key=_polls.available_primary_key(); m5 v, N0 J* r. f. Z2 y8 f& F
p.pollId=_polls.available_primary_key();
p.pollName=pollName;
p.pollStatus=0;
p.option="";
p.count=0;: }- V1 k8 G( x. a }( [
});# Y/ g) d" I+ {: R, j B' [: Z
};4 Q* o4 s. c7 W( e x" h
///@abiaction0 _- @) K& y0 _8 F
voidrmpoll(account_names,std::stringpollName)' L: T/ o; o; v9 O1 \ S
{
//require_auth(s);
print("Removepoll",pollName);$ D2 Q" \4 d" d# l
std::vectorkeysForDeletion;
//finditemswhichareforthenamedpoll
for(auto&item:_polls)
{
if(item.pollName==pollName)
{
keysForDeletion.push_back(item.key);
}
}! c% x' M/ b& ?
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletion)* c1 h! P6 H4 G" J' n7 H4 g9 C
{
print("removefrom_polls",key);9 ?! ]* n1 X# n. {
autoitr=_polls.find(key);
if(itr!=_polls.end())
{& L2 n* Q" ?* |- O
_polls.erase(itr);
}
}9 G. T( C' {8 H5 M% c! b3 p
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain$ F0 q# O: w% ]3 x U. `
std::vectorkeysForDeletionFromVotes;' `' G* q; N5 I
//finditemswhichareforthenamedpoll
for(auto&item:_votes)
{
if(item.pollName==pollName)- E, ~. O$ s, X1 ^8 N
{( [5 K K6 D! [! H; c
keysForDeletionFromVotes.push_back(item.key);' N* B( U6 k. ?1 J) D3 y
}1 W; j* \8 z4 F/ b0 Q. A
}
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletionFromVotes)
{
print("removefrom_votes",key);) A. v( A/ C, j8 S& r! o
autoitr=_votes.find(key);
if(itr!=_votes.end())
{0 P' e' d2 r, F% p9 S3 k
_votes.erase(itr);
}2 M8 A) l7 [; V8 B! r
}5 J7 w* K, j0 w3 K4 k" v; c
};
///@abiaction; m. s- U& B$ `8 P/ O: K; a: B
voidstatus(std::stringpollName)6 H( o7 F# e# q( x8 W
{) r$ E3 P+ P1 r& o z8 P
print("Changepollstatus",pollName);# a+ k0 B* z4 w- l1 L& [* ?
std::vectorkeysForModify;
//finditemswhichareforthenamedpoll
for(auto&item:_polls)& n( D6 q- ^! L9 H! \
{4 d# K. v) w9 J% ~7 j
if(item.pollName==pollName)0 D" Y8 g9 X7 j5 N* A* V X
{2 h9 y- r/ P; A( L K0 x
keysForModify.push_back(item.key);
}
}
//nowgeteachitemandmodifythestatus; j$ e* K; | n$ M2 q9 f
for(uint64_tkey:keysForModify)
{! h: f3 g, I! I }1 J
print("modify_pollsstatus",key);/ D# W: Z4 }: v6 a+ {: s
autoitr=_polls.find(key);$ c" u! r4 M) D q
if(itr!=_polls.end())
{
_polls.modify(itr,get_self(),[&](auto&p)4 ~: S' B2 h+ Q2 M8 r
{
p.pollStatus=p.pollStatus+1;9 |$ g _1 O2 g, J2 u& o$ R
});
}7 C! @, X7 A; _
}
}; Z o# x$ k& D' W
///@abiaction$ B% J3 J# m& O. m' ^
voidstatusreset(std::stringpollName)* v$ q' R- Q. j2 _. \
{
print("Resetpollstatus",pollName);1 E. q- \- k. i7 g/ ?+ h
std::vectorkeysForModify;3 S) x& H$ U* D# u
//findallpollitems: w4 s4 e" W, m
for(auto&item:_polls)' M' z+ A% N7 }: A2 Y5 z
{; J, F* T A8 @) w; d
if(item.pollName==pollName)
{
keysForModify.push_back(item.key);- {; q+ I. m6 V' J0 M+ J2 ~* @
}4 v% f/ x" P- |$ ^* Y+ x7 p/ R
}
//updatethestatusineachpollitem, x+ s) [6 P( k M' v3 F& d6 ]! ~! U
for(uint64_tkey:keysForModify)- A- |" T5 v/ c+ X7 e
{, V* Z* ~/ f c# C
print("modify_pollsstatus",key);! _) M9 M0 t9 s
autoitr=_polls.find(key);
if(itr!=_polls.end())
{$ \1 A% \' Z0 U% D+ ~5 r2 g; u
_polls.modify(itr,get_self(),[&](auto&p)! Q5 y' H& ?( F$ O( d
{
p.pollStatus=0;5 c' s* a6 m. b( r; z: B
});9 o2 f6 b) y6 k! M% e' u) n( j
}' b; e Y& V. ?# i1 E% ~8 ]' P
}
};
///@abiaction) ] ~9 k! N, p" @
voidaddpollopt(std::stringpollName,std::stringoption)
{
print("Addpolloption",pollName,"option",option);5 T$ Z7 \* g2 m" |* U. F: I
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption
for(auto&item:_polls)
{& H+ P g. ~' e4 K h
if(item.pollName==pollName)
{: n# p* ?. ?1 d: h( o6 c k
//canonlyaddifthepollisnotstartedorfinished
if(item.pollStatus==0)
{, W2 q2 w2 ~& l. h5 k2 V- v
_polls.emplace(get_self(),[&](auto&p)
{1 `$ E4 Z# T- i- }& |& ^ b6 q! \
p.key=_polls.available_primary_key();! k+ b4 ?/ @" Z
p.pollId=item.pollId;; b# S4 ?/ u7 G& ]
p.pollName=item.pollName;
p.pollStatus=0;# ]3 J+ \' S4 N: v! P; w
p.option=option;
p.count=0;
});$ N8 N9 S3 Y4 ?8 M& _" |
}0 U2 H$ [. d* {& y3 L
else6 S: C$ b1 h: ^4 T0 \( w6 \
{
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");9 z. T* d$ a( O0 V# C
}" c6 e$ F9 i; M
break;//soyouonlyadditonce7 A, r5 R' S- ~2 I
}& A5 B! L* j& ?3 [% `- q, J) E6 b
}: f: {; c) E1 O( Q4 Q
};( U0 v- E# s6 }1 t5 ?
///@abiaction
voidrmpollopt(std::stringpollName,std::stringoption)8 ]! a) N6 g3 n3 z2 K u" }. I
{
print("Removepolloption",pollName,"option",option);4 `: e6 @1 }! ~6 c
std::vectorkeysForDeletion;% c+ d% @* {7 I/ k+ |+ b
//findandremovethenamedpoll
for(auto&item:_polls)8 s7 c9 [ R) B2 I! A& Z
{
if(item.pollName==pollName)2 n! ]# c$ w7 d8 j3 m5 q/ x0 I
{2 \+ `6 O! ^. N# j% U! J
keysForDeletion.push_back(item.key);3 s' H' }7 t2 p1 X3 b; H8 W
}
}6 P1 E! N, r" L( W/ ]# b$ K2 M
for(uint64_tkey:keysForDeletion), A' j& \" p! V0 P
{( C: J! h0 r* i% J( j( a
print("removefrom_polls",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())( k( v0 @1 ?" K/ j) w# k7 y2 P
{+ k5 N0 ?/ z1 L1 }6 Z
if(itr->option==option)* V9 m X l5 V/ p8 J6 F
{
_polls.erase(itr);
}- `0 }4 v. K/ k0 r, M
}' Y0 s) ^& |" l" J, q! i5 ~* c
}' S" ?& C2 E, G
};4 B* l7 @; K9 F; @( K3 X9 T
///@abiaction6 A* {1 s- ^9 n0 F8 @4 y) j. M4 N4 x
voidvote(std::stringpollName,std::stringoption,std::stringaccountName)
{* `% o; g0 @3 j! V0 l \
print("votefor",option,"inpoll",pollName,"by",accountName);
//isthepollopen
for(auto&item:_polls)" @+ ~8 Y, j Y* v( U
{
if(item.pollName==pollName)+ }# Z; J) j( @% X& L4 j
{
if(item.pollStatus!=1)9 k; e* f! |$ S* b
{
print("Poll",pollName,"isnotopen");
return;
}. [9 v2 `8 f4 c7 p3 r) C0 C( }
break;//onlyneedtocheckstatusonce- m! Q; \ d+ i: i
}7 \# c2 p- y. p/ O5 |: \5 H
}
//hasaccountnamealreadyvoted?7 V4 V9 \2 M' C& v4 N# P
for(auto&vote:_votes)" C {" ]! E% M3 K
{
if(vote.pollName==pollName&&vote.account==accountName)2 r8 S- c; b, r* {8 ~5 U0 F2 m
{
print(accountName,"hasalreadyvotedinpoll",pollName);! U4 i& ` N C- [, A) x
//eosio_assert(true,"AlreadyVoted");
return;+ h4 b- A. l& s
}
}
uint64_tpollId=99999;//getthepollIdforthe_votestable) ~" `% l0 X$ G3 u; B0 @
//findthepollandtheoptionandincrementthecount& y1 l& \7 H! h1 q4 S
for(auto&item:_polls)) e8 A, g7 H8 x
{0 e5 v% ?2 z- m4 F2 }6 i
if(item.pollName==pollName&&item.option==option)1 ^, a' n/ L2 m- G8 O, v
{
pollId=item.pollId;//forrecordingvoteinthispoll8 v3 G3 f+ t2 {- [' \( Q
_polls.modify(item,get_self(),[&](auto&p)0 s5 ?+ l' X, R9 \5 B
{5 T, V+ o& a- G1 V* D& r! l
p.count=p.count+1;- x; o9 {6 ?! q1 q+ U. R
});
}& }% W* B- n: R
}" M+ {% z0 U! ~
//recordthataccountNamehasvoted3 d) X# N( [+ Q: m+ K( U8 z, F I
_votes.emplace(get_self(),[&](auto&pv)
{5 v! w$ E( K: ~3 ]6 A
pv.key=_votes.available_primary_key();9 j$ T" N! K& ?) o7 R/ r
pv.pollId=pollId;& Q; _$ c* C; e) {8 k1 a& u
pv.pollName=pollName;3 e$ u$ c8 T2 a& v
pv.account=accountName;
});
};
private:4 p0 `; E x! P
//createthemultiindextablestostorethedata% u7 X) z) ?8 Z- U
///@abitable
structpoll& D4 P5 l6 N, T1 U( {* G( G) ^
{
uint64_tkey;//primarykey
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption- q2 W6 H& g4 q
std::stringpollName;//nameofpoll* t8 C% j& E$ Q* G; g
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished3 ]5 h; b( D; O% Y; J; P
std::stringoption;//theitemyoucanvotefor3 w7 m4 ? @1 A& s+ o$ G
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable.' d2 ?& X4 ^+ Q! ^/ a2 M: O
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}" z0 s/ D- Q, r q3 n
};0 u2 e; Y, D8 I, f- o
typedefeosio::multi_index>>pollstable;- y/ M$ Q$ j' \+ W3 i
///@abitable
structpollvotes
{
uint64_tkey;* k' A: x/ k0 a
uint64_tpollId;& N$ d9 |3 d0 \
std::stringpollName;//nameofpoll4 Q; X U1 o/ s
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>16 A8 q& ^8 y) z: S
uint64_tprimary_key()const{returnkey;}! u: P2 {$ \6 {8 X' T8 u
uint64_tby_pollId()const{returnpollId;}
};4 p7 i$ d9 O1 Y1 @8 p6 s2 o$ t: c3 c+ W
typedefeosio::multi_index>>votes;
//localinstancesofthemultiindexes' {6 W! I: I) G' ]8 }2 P
pollstable_polls;
votes_votes;9 w7 U' C; v% {! `, _4 j# O- S& U
};3 B& c4 I$ s q& v4 i$ k+ V6 c
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))+ @3 u3 I9 X; [& z
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人