EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
178
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。2 y0 K/ S( ^% x+ ^1 f4 M4 P
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。
1.创建一个结构
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。9 f) n- L$ w1 T, l2 j
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。4 u5 \4 f0 l; i7 _2 Y' _6 O1 p" A
///@abitable- W" |# a) Y/ q# ?$ w
structmystruct, B. ]3 M) [4 E0 M* D
{. E4 t% z# X# f2 e1 M$ s* d' o+ }
uint64_tkey;
uint64_tsecondid;9 W- J# a6 `3 w1 W4 ^4 ~
std::stringname;7 K0 A* g4 y6 @+ L2 S& }/ r0 l
std::stringaccount;5 F6 D: ]1 Z# E' j( I0 v# u
uint64_tprimary_key()const{returnkey;}//getterforprimarykey: }6 y* f5 F3 u% J
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey
};
这里还要注意两件事:' [* S3 W. \, B; j3 }) n" I) R) H( W
1.注释:/ }. F* r5 I; \& |: e
///@abitable( W& b G, U; ^/ [: v
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。9 ~! c+ [: r- ~. t
2.结构名称少于12个字符,而且所有的字符都要小写字母。7 H( K8 w. G# F
2.多索引表和定义索引
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:$ ?$ F8 G1 f4 J7 S6 i4 o$ L
typedefeosio::multi_indexdatastore;
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。$ P. f1 W) ]. L |) W( W @* u# R
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:
typedefeosio::multi_index>>datastore;2 u2 {0 V. }1 q O. @! h8 Q% U x
注意:! ? ^7 B) t8 F* _. A
indexed_by>
参数:
字段的名称转换为整数,N(secondid)
一个用户定义的密钥调用接口,const_mem_fun. z. U9 {8 ?( c q
来看看有三个索引的情况。
///@abitable$ i1 f# ]6 j# r+ Z+ Z
structmystruct. t4 O4 u) b( p0 [5 L0 Y+ |
{
uint64_tkey; m6 t! Z; `4 l/ o
uint64_tsecondid;
uint64_tanotherid;
std::stringname;8 Z0 b: F% L' L6 n6 v
std::stringaccount;
uint64_tprimary_key()const{returnkey;}: D/ G7 a% }) q: l* i% L
uint64_tby_id()const{returnsecondid;}
uint64_tby_anotherid()const{returnanotherid;}: P5 K. Z/ y1 A
};) t% w- w% Q" Y" }. z
typedefeosio::multi_index>,indexed_by>>datastore;
更多的就不列了。
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。
3.创建定义类型的局部变量
//localinstancesofthemultiindexes; p: ~- H, l- O1 l
pollstable_polls;, m) k9 y- v) D: {- z
votes_votes;% X+ _ `3 R5 @' o
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。
#include$ S8 x4 \, q' y3 `; \& l7 \( z
usingnamespaceeosio;
classyouvote:publiccontract{
public:
youvote(account_names):contract(s),_polls(s,s),_votes(s,s)$ t4 x2 r0 M, k) [7 d9 C$ \! ~
{}/ ~% [' e& A( O% h3 D, x( A- f
//publicmethodsexposedviatheABI
//onpollsTable! d: w0 l, A+ K9 p
///@abiaction
voidversion()
{
print("YouVoteversion0.01");+ b! F2 p( V7 x* o, ?
};
///@abiaction
voidaddpoll(account_names,std::stringpollName)
{
//require_auth(s);" {( y2 X8 V' Z; g: D% r. ~, E' |* A0 {
print("Addpoll",pollName);
//updatethetabletoincludeanewpoll+ S- U* u1 q/ E% R/ D7 v5 ^# t# v
_polls.emplace(get_self(),[&](auto&p). M% ? s* G9 ?4 u! r e# C) @6 U
{( Y$ X7 U, h- {5 R- A* b: J
p.key=_polls.available_primary_key();5 ]: H7 S* ^- a" n7 ~
p.pollId=_polls.available_primary_key();) y3 A9 L0 k1 ^$ w6 K" y1 m; H7 @
p.pollName=pollName;( ~ D& I/ i6 J- X4 ^
p.pollStatus=0;
p.option="";6 {' K) D2 c. P
p.count=0;
});
};# q& O& V! K4 T$ w
///@abiaction
voidrmpoll(account_names,std::stringpollName)/ b3 F- ?$ ^/ B% N
{3 N: }1 k0 @4 C& z% P! Z% U
//require_auth(s);
print("Removepoll",pollName);
std::vectorkeysForDeletion;; P+ ~( Q7 g. I- Y* o
//finditemswhichareforthenamedpoll. D6 X5 W' x& w( L
for(auto&item:_polls)
{
if(item.pollName==pollName)
{) {; g, ?; y, Q; F8 F* y0 t8 z
keysForDeletion.push_back(item.key);
}( O7 h# m4 P# x$ S* y R
}( [: F5 B0 J/ L
//nowdeleteeachitemforthatpoll& g! e0 c% J- X* i( I6 e
for(uint64_tkey:keysForDeletion)5 e" V3 L, S- k4 q
{$ E/ a6 J% I$ ~9 M8 @
print("removefrom_polls",key);" F7 b( ]- n0 D j1 `! S# w! O" R. x
autoitr=_polls.find(key);
if(itr!=_polls.end())( ^9 [+ n7 C* j
{) Y9 U! X' N/ E
_polls.erase(itr);3 m3 p, |8 b, h3 e" a! ?- ^
}
}5 o1 R- [1 a( s: K- {9 D: O
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain
std::vectorkeysForDeletionFromVotes;
//finditemswhichareforthenamedpoll0 r$ g2 N6 r/ {4 {* |
for(auto&item:_votes)
{
if(item.pollName==pollName)9 N/ l2 [3 b! r% u- M
{
keysForDeletionFromVotes.push_back(item.key);
}9 a, }# C p5 W, {7 q
}
//nowdeleteeachitemforthatpoll+ S* u4 B' ~ i0 G- S* g8 k
for(uint64_tkey:keysForDeletionFromVotes)
{
print("removefrom_votes",key);
autoitr=_votes.find(key);
if(itr!=_votes.end())' k' n" y: i* h' P: J `9 E
{
_votes.erase(itr);+ `5 H- x: Y' c7 f& a9 D4 _ N$ X
}
}+ |" O) q1 g/ p% d
};) |0 B, S7 t/ H5 `3 o' p
///@abiaction
voidstatus(std::stringpollName)* j7 G; f8 c2 Q( o7 m
{ Q/ f: `1 O/ |+ p1 U; X
print("Changepollstatus",pollName);* L/ }1 S1 E* V5 z+ ^
std::vectorkeysForModify;( b+ |/ c9 u9 Y% r- U1 ?3 w1 {
//finditemswhichareforthenamedpoll
for(auto&item:_polls)
{6 w6 V6 X/ |9 w* N1 N$ R2 Y
if(item.pollName==pollName)
{
keysForModify.push_back(item.key);' e& j4 e6 H( B2 w/ _( W8 {8 N. C3 ^' G
}
}
//nowgeteachitemandmodifythestatus; e. A! z3 E8 E3 O- [/ [; B
for(uint64_tkey:keysForModify)# q6 u2 v$ K& d- \% A
{
print("modify_pollsstatus",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())
{
_polls.modify(itr,get_self(),[&](auto&p)
{/ Y% l( M4 O+ c& [) K
p.pollStatus=p.pollStatus+1;
});: S% w0 J& h. _) B" D0 S" l
}
}
};
///@abiaction, l& U/ V. |2 W: s; C i5 t
voidstatusreset(std::stringpollName)
{ q3 r: D- d' O |2 Y8 D
print("Resetpollstatus",pollName);! N0 p! I- J7 u1 X1 [
std::vectorkeysForModify;' j+ X, z4 V, d. p
//findallpollitems: o5 q4 x, N# f# B0 C
for(auto&item:_polls)
{ W. P9 F; I" V; u0 [ @
if(item.pollName==pollName)' {4 |$ I% H5 Q* E$ G* n$ z% ^- K
{8 M* z& i' e9 o' U% Q9 I, Z% p
keysForModify.push_back(item.key);
}
}
//updatethestatusineachpollitem
for(uint64_tkey:keysForModify), `* f/ p8 q/ i) u# S. i
{
print("modify_pollsstatus",key);
autoitr=_polls.find(key);, _6 B! r9 T! O z% M
if(itr!=_polls.end())
{6 _$ }& m% C p/ }* ~1 {7 l
_polls.modify(itr,get_self(),[&](auto&p)
{* H- z, D1 V% l2 T, m% M! i1 R
p.pollStatus=0;
});
}
}! ?4 @0 w2 i7 H1 W
};
///@abiaction8 v8 e. Q. U1 n* m
voidaddpollopt(std::stringpollName,std::stringoption)
{! P6 p4 g' b/ i7 y5 e0 T
print("Addpolloption",pollName,"option",option);- q: n( a6 A& K9 O r, ~/ \
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption
for(auto&item:_polls)
{
if(item.pollName==pollName)
{- T. p+ l0 e6 z+ \+ B0 f F
//canonlyaddifthepollisnotstartedorfinished4 v& x- ` L+ r6 t2 _
if(item.pollStatus==0)1 S7 @( _, w: n; T6 v3 n
{
_polls.emplace(get_self(),[&](auto&p)
{" E4 l, f# O4 `% S
p.key=_polls.available_primary_key();0 f) J- O) P) {& V: d
p.pollId=item.pollId;
p.pollName=item.pollName;
p.pollStatus=0;$ \& L4 q2 v) R
p.option=option;
p.count=0; H3 {* J8 T) e& p$ i% k" C
});% L2 k5 H$ j A4 s9 i
}
else
{
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");7 x$ j# M: K2 x' d1 a
}, |3 H+ B7 O% m" O5 e
break;//soyouonlyadditonce$ G9 n: Z4 y% z u% w
}8 q! J4 O) r& E, N
}' L( S0 C- O8 Y$ _. s! G
};
///@abiaction3 G2 P! ]" t; g/ s, x9 H5 m
voidrmpollopt(std::stringpollName,std::stringoption)9 W/ H0 [+ l2 t7 M. @
{! B" J$ x5 e: b
print("Removepolloption",pollName,"option",option);
std::vectorkeysForDeletion;
//findandremovethenamedpoll
for(auto&item:_polls)
{* B6 y: x2 v5 ^, g$ g; H/ w
if(item.pollName==pollName)5 u5 ^ E6 O, [6 {+ H
{+ D" v0 {! r( P' l1 H9 `# [& d7 u W
keysForDeletion.push_back(item.key);
}" l; N% ?0 Y6 R2 n+ a9 c" h, ?
}
for(uint64_tkey:keysForDeletion)( ]) ?, r/ B: x1 x. }
{
print("removefrom_polls",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())" D% [% F& l- C6 J9 s+ b
{) `3 L9 z N( @& J6 a: O' g( h, V
if(itr->option==option)% H7 f/ f, i! r) r1 q. p$ h
{. Y0 X' _' I; m. q, l
_polls.erase(itr);9 Q& n8 H3 F4 l( U
}
}
}% d0 ~, v x1 A3 m" p! {
};* [7 m% K8 X% k; U" E
///@abiaction/ K1 X: e% [: M) J1 Q X2 N
voidvote(std::stringpollName,std::stringoption,std::stringaccountName): _0 j+ {, x8 F# p
{
print("votefor",option,"inpoll",pollName,"by",accountName);
//isthepollopen
for(auto&item:_polls)0 E) U4 r; H: i3 F, M* R1 h
{
if(item.pollName==pollName)
{" T1 E. E6 m0 \ }* T4 ~
if(item.pollStatus!=1)
{9 P A) ]% Y# a7 z/ q" N$ }% z
print("Poll",pollName,"isnotopen");) X2 L( s- i, t% M5 P5 k" c
return;
}
break;//onlyneedtocheckstatusonce
}7 p' _9 U+ Z3 O& ?4 d
}
//hasaccountnamealreadyvoted?
for(auto&vote:_votes)# q: q, F/ C# t+ O' ]; R& t4 |
{7 U2 N' J) j8 F
if(vote.pollName==pollName&&vote.account==accountName)- E2 ?) |% U; k
{
print(accountName,"hasalreadyvotedinpoll",pollName);7 d! J# B4 ]9 I) S2 m" s) h- i* k
//eosio_assert(true,"AlreadyVoted");; X! h. o/ n0 N, b
return;" K6 M: g; r) W/ H0 R8 W1 Q/ A) {& h' Z! [
}2 {# J0 D9 G Y: o. b
}' ~7 ^$ S: M! ]( W' c
uint64_tpollId=99999;//getthepollIdforthe_votestable
//findthepollandtheoptionandincrementthecount o9 W N9 @, D6 K: U; ?
for(auto&item:_polls)
{: w9 ^. T2 ?- ^: ~* p& j! Z5 y
if(item.pollName==pollName&&item.option==option)6 }* w! u+ y/ n+ i
{" \$ U6 V0 X U# N& r9 R: n
pollId=item.pollId;//forrecordingvoteinthispoll
_polls.modify(item,get_self(),[&](auto&p)
{( @. _1 u$ B1 E# }
p.count=p.count+1;$ T+ P- [" y, M: b( M/ m& _2 |
});
}
}$ d4 I0 F6 }& A+ K5 E
//recordthataccountNamehasvoted
_votes.emplace(get_self(),[&](auto&pv)3 z- |$ Y- y$ f1 z; r, D4 m
{
pv.key=_votes.available_primary_key();
pv.pollId=pollId;2 S: @9 b. g- `9 ~$ Y
pv.pollName=pollName;! B6 R- l2 [5 _+ Y3 `
pv.account=accountName;
});6 s5 G" e3 `- m4 D0 P7 H
};' c% d' r4 u6 U
private:
//createthemultiindextablestostorethedata
///@abitable
structpoll
{
uint64_tkey;//primarykey
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption, v% U: \! J2 C# t1 l# B: q. `
std::stringpollName;//nameofpoll2 L& o! _( M/ T/ \7 i: Q
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished9 T1 K/ v) e. Y7 D( {
std::stringoption;//theitemyoucanvotefor
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable.% M4 M+ r- T' Z5 E
uint64_tprimary_key()const{returnkey;}6 b# n$ j7 n k& ^
uint64_tby_pollId()const{returnpollId;}
};# {' e, ?+ o( T# p, | x/ q
typedefeosio::multi_index>>pollstable;% e" q0 l& R: {, D+ U
///@abitable6 c' I) U. O4 z( \7 y, l5 r
structpollvotes$ b8 {5 |9 P% G5 Y- Q
{( e ~/ K2 ~3 p8 r1 l' y" H
uint64_tkey;
uint64_tpollId;
std::stringpollName;//nameofpoll4 K/ f& w4 y0 {: W, Q2 s8 k% {9 q
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>1! x q9 m( G/ O- t
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}
};
typedefeosio::multi_index>>votes;; }0 A' p& P+ r* Q) p+ s4 b
//localinstancesofthemultiindexes% _7 h: I7 ]& i; v
pollstable_polls;
votes_votes;
};7 ~+ P" p$ t& A, T: [
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人