EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
128
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。# _5 s1 P* w; d, n2 o) C. M7 q
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。# _ q. [- W, W. i% a
1.创建一个结构
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。4 K! h1 ^4 u8 g# m4 Q/ o( N
///@abitable
structmystruct! U! k5 P, Q5 u0 F: x9 b1 f( H
{7 u) g! K2 \" ~
uint64_tkey;
uint64_tsecondid;
std::stringname;
std::stringaccount; \( G Q+ l! J9 d @7 ~6 I/ l
uint64_tprimary_key()const{returnkey;}//getterforprimarykey
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey9 o$ W+ B* O+ H1 ~6 i6 \3 K* j
};& U+ H0 u: ~- O' c& \0 I$ M0 L* o. D( M( S
这里还要注意两件事:
1.注释:) _' U% j% I8 Y. D8 I$ ^1 C4 [' m
///@abitable8 }9 m) a: K7 a3 ]
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。
2.结构名称少于12个字符,而且所有的字符都要小写字母。
2.多索引表和定义索引$ R- Q! X1 i7 X
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:
typedefeosio::multi_indexdatastore;
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。6 M, A* Z9 H/ A- {( M
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:
typedefeosio::multi_index>>datastore;
注意:/ |% b" I% E: z: p4 b: R' r
indexed_by> a/ v1 b9 e6 C I! z4 u$ x" j
参数:
字段的名称转换为整数,N(secondid)+ Q- K% @' U- D! T+ H/ C+ y
一个用户定义的密钥调用接口,const_mem_fun
来看看有三个索引的情况。: Z. @% o8 a; _( ~0 n. q
///@abitable
structmystruct
{
uint64_tkey;. D* K' b8 v7 F3 O4 Y& X" u
uint64_tsecondid;0 s% ^% y* `& w/ w- `7 r0 u/ O
uint64_tanotherid;" \& a* X; ?8 t5 k. m4 Q
std::stringname;* O- `0 K* Z: y- ] N
std::stringaccount;& _5 C* L9 X/ n5 s4 r1 P' r% ]; l
uint64_tprimary_key()const{returnkey;}
uint64_tby_id()const{returnsecondid;}$ U7 ?; ~& _; x7 r- I* y0 x
uint64_tby_anotherid()const{returnanotherid;}
};
typedefeosio::multi_index>,indexed_by>>datastore;
更多的就不列了。
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。* x5 a# Q& U1 J5 ~% g- |
3.创建定义类型的局部变量
//localinstancesofthemultiindexes
pollstable_polls;
votes_votes;
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。. \. H! Y( q: L' B, u: D# n: G
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。: s% f$ }& ~* E7 h' S
#include1 w% g. u4 `8 U' _+ h: ]/ Z
usingnamespaceeosio;
classyouvote:publiccontract{
public:
youvote(account_names):contract(s),_polls(s,s),_votes(s,s)
{}6 w4 Y( c8 e" g; d
//publicmethodsexposedviatheABI) W8 g5 L2 x9 F0 L9 ]6 Q% j7 i
//onpollsTable
///@abiaction+ O4 s( j; I, g! \0 v) `
voidversion(): B/ E2 g4 C/ O$ x4 D( \, @8 r% H
{; W: r j0 N6 M u
print("YouVoteversion0.01");
};0 j" ]$ B; A. n3 V" j' m
///@abiaction
voidaddpoll(account_names,std::stringpollName)0 d2 ~; U2 L. ?* g+ s9 f
{
//require_auth(s);
print("Addpoll",pollName);# k* d! _. d: l) F
//updatethetabletoincludeanewpoll
_polls.emplace(get_self(),[&](auto&p)/ @1 ?6 |( h- F+ C9 x6 D
{
p.key=_polls.available_primary_key();6 \" ~ h& \# Z
p.pollId=_polls.available_primary_key();4 J v8 p1 c$ @
p.pollName=pollName;
p.pollStatus=0;4 o% a8 D3 p0 F
p.option="";7 U" d P% B. u0 I
p.count=0;
});- `0 [( g0 g; h7 ]+ n' z
};
///@abiaction1 z4 Q- |; R! f0 X; u
voidrmpoll(account_names,std::stringpollName)
{
//require_auth(s);: x [/ d' ~: L0 \1 x) r& c
print("Removepoll",pollName);. e$ B8 h$ X+ [* H( M: Y7 {
std::vectorkeysForDeletion;3 C# g8 m; B$ I7 b$ R# s
//finditemswhichareforthenamedpoll
for(auto&item:_polls): w& v$ E0 o+ U- d l1 x/ T% R
{5 o% s3 F: s, q! |. p% o
if(item.pollName==pollName)
{
keysForDeletion.push_back(item.key);
}
}
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletion)1 q' t% u7 t. I
{
print("removefrom_polls",key);* o1 b2 S; m+ B8 o _6 {& F" y& R C
autoitr=_polls.find(key);
if(itr!=_polls.end())4 ]% u# a* G" @6 t. x F
{
_polls.erase(itr);
}
}
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain
std::vectorkeysForDeletionFromVotes;8 I9 ?: @" i- V# L
//finditemswhichareforthenamedpoll# u R* t( \6 w/ r4 v
for(auto&item:_votes)7 A7 \1 Q# W3 M
{
if(item.pollName==pollName)
{
keysForDeletionFromVotes.push_back(item.key);
}# p9 v5 D/ a4 ^8 I3 S1 @
}
//nowdeleteeachitemforthatpoll) X% P" \: S% x6 D% ^
for(uint64_tkey:keysForDeletionFromVotes)
{
print("removefrom_votes",key);
autoitr=_votes.find(key);' Y8 t& L8 O# w8 X6 i- c* h
if(itr!=_votes.end())
{
_votes.erase(itr);! _6 w8 _+ K! n& Q, f1 X3 i
}9 ]" L% q( o S& ]6 Y& Y
}
};
///@abiaction
voidstatus(std::stringpollName)/ Z, r j8 p( J
{
print("Changepollstatus",pollName);: W9 ^9 \1 h7 ~9 A y
std::vectorkeysForModify;( y( f0 q3 ?5 o: y# k& ?8 Z& Z- m
//finditemswhichareforthenamedpoll
for(auto&item:_polls)
{5 X t" m2 v4 L. T# d- ^% `
if(item.pollName==pollName)
{
keysForModify.push_back(item.key);- a/ k7 E$ P. z, L/ z8 G/ W
}; @0 L, d" ]4 S' k: A& k6 Z
}9 L2 Q5 x( A+ ?& u. Z
//nowgeteachitemandmodifythestatus
for(uint64_tkey:keysForModify): a. B# C! s; f W0 m$ k
{
print("modify_pollsstatus",key);
autoitr=_polls.find(key);. X/ o$ ~. ?9 K6 N+ o9 C
if(itr!=_polls.end())
{' ^0 C. ~5 }& d7 {
_polls.modify(itr,get_self(),[&](auto&p)
{
p.pollStatus=p.pollStatus+1;
});8 _! V0 i$ ]. B q8 g( n% `
}
}
};" Q$ t3 _" r1 Z
///@abiaction& F' P, m) Y% h9 T& H5 {
voidstatusreset(std::stringpollName)
{: R* ]8 x+ ~2 I$ [
print("Resetpollstatus",pollName);
std::vectorkeysForModify;
//findallpollitems
for(auto&item:_polls)
{
if(item.pollName==pollName)' H( w2 s, {+ `+ U1 W2 k
{2 N. e$ k# D2 k% C$ F+ f1 A
keysForModify.push_back(item.key);
}3 Q: t- E/ D1 c( D# O
}# V6 |7 S5 U. j& o$ _
//updatethestatusineachpollitem
for(uint64_tkey:keysForModify)2 z- z( x2 d% A% m1 c/ [: A
{
print("modify_pollsstatus",key);
autoitr=_polls.find(key);& x% x( O& L. s( {# m, ]9 c
if(itr!=_polls.end())
{
_polls.modify(itr,get_self(),[&](auto&p)
{
p.pollStatus=0; \) s+ `. |6 D5 _6 a! ?
});
}+ A+ e. f0 M# H6 ^4 a5 @ a
}# @& Q% V1 f, x# m K
};
///@abiaction
voidaddpollopt(std::stringpollName,std::stringoption)
{. w* B4 e- X( `8 \: Z1 P. H
print("Addpolloption",pollName,"option",option);
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption
for(auto&item:_polls)+ l Y6 M: y* c1 s c5 Q {. E
{
if(item.pollName==pollName)
{0 g4 m) y- {) I# X7 |2 V, p2 b( M6 D
//canonlyaddifthepollisnotstartedorfinished
if(item.pollStatus==0)
{
_polls.emplace(get_self(),[&](auto&p)% M( T+ c0 c! ]; h6 m$ y
{3 w; {' j% R8 t
p.key=_polls.available_primary_key();
p.pollId=item.pollId;* j- B- W( g) N9 S. }
p.pollName=item.pollName;" g) [0 U1 q( k; S/ e, r- @8 P3 s
p.pollStatus=0;8 S% k0 m* t! X% r% g. n
p.option=option;* T! F$ ]9 w" z6 w# y' U7 k
p.count=0;6 e4 z. Y/ F* j, H+ N4 W7 @. |
});
}. M+ U8 @: P5 L7 Z" a6 q: R' Y; ~
else
{) F! S4 y9 \# g! E4 Y
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");
}/ V3 J ], I0 V" e% O) K
break;//soyouonlyadditonce
}
}
};4 [8 `) P2 Q/ K6 C$ |, O' K/ p( z
///@abiaction
voidrmpollopt(std::stringpollName,std::stringoption); x. L6 O0 F- D S& |# ]+ [
{
print("Removepolloption",pollName,"option",option);
std::vectorkeysForDeletion;
//findandremovethenamedpoll* w) @' L; X# o2 [' }& T E1 g
for(auto&item:_polls)( N# w* {3 B9 p" p; X: |4 I
{
if(item.pollName==pollName)- X5 {% Q/ I ]" y7 d* z
{
keysForDeletion.push_back(item.key);4 g2 J" c+ g! [: d' {
}
} R: ]. I/ C& S7 M6 ?) w$ Q
for(uint64_tkey:keysForDeletion)5 _# J$ B' ?! Q3 I a# H% B( ~. ~
{
print("removefrom_polls",key);5 x8 S: \. N4 H' p" D4 ]! l
autoitr=_polls.find(key);
if(itr!=_polls.end())
{! K7 i( o# t3 E# C+ X u
if(itr->option==option)
{
_polls.erase(itr); v' D0 m) i- v7 i
}
}
}2 h. `3 v5 U5 O- \% f
};
///@abiaction8 }9 d. ]! E) b% \% o
voidvote(std::stringpollName,std::stringoption,std::stringaccountName), k" l: m, c; B v$ q$ j0 ?' y8 X
{
print("votefor",option,"inpoll",pollName,"by",accountName);9 V& W' Z- n$ n" |
//isthepollopen
for(auto&item:_polls)
{/ W+ B( k) C2 N+ [0 N8 r8 S0 x
if(item.pollName==pollName)
{
if(item.pollStatus!=1)/ G2 c7 c% ^4 ]4 J
{
print("Poll",pollName,"isnotopen");
return;
}
break;//onlyneedtocheckstatusonce! _: x$ b+ \' j6 r3 Y
}
}
//hasaccountnamealreadyvoted?3 q9 b* u5 [1 o& V2 I" V @
for(auto&vote:_votes)
{5 X% |* y8 ^5 V8 i& a3 H
if(vote.pollName==pollName&&vote.account==accountName) E1 D4 L8 k$ D! W+ w
{
print(accountName,"hasalreadyvotedinpoll",pollName);( H( }! x7 U2 o4 v+ ^/ @, E
//eosio_assert(true,"AlreadyVoted");1 E. v' J, Q2 N: s- s! }' T
return;& \: w; ^" h- P2 Z- j8 Y5 Q! |
}0 t3 j6 K; G/ }1 f+ |
}
uint64_tpollId=99999;//getthepollIdforthe_votestable' R7 w0 I% }9 m! R& W8 l
//findthepollandtheoptionandincrementthecount
for(auto&item:_polls)8 {( r8 X& [+ V" u6 m( v
{
if(item.pollName==pollName&&item.option==option)
{
pollId=item.pollId;//forrecordingvoteinthispoll# M( L( d6 F4 `! w% q! J: \
_polls.modify(item,get_self(),[&](auto&p)9 g# x; Y: R6 Z: X7 k) S0 K2 k/ U6 s
{
p.count=p.count+1;
});
}
}8 P M0 R3 y# Q
//recordthataccountNamehasvoted2 K/ W: t, s3 X6 E- M
_votes.emplace(get_self(),[&](auto&pv)
{
pv.key=_votes.available_primary_key();
pv.pollId=pollId;
pv.pollName=pollName;# Y3 g1 x$ {$ z% b% \ T
pv.account=accountName;3 \4 A' _7 e! c" U' a1 N; e( N
});
};. h8 n- ], y3 k- E" d6 W
private:
//createthemultiindextablestostorethedata$ m3 b$ I# h- v( a2 w4 J$ S
///@abitable
structpoll
{
uint64_tkey;//primarykey
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption
std::stringpollName;//nameofpoll+ l, V! j7 [2 X1 e4 M F) a
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished
std::stringoption;//theitemyoucanvotefor
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable.
uint64_tprimary_key()const{returnkey;}& X T, I Y: g6 D$ t
uint64_tby_pollId()const{returnpollId;}
};9 ^- I/ H' R9 `
typedefeosio::multi_index>>pollstable;
///@abitable
structpollvotes5 B" {" |4 w2 \3 B6 k8 s
{
uint64_tkey;3 {: j% S6 T) G( o, [0 ]
uint64_tpollId;
std::stringpollName;//nameofpoll) l6 ]4 O+ R; v) c
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>10 ]5 A2 l8 \. p
uint64_tprimary_key()const{returnkey;}8 T1 Q% ~& I0 Z( t0 S- w
uint64_tby_pollId()const{returnpollId;}
};
typedefeosio::multi_index>>votes;" G2 j" l: E1 H8 y6 H
//localinstancesofthemultiindexes$ L2 J9 M4 w5 m! L
pollstable_polls;
votes_votes;; T7 e' `) f+ I* i# F$ D
};
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人