EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
177
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。/ o2 c' Y+ @" t$ G
1.创建一个结构
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。$ \7 }) o8 o7 A* x( A, z
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。* x4 ?+ B6 Y) \1 k2 ?% V3 z
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。' F2 H; i; o0 |$ Y; i( Z
///@abitable: c/ a% P& [+ _, o8 ^
structmystruct" u$ Q* |! Z3 @0 {" F5 O
{% j; ^8 H- m' k7 _/ I* ? J' y% ]
uint64_tkey;( ~2 W7 ~5 k( f. c2 Q/ R
uint64_tsecondid;
std::stringname;
std::stringaccount;
uint64_tprimary_key()const{returnkey;}//getterforprimarykey
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey. B1 f! y& ^ u6 F
};
这里还要注意两件事:
1.注释:
///@abitable
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。( W( R4 X* n6 ]7 L& Z
2.结构名称少于12个字符,而且所有的字符都要小写字母。1 H" a' \! \1 x d8 L' [! a. V
2.多索引表和定义索引5 Q' g' \4 K- M1 r8 U) J x$ {8 [2 p
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:) Z2 i) Z' v" e7 B) S L) ]
typedefeosio::multi_indexdatastore;# H4 k6 h0 v$ \
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:
typedefeosio::multi_index>>datastore;7 h9 i: Y% x& P3 n. A/ }( |
注意:
indexed_by>: i9 [3 U& F4 ^5 `) _0 G
参数:. R: ~ n3 A: a) Y; T
字段的名称转换为整数,N(secondid)* a& k0 G% ^5 s
一个用户定义的密钥调用接口,const_mem_fun5 [3 {% ]8 c6 ]
来看看有三个索引的情况。* ]- e+ D. _ \2 S. N# q$ |& Y. k' d3 K
///@abitable5 X! p& A8 U; {$ V
structmystruct
{) q: g0 x1 M3 k V- P3 q1 b
uint64_tkey;. o* u( L4 |' T' r# K/ c
uint64_tsecondid;1 v6 w* ~8 I5 Z. Q* p
uint64_tanotherid;" N2 x0 v" k3 d# Y, y6 n
std::stringname;
std::stringaccount;4 [! W: }' U4 K/ \
uint64_tprimary_key()const{returnkey;}
uint64_tby_id()const{returnsecondid;}
uint64_tby_anotherid()const{returnanotherid;}
};
typedefeosio::multi_index>,indexed_by>>datastore;
更多的就不列了。
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。
3.创建定义类型的局部变量
//localinstancesofthemultiindexes
pollstable_polls;4 _8 z! u) R! s; c( b( ^) Q' w
votes_votes;3 w* m" U6 p% U i6 P
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。7 ?1 d7 y6 o) B, B, _; e
#include
usingnamespaceeosio;
classyouvote:publiccontract{
public:% h, y. W5 M- b" \" T6 ~$ p
youvote(account_names):contract(s),_polls(s,s),_votes(s,s)
{}
//publicmethodsexposedviatheABI
//onpollsTable
///@abiaction
voidversion(), C4 a0 W r! h$ R E
{
print("YouVoteversion0.01");
};
///@abiaction- P- y, ?. o3 @6 c
voidaddpoll(account_names,std::stringpollName)
{
//require_auth(s);" Y0 L+ A) m% r) r
print("Addpoll",pollName);
//updatethetabletoincludeanewpoll
_polls.emplace(get_self(),[&](auto&p)
{: C: ^6 k1 r3 q2 f- v3 x9 [' d
p.key=_polls.available_primary_key();" r; e! Q0 ^3 {7 X
p.pollId=_polls.available_primary_key();
p.pollName=pollName;
p.pollStatus=0;
p.option="";' u& h8 v1 \& |; D' l. X
p.count=0;+ ?0 x& i; h1 D: y2 c, z! p8 E! }
});/ d4 t0 O5 r8 ?2 q( W D1 O
};
///@abiaction
voidrmpoll(account_names,std::stringpollName)# j- p, N. l1 ^ t4 A
{
//require_auth(s);
print("Removepoll",pollName);
std::vectorkeysForDeletion;
//finditemswhichareforthenamedpoll
for(auto&item:_polls)
{( I4 L+ U5 h2 c
if(item.pollName==pollName)
{, C- ~- L# \, s8 M; R& D" I& D" L
keysForDeletion.push_back(item.key);+ ?. u) w4 V- x7 Z2 T
}
}3 p6 n6 z. P9 Q/ ~( W
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletion)' e% g2 S$ H; h6 d( e+ s1 d
{9 D+ ~/ H- s+ O
print("removefrom_polls",key);- [! ^9 t: f5 Y- v: a! M. u" Y
autoitr=_polls.find(key);
if(itr!=_polls.end())& h8 H9 Y4 R5 T" K J5 \- N& |
{! s- r" u$ ]# C
_polls.erase(itr);7 Q; A& V" X0 v* K1 {. ]* z
}
}2 R! S( J- s; f- e3 k
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain
std::vectorkeysForDeletionFromVotes;
//finditemswhichareforthenamedpoll9 B) C; O4 n1 E: `) A2 ?" f
for(auto&item:_votes)- Y5 A* M/ u/ q; k+ C% S+ \& N8 |
{
if(item.pollName==pollName)
{( t+ s0 ^+ x& o
keysForDeletionFromVotes.push_back(item.key);6 q1 u& ]9 }) ~" {% h# L0 x% X
}2 J- |8 \7 i, l4 r
}
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletionFromVotes)
{
print("removefrom_votes",key);% a$ U S- a4 J! M1 p" U
autoitr=_votes.find(key);7 a: A6 L# j# r1 r
if(itr!=_votes.end())
{
_votes.erase(itr);: g4 V! X, G( a! q k
}1 j# E# H# Z. U4 \+ g& n5 U
}
};
///@abiaction
voidstatus(std::stringpollName)- N0 t' L6 `; |$ g9 N
{
print("Changepollstatus",pollName);! v& L" {5 `' K0 Q5 S4 n
std::vectorkeysForModify;' } A. |7 w: R A& Q# a4 x
//finditemswhichareforthenamedpoll& I( \+ Z* f, v- H0 H
for(auto&item:_polls)
{, x/ d3 }/ ^" k) Q+ q- s- W5 g
if(item.pollName==pollName)- D5 w1 j5 @' ^0 q
{
keysForModify.push_back(item.key);
}, W( w; \$ n9 x9 f) K% @
}, ^* o* g+ C) B' F3 H
//nowgeteachitemandmodifythestatus6 A. A8 r# O& R
for(uint64_tkey:keysForModify)
{ v- \ h6 W, J4 i) w
print("modify_pollsstatus",key);. z' w! B: h+ h4 y
autoitr=_polls.find(key);
if(itr!=_polls.end())
{
_polls.modify(itr,get_self(),[&](auto&p)- [: u+ p/ F; ^
{5 D% g; b. ?6 ^6 a* i
p.pollStatus=p.pollStatus+1;
});
}
}
};9 l/ x5 _* X4 |
///@abiaction
voidstatusreset(std::stringpollName)
{' R7 V# V% f4 n
print("Resetpollstatus",pollName);( S/ E6 F5 S2 w3 z
std::vectorkeysForModify;/ x" U4 @4 u Y" P7 f
//findallpollitems0 `- p% }1 @( C4 g3 g
for(auto&item:_polls)% R5 {" y7 _0 D9 J) k: S, C
{1 ]* I9 i- k0 C3 R8 g1 P; D4 v9 H
if(item.pollName==pollName)
{" C* s7 @8 ]% d1 {
keysForModify.push_back(item.key);2 ]* z5 H p% J/ N4 q# \
}
}% a' o4 a) ^1 Z2 u8 m' z& O, q+ u" V
//updatethestatusineachpollitem) t& @& P+ b0 Z$ ^
for(uint64_tkey:keysForModify)
{
print("modify_pollsstatus",key);
autoitr=_polls.find(key);" o7 L( J% k' c1 l2 ?, C
if(itr!=_polls.end())
{& b0 ]# T" {: R7 c# z
_polls.modify(itr,get_self(),[&](auto&p). m9 |; \- U2 ~; y. n
{8 {- e$ m- v% C; Z; `, O
p.pollStatus=0;
});
}
}0 b+ l& H2 h! V
};! ?. i7 {2 ]+ z$ f
///@abiaction- g2 Z0 r) C, E4 L( y5 E
voidaddpollopt(std::stringpollName,std::stringoption); M" ^! `4 f7 S8 h# G3 h
{
print("Addpolloption",pollName,"option",option);
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption! q0 z" B1 b2 }: e0 d; S
for(auto&item:_polls)- Y# \8 a' R, C) p1 I' {
{/ ]& Q7 ]# n" k( D5 s+ a
if(item.pollName==pollName)' @) @% V; ]% V9 L+ y9 Y
{
//canonlyaddifthepollisnotstartedorfinished
if(item.pollStatus==0)
{
_polls.emplace(get_self(),[&](auto&p): k: ~" A9 e6 l6 D# ~. e6 U1 C' j
{" C/ N$ ]+ T0 M$ y9 ^
p.key=_polls.available_primary_key();
p.pollId=item.pollId;
p.pollName=item.pollName;
p.pollStatus=0;2 {0 j& |# a1 {( M$ |
p.option=option;: t9 H& Y4 j) G7 Z& m! I
p.count=0;
});
}
else
{. ^. e ^- E0 g5 C0 Y. S, h
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");; j- d; }$ z. l2 D+ ^, o
}
break;//soyouonlyadditonce1 K! F$ |6 H9 w7 M2 r# m$ r& z
}; ]# o7 L6 s! J3 W6 |# z4 ]
}
};; y# c; M: M+ U w
///@abiaction
voidrmpollopt(std::stringpollName,std::stringoption)) `4 v8 d6 c2 |4 u# y0 }
{$ N b8 f: O* | s; u. m
print("Removepolloption",pollName,"option",option);
std::vectorkeysForDeletion;
//findandremovethenamedpoll, r/ _0 i6 Y- w1 }: u
for(auto&item:_polls)! B+ n& z4 g( f: y6 D2 u& R
{/ z6 ] r1 x7 f+ B8 E _, u
if(item.pollName==pollName)
{+ t- g8 Z2 ~. V1 r
keysForDeletion.push_back(item.key);
}
}) e' `2 @4 c* E
for(uint64_tkey:keysForDeletion)
{
print("removefrom_polls",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())
{* w: M' l* J9 K8 Z; e
if(itr->option==option)
{
_polls.erase(itr);
}7 B$ s5 K+ f7 |+ m+ V
}% M! f* |/ b# ~: T- B0 f
}/ ?: y( @$ J( Z4 e3 p
};+ Z1 K: W3 N. L o' l. z
///@abiaction U6 ]% s5 `+ t
voidvote(std::stringpollName,std::stringoption,std::stringaccountName)/ l! T- Z; }) _3 Q
{
print("votefor",option,"inpoll",pollName,"by",accountName);
//isthepollopen: _- O: p* s9 O& d+ \
for(auto&item:_polls)5 f$ N7 @" h3 h, g) @/ K% w
{
if(item.pollName==pollName)" B+ e" @- {- J
{3 r7 X9 |7 D- |" p3 t3 V
if(item.pollStatus!=1)
{
print("Poll",pollName,"isnotopen");
return;; i6 K/ E2 ~9 ]; K* U
}% X: i6 L" c8 u+ W& c5 `; z
break;//onlyneedtocheckstatusonce# |4 y: O. _. }( w( [
}* A9 `5 J: H. ~& h; w" V2 e1 I
}
//hasaccountnamealreadyvoted?+ ?5 R" `& X. J
for(auto&vote:_votes)4 b& N/ y; x! U- H+ N9 X3 o5 D6 y$ N
{, H* t% P- M3 w6 g. Y+ F8 T" J
if(vote.pollName==pollName&&vote.account==accountName)
{
print(accountName,"hasalreadyvotedinpoll",pollName);- Q: f" @% q* T
//eosio_assert(true,"AlreadyVoted");
return;
}
}' C5 `4 L, m& l( e1 u/ e
uint64_tpollId=99999;//getthepollIdforthe_votestable ~- l- R, Q; U. {9 K
//findthepollandtheoptionandincrementthecount* K6 O7 E( `# m/ c5 o: H/ |
for(auto&item:_polls)
{
if(item.pollName==pollName&&item.option==option)
{. J; ?) C; }8 y
pollId=item.pollId;//forrecordingvoteinthispoll! i e5 l. r; O6 S3 n0 S8 t7 w
_polls.modify(item,get_self(),[&](auto&p)
{
p.count=p.count+1;* O0 Q; O) u$ O$ v9 w% e- {; v
});0 R# e/ a4 z4 K% d
}
}
//recordthataccountNamehasvoted
_votes.emplace(get_self(),[&](auto&pv)
{
pv.key=_votes.available_primary_key();! p! F/ H( [& t2 b! p( d& \. I
pv.pollId=pollId;1 Q* \. U8 m. A9 m' @5 q6 ~
pv.pollName=pollName;$ e6 @ p( T" ]
pv.account=accountName;
});
};
private:' v6 E7 J0 |- F2 J( K" W; s P! i l- _
//createthemultiindextablestostorethedata5 a: r8 V! Y3 _" e E5 X
///@abitable( o% L* P6 f5 f6 y& P. e
structpoll6 e/ g! _( p1 W' w; S- Y5 U
{
uint64_tkey;//primarykey
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption& d) [8 K4 m( k
std::stringpollName;//nameofpoll
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished' W; c7 q: m" ?' r
std::stringoption;//theitemyoucanvotefor' R8 |' n" d. U9 I+ A& O3 H
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable.) D S+ C) {" m _4 U2 B% R; W
uint64_tprimary_key()const{returnkey;}- m4 Q- g2 q& g! Y
uint64_tby_pollId()const{returnpollId;}8 e* `* A V3 B8 \+ H
};6 N' F% y. m# W6 K& x
typedefeosio::multi_index>>pollstable;, d1 [0 j0 C# j; q4 C
///@abitable
structpollvotes
{
uint64_tkey;
uint64_tpollId;
std::stringpollName;//nameofpoll
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>10 D4 z/ w. U) U2 }: [% s- F
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}
};6 W1 S+ ? B3 r% N& Y
typedefeosio::multi_index>>votes;
//localinstancesofthemultiindexes A# d" P J2 a- g9 m3 o( }3 T4 s1 ?
pollstable_polls;
votes_votes;
};
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))0 @7 t+ C# u7 l9 T7 \ [) h
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人