EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
179
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。1 a+ o0 c4 I/ K8 ]
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。
1.创建一个结构* g% d) V6 k0 Z6 _% C
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。2 M, V+ J5 c+ e2 b
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。( u2 M9 L" g6 g) N
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。
///@abitable
structmystruct" m7 W; T4 A& g# e* u
{
uint64_tkey;: }2 C5 p. J& Q0 a
uint64_tsecondid;. b' E% E# u7 _7 v. i* G" o$ x! R
std::stringname;
std::stringaccount;$ m! X; c. r2 l- _2 f2 W
uint64_tprimary_key()const{returnkey;}//getterforprimarykey
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey
};6 Q. }: h$ j, ~
这里还要注意两件事:
1.注释:
///@abitable
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。$ y9 `, F4 Y- |0 H6 a' y8 V/ o+ `' Z
2.结构名称少于12个字符,而且所有的字符都要小写字母。+ s% y3 j/ U" E
2.多索引表和定义索引
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:2 H5 H3 H# M7 i& c' B8 ~
typedefeosio::multi_indexdatastore;8 V5 W/ T: W2 Q2 R% P/ B
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。& i' P5 H2 b1 K+ {0 k/ |
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:
typedefeosio::multi_index>>datastore;9 J7 D) O5 f; P6 f. g% O
注意:, b+ h. e5 ?) F1 [: g
indexed_by>
参数:
字段的名称转换为整数,N(secondid): d' \4 V5 [8 I7 {9 @. }
一个用户定义的密钥调用接口,const_mem_fun
来看看有三个索引的情况。3 B* q3 v! u0 }
///@abitable
structmystruct
{+ ~- J r7 B% c! }! o8 H& \4 m
uint64_tkey;, R2 [' [2 l2 g5 Q2 ^4 e
uint64_tsecondid;
uint64_tanotherid;
std::stringname;
std::stringaccount;
uint64_tprimary_key()const{returnkey;}. \' V& c' N* j. Z* g
uint64_tby_id()const{returnsecondid;}
uint64_tby_anotherid()const{returnanotherid;}
};" G% v" J, n9 o) F
typedefeosio::multi_index>,indexed_by>>datastore;# j( C: k( o' X7 G% N
更多的就不列了。
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。+ W) h+ Q& R, _
3.创建定义类型的局部变量
//localinstancesofthemultiindexes
pollstable_polls;3 d- o7 D9 d2 U
votes_votes;
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。
#include2 H. `2 O' a- U! O# _. y
usingnamespaceeosio;
classyouvote:publiccontract{
public:
youvote(account_names):contract(s),_polls(s,s),_votes(s,s)- V) F# x: I5 ]+ X: ^* L) t
{}
//publicmethodsexposedviatheABI. }2 `% w$ V6 Y
//onpollsTable
///@abiaction
voidversion()
{! a2 l3 ?4 L$ ]: E* L- M3 a
print("YouVoteversion0.01");
};
///@abiaction
voidaddpoll(account_names,std::stringpollName)2 [; B* W# d& I2 e! q
{
//require_auth(s);
print("Addpoll",pollName);
//updatethetabletoincludeanewpoll
_polls.emplace(get_self(),[&](auto&p)
{
p.key=_polls.available_primary_key();
p.pollId=_polls.available_primary_key();9 S) h2 S h8 y0 b. i! ^, _
p.pollName=pollName;
p.pollStatus=0;% e+ A6 `/ S* P, S( P. Q* S0 |* N$ _
p.option="";$ I2 B% [: _' @0 e2 X
p.count=0;- r: k: }( x+ x9 _2 ?8 ]# A
});+ m, R' `! b6 ^4 y" x
};$ T6 }) ?4 X' k$ B
///@abiaction- N. ]+ A# G" G
voidrmpoll(account_names,std::stringpollName)! |5 }- g- N2 S" T
{( |& s' d& m) E' T* ?
//require_auth(s);
print("Removepoll",pollName);
std::vectorkeysForDeletion;3 o6 ^* b( m9 k2 X( g) K/ B7 P/ G
//finditemswhichareforthenamedpoll
for(auto&item:_polls)/ N0 X# u1 ~) R1 x# s" i: @$ Y# C9 L
{3 u. y P; Y F
if(item.pollName==pollName)
{
keysForDeletion.push_back(item.key);
}8 s7 A- o6 q T! v0 k
}3 q2 f, `: O! T) V: w
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletion)
{
print("removefrom_polls",key);5 H N: c) ~) ~3 F8 w
autoitr=_polls.find(key);2 E0 O% x9 u- r! A, i! O( J
if(itr!=_polls.end())) L( d8 F* f) P4 w% U F! f8 P
{
_polls.erase(itr);1 D- W9 o2 }* J
}2 p5 O, m! o" K+ x2 J
}2 Q( o/ h; I0 e# ]" f
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain
std::vectorkeysForDeletionFromVotes;
//finditemswhichareforthenamedpoll
for(auto&item:_votes)
{
if(item.pollName==pollName)
{
keysForDeletionFromVotes.push_back(item.key);; ]' U$ L8 [( M
}* g; [- X' ]) t1 F+ X
}
//nowdeleteeachitemforthatpoll8 W8 n3 G6 e: K$ N C
for(uint64_tkey:keysForDeletionFromVotes)
{
print("removefrom_votes",key);5 e- @) ]" h" A' C" W2 h/ [+ i* [
autoitr=_votes.find(key);3 m' u( `- g. g
if(itr!=_votes.end())
{4 M# B8 s* u4 K1 p
_votes.erase(itr);
}# B0 i7 A8 a# i. I
}
};6 c+ z; B" P6 |
///@abiaction
voidstatus(std::stringpollName)5 a# E, j- c) w* d: r
{
print("Changepollstatus",pollName);
std::vectorkeysForModify;9 m) J0 n3 g$ X; k# J: m
//finditemswhichareforthenamedpoll, }& _0 P. ]% \; U; W
for(auto&item:_polls)
{( v" { W7 g' m1 _
if(item.pollName==pollName)5 V; x% V" p9 b8 q
{
keysForModify.push_back(item.key);# O2 m" p2 X6 u, |2 V, T
}
}
//nowgeteachitemandmodifythestatus
for(uint64_tkey:keysForModify)" i+ m0 s/ q: M$ m, |7 M. n2 X4 T0 g
{
print("modify_pollsstatus",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())' L9 c( A; p y! |8 |3 H% M
{
_polls.modify(itr,get_self(),[&](auto&p)- ~) L8 k, s6 s8 G! _
{
p.pollStatus=p.pollStatus+1;
});8 y& x) e! e8 J e( }
}6 x3 B p0 s7 H' J7 I" V V
}
};! f8 J: ] d, H) C% N" n5 ]
///@abiaction
voidstatusreset(std::stringpollName)4 A/ W* M! w$ S/ z% E
{8 L1 E; P: h* U
print("Resetpollstatus",pollName);
std::vectorkeysForModify;) a" g. x* ^" U# B! m
//findallpollitems
for(auto&item:_polls)
{
if(item.pollName==pollName)3 f0 c! g/ a9 }. w b# o; I9 \
{
keysForModify.push_back(item.key);
}
}! O* b8 @5 ^- k) d8 r4 S
//updatethestatusineachpollitem& Z+ y( D* g/ j( T4 l1 D
for(uint64_tkey:keysForModify): y/ T6 s; N. A
{7 Q ~, h, N- B- x5 }5 l2 P. n: w
print("modify_pollsstatus",key);
autoitr=_polls.find(key);( X5 g% S" H9 h( k) T
if(itr!=_polls.end())& Y( d/ S c' c2 ~
{
_polls.modify(itr,get_self(),[&](auto&p)3 b m, \$ a) u
{! Y0 X- V) ~9 M6 M) ]8 E4 r
p.pollStatus=0;
});' V$ _2 y& i M N% n- p
}
}
};* l4 O4 r) o6 t- e# Y) g& t+ ]4 @" F
///@abiaction$ A1 P2 f& O! m- d$ T
voidaddpollopt(std::stringpollName,std::stringoption)7 F& @* U2 t6 A4 B0 i, H3 D
{
print("Addpolloption",pollName,"option",option);+ p# |& b$ \% N! s
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption. @, l' N+ G. _
for(auto&item:_polls)
{( B/ e- Y' s/ r' m% i: J
if(item.pollName==pollName)) r0 n. E/ J" @8 @& {5 h4 o
{3 W- E! V& h1 Y
//canonlyaddifthepollisnotstartedorfinished
if(item.pollStatus==0)' G- G- z( Q9 {5 k! X% T1 C
{. N; c' K* P: B2 p0 J7 | N6 \
_polls.emplace(get_self(),[&](auto&p)
{, E2 X; {& ?1 ~* g) ?
p.key=_polls.available_primary_key();
p.pollId=item.pollId;& d3 z, B, o3 P0 `3 T @0 U
p.pollName=item.pollName;
p.pollStatus=0;
p.option=option;" f3 s* S q2 M9 D/ l" @5 A! b
p.count=0;5 G3 X* A8 z' \- j/ H) v
});* @8 A3 R3 w+ w1 @+ }' d
}
else
{
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");
}
break;//soyouonlyadditonce
}
}+ l0 l8 b. C: |, Z
};: J- [4 V4 T) _
///@abiaction
voidrmpollopt(std::stringpollName,std::stringoption)! m. G5 p; g7 {8 t" C4 m# i
{
print("Removepolloption",pollName,"option",option);
std::vectorkeysForDeletion;
//findandremovethenamedpoll
for(auto&item:_polls)
{
if(item.pollName==pollName)
{4 c4 R6 a; j8 F" t P6 E8 u S
keysForDeletion.push_back(item.key);$ }1 k" ?* h( C \: V' c+ O
}
}
for(uint64_tkey:keysForDeletion)4 _$ e& J2 W# n
{
print("removefrom_polls",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())
{
if(itr->option==option)( N+ |0 k, @' v' U% C; @
{; s8 b1 W, [' o2 b
_polls.erase(itr);% Q- ~+ {: V4 R+ r& c/ f3 B
}1 K5 b" h) `" r0 q3 Q# H; r) M3 S
}( `9 x7 x# `! w) S# q6 d* D# `
}+ ~+ t& ~6 P% |6 x& a( k! W
};
///@abiaction* y" t/ M. a' [
voidvote(std::stringpollName,std::stringoption,std::stringaccountName)
{
print("votefor",option,"inpoll",pollName,"by",accountName);
//isthepollopen' @' P8 j+ n- q5 Z) n! M5 Z/ B$ p2 o( p
for(auto&item:_polls)5 o) o, I L' m4 c+ n8 b$ n% d) |
{
if(item.pollName==pollName)' `6 _% L) x, t9 d s- G2 i9 _
{
if(item.pollStatus!=1)8 T& O; @$ J L% |+ S! F
{% N7 j ? o' b3 y \% ]" [; ?
print("Poll",pollName,"isnotopen");
return;
}
break;//onlyneedtocheckstatusonce4 N1 [' l: q" b
}
}2 d+ T8 ?8 z' \- L: k
//hasaccountnamealreadyvoted?
for(auto&vote:_votes)
{3 u# G( P0 W) Q! }+ Q! Q
if(vote.pollName==pollName&&vote.account==accountName)( x% I: k* V* ?
{, `& b' O- @. ? [" y' E: a
print(accountName,"hasalreadyvotedinpoll",pollName);3 Q) Y% D) N- f4 ~; {( W5 j
//eosio_assert(true,"AlreadyVoted");- L( @" O+ W4 P
return;& `# X3 B @7 g/ l+ U
}6 [7 |+ m Q! x/ B2 W" T
}1 f3 P; n# s8 ]8 r' M9 }
uint64_tpollId=99999;//getthepollIdforthe_votestable+ b, ~+ E i2 M! P
//findthepollandtheoptionandincrementthecount" S$ `* X" [# _& Q* D* n: G
for(auto&item:_polls)* Z5 M6 ^' G* D* j* K% O- Z: |1 c, p/ o
{: C% o2 G. j* N) u: v- r% `; E; N _# C
if(item.pollName==pollName&&item.option==option)
{! ]2 m q9 W6 i2 F
pollId=item.pollId;//forrecordingvoteinthispoll' q3 G9 J" {3 H
_polls.modify(item,get_self(),[&](auto&p)
{$ G+ U+ W' u3 ]8 m: q
p.count=p.count+1;. {* J* H0 |; J- C, T1 P3 A
});
}/ c* ?; Z! k% y6 Z( [
}' T$ k% V" o& m: T) t9 I/ [
//recordthataccountNamehasvoted
_votes.emplace(get_self(),[&](auto&pv)
{
pv.key=_votes.available_primary_key();- _; G+ J( A0 m! E' p, f
pv.pollId=pollId;2 T4 S7 {; j o! a7 i' {
pv.pollName=pollName;
pv.account=accountName;* `/ o% V9 {2 N, j
});
};
private:
//createthemultiindextablestostorethedata( G+ m# Y M8 ?6 C
///@abitable3 A+ ~8 \9 y3 y+ B# W0 e9 `
structpoll7 l, G" R6 Y6 _# U% L
{) n3 d( u) C! Y" f( \
uint64_tkey;//primarykey
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption
std::stringpollName;//nameofpoll- O1 m& k4 R3 p; _. f
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished5 X& B" w+ _, V7 O4 n* f
std::stringoption;//theitemyoucanvotefor
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable.
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}% M# P! ]4 N! \8 Z, B/ k& b
};+ j; ]8 X- d3 T3 {7 j
typedefeosio::multi_index>>pollstable;3 G: S! U9 ?' C/ u* p7 Y: d
///@abitable# _8 }& x$ [3 z% a" w
structpollvotes3 T+ B& V: s p
{
uint64_tkey;
uint64_tpollId;$ d$ v; g7 }: h4 x
std::stringpollName;//nameofpoll
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>1- a3 y9 Q6 D6 j* }& u
uint64_tprimary_key()const{returnkey;}+ q1 |) Y5 H$ ?3 S
uint64_tby_pollId()const{returnpollId;}
};% V1 x/ N! @. ?2 A
typedefeosio::multi_index>>votes;
//localinstancesofthemultiindexes9 u& {# O J8 u6 B
pollstable_polls;7 C' [/ {, }; t# A3 \
votes_votes;
};( l9 I% W" v) K9 [- ^
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人