EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
114
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。# Q( n2 a4 l7 I9 \" `7 ~
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。 h, I+ H _% z* t' m, }% g! H
1.创建一个结构; ?8 ]9 O' [# {9 J1 a) \
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。+ V* r* M' f( j$ m! F8 A/ m' z8 X
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。( \3 X1 f3 e8 i% K# a8 y
///@abitable3 \# U' M0 ^4 N1 n
structmystruct
{
uint64_tkey;
uint64_tsecondid;" `$ h5 T M& {- B
std::stringname;
std::stringaccount;
uint64_tprimary_key()const{returnkey;}//getterforprimarykey& ]8 v. h4 {4 [& e. q" e( N
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey
};( |" U7 V' n. K# Z$ P
这里还要注意两件事:
1.注释:
///@abitable* @0 K& Y: T* G: u
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。 R+ k! o" ^0 m( ^# ?
2.结构名称少于12个字符,而且所有的字符都要小写字母。7 O7 s2 q h3 _& b3 n" f: e
2.多索引表和定义索引
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:3 [, ^) v8 p) _* {" L) u3 |% a- O/ {
typedefeosio::multi_indexdatastore;8 X; z/ z7 ^0 k9 m/ P
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:0 B! P% Z( C- a7 j2 K6 Y# ~1 r) x
typedefeosio::multi_index>>datastore;* e$ {' j4 x% w
注意:
indexed_by>
参数:$ R. t, Y$ ^( n } d) g& q
字段的名称转换为整数,N(secondid)
一个用户定义的密钥调用接口,const_mem_fun* k% W( `, @" Q! G
来看看有三个索引的情况。
///@abitable
structmystruct
{* x" U. d1 H/ u3 s$ f( v
uint64_tkey;
uint64_tsecondid;/ R7 [6 v+ R' t) W
uint64_tanotherid;9 X% n2 i5 f, ?3 Y6 A2 o
std::stringname;2 L0 t% ]0 t1 [8 C; G# z
std::stringaccount;
uint64_tprimary_key()const{returnkey;}8 e. H& ^9 ]6 V8 B, r! X
uint64_tby_id()const{returnsecondid;}9 |1 p6 v0 o8 `6 m# I% X- n
uint64_tby_anotherid()const{returnanotherid;}
};
typedefeosio::multi_index>,indexed_by>>datastore;
更多的就不列了。
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。
3.创建定义类型的局部变量
//localinstancesofthemultiindexes
pollstable_polls;: s1 ~. w1 j5 ?7 Y$ |3 |* F/ G$ `( p
votes_votes;
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。. I8 q& D {0 a8 P9 Z+ g
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。 _1 }% Y2 I( ?! H) ?: @* W
#include
usingnamespaceeosio;7 u0 L9 v3 v: _9 h* a" g
classyouvote:publiccontract{
public:" w: {6 e9 }) T9 q2 b
youvote(account_names):contract(s),_polls(s,s),_votes(s,s), R8 P4 {6 D0 l m
{}
//publicmethodsexposedviatheABI4 z- @& h7 E1 `9 \$ c8 f5 R
//onpollsTable6 a7 M: i' q' N1 Z; B# X5 [
///@abiaction
voidversion(). y$ c: I) B# [* m
{ Z0 F, a! K, q! M0 r7 L% z2 r
print("YouVoteversion0.01");
};
///@abiaction6 |/ s5 H1 ~6 ~+ m+ a
voidaddpoll(account_names,std::stringpollName)
{
//require_auth(s);
print("Addpoll",pollName);
//updatethetabletoincludeanewpoll0 |9 i, G5 n n/ U9 N. \/ W
_polls.emplace(get_self(),[&](auto&p)
{
p.key=_polls.available_primary_key();9 K6 p) e1 {; E, I) O* b' U
p.pollId=_polls.available_primary_key();5 A9 Z ~$ _, ]# V9 m- I
p.pollName=pollName;. b$ N! @* c, ?+ a
p.pollStatus=0;
p.option="";: _/ ]$ Z+ ~ ] `+ d& x* {2 L3 }
p.count=0;
});( { v" D }, [' _. J
};
///@abiaction
voidrmpoll(account_names,std::stringpollName)
{
//require_auth(s);
print("Removepoll",pollName);
std::vectorkeysForDeletion;
//finditemswhichareforthenamedpoll Z- U1 S; E9 C# \$ h$ c
for(auto&item:_polls)9 K9 y n' |6 r! U1 h! J: a
{, J+ Z0 e0 ~. k9 k
if(item.pollName==pollName)
{
keysForDeletion.push_back(item.key);
}9 n# I6 u! a) F* F2 p/ a% b' I
}3 }7 N0 [7 v% K3 v. s0 p
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletion)( R: \/ g2 B) U
{* R) m x) X- Q( @. [, J, C
print("removefrom_polls",key);
autoitr=_polls.find(key);2 W, i& L/ k* r1 T
if(itr!=_polls.end())
{
_polls.erase(itr);, M2 |7 g2 Z0 s S2 o- q3 ~( g* P/ ?) Z
}2 s0 W, f: V5 R" s% E: A* t! \
}
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain
std::vectorkeysForDeletionFromVotes;
//finditemswhichareforthenamedpoll5 q5 B7 \2 Y2 T) \7 V
for(auto&item:_votes)
{5 l, z9 }+ ~6 {3 Y# w
if(item.pollName==pollName)
{
keysForDeletionFromVotes.push_back(item.key);6 K5 J, a+ L# S( k! ?& q9 }5 `
}
}
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletionFromVotes)
{
print("removefrom_votes",key);# v' A8 T" R7 ]3 O2 E. y
autoitr=_votes.find(key);$ z# t0 H8 B- v7 P
if(itr!=_votes.end())6 I( N }. Z% U! o8 c$ x L
{
_votes.erase(itr);
}
}
};
///@abiaction
voidstatus(std::stringpollName)
{, }( ?8 l R" k. f0 P* ^2 g% W
print("Changepollstatus",pollName);1 T/ _- ^) p; f: u9 C
std::vectorkeysForModify;
//finditemswhichareforthenamedpoll
for(auto&item:_polls): N! D' L' y/ F+ B1 d1 S5 M
{. G5 n6 F3 k1 p4 H4 L
if(item.pollName==pollName)! y! G1 J* }( v9 m
{
keysForModify.push_back(item.key);" a7 j$ l8 ]! v$ `* T
}) `, A+ O7 ?; s6 ~0 N
}3 {7 \/ D. a2 x D
//nowgeteachitemandmodifythestatus
for(uint64_tkey:keysForModify)
{
print("modify_pollsstatus",key);' d& ^- W& O' R; A2 F% p$ {' ?
autoitr=_polls.find(key);
if(itr!=_polls.end())
{
_polls.modify(itr,get_self(),[&](auto&p)
{
p.pollStatus=p.pollStatus+1;
});+ V: t9 e* Y- v4 U \( @4 P
}
}& O8 M& J! y. f$ M5 N& n
};
///@abiaction9 I4 h: Q6 y/ ~1 c; l5 V2 n9 p
voidstatusreset(std::stringpollName)9 {7 x# h$ z! m( ^
{
print("Resetpollstatus",pollName);
std::vectorkeysForModify;$ U- z4 `: N( O4 S
//findallpollitems
for(auto&item:_polls)
{% o n% y) X; x) z5 U' N/ {
if(item.pollName==pollName)
{
keysForModify.push_back(item.key);, I% L0 ^6 b* e# i
}
}
//updatethestatusineachpollitem
for(uint64_tkey:keysForModify), ~5 E9 Z8 D: a6 m* e
{! W% T x& r8 u; n9 C3 N: C; s- H# B. b
print("modify_pollsstatus",key);4 H, j: Q1 z+ P j. h
autoitr=_polls.find(key);
if(itr!=_polls.end())' `1 ^ Z9 q: z9 C
{
_polls.modify(itr,get_self(),[&](auto&p)
{/ ~9 P2 P; k2 [- V/ C* m. G& N
p.pollStatus=0;& F4 J, G/ k( o: {# h4 G. B. K
});
}& ~) w) [; P; e* S( v+ |
}
};0 C: y4 `* T* q8 r8 t
///@abiaction
voidaddpollopt(std::stringpollName,std::stringoption)
{' N; G) D" ]7 l. H
print("Addpolloption",pollName,"option",option);* Y8 [- b' f- m
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption
for(auto&item:_polls)
{( J/ m. T5 w6 L1 t
if(item.pollName==pollName)
{
//canonlyaddifthepollisnotstartedorfinished
if(item.pollStatus==0)
{9 t+ n; K$ z, s0 o* T! W
_polls.emplace(get_self(),[&](auto&p) V9 T9 X1 \9 s: X& F
{: V) F9 ]' d5 u0 Z- N
p.key=_polls.available_primary_key();
p.pollId=item.pollId;
p.pollName=item.pollName;' J' I* z- s/ P! u+ I2 j5 |6 k* ?& ~
p.pollStatus=0;3 T0 i7 W! a& e* x$ X. \6 H
p.option=option;
p.count=0;' |4 G8 L. E; y7 M- s+ \9 d
});
}
else# A0 z$ Z' w( O* x. b! Y6 q+ o( }
{
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");: G+ Y4 ^3 s$ O0 D
}
break;//soyouonlyadditonce8 Y ]: d/ K3 o! \7 _ y
}
}3 N+ F! T* J, o$ Q, D' G
};9 ^" O9 B* l* Z
///@abiaction
voidrmpollopt(std::stringpollName,std::stringoption)5 q! a- [8 h6 H, P: u
{+ m' x' L+ i+ U3 J
print("Removepolloption",pollName,"option",option);6 u* a$ c9 ~2 g. Y0 [: u
std::vectorkeysForDeletion;6 E/ ~' @7 F: r& W- C: S: f
//findandremovethenamedpoll4 U' R( I4 H7 r8 c
for(auto&item:_polls)
{
if(item.pollName==pollName)
{: J/ q6 W3 W' u! i j' C, O
keysForDeletion.push_back(item.key);
}& s- U9 n1 o# m- x, k- {
}6 m" h4 N4 p5 K# N6 ^
for(uint64_tkey:keysForDeletion)
{! b) ?+ ^% Y. _! o- p+ c
print("removefrom_polls",key);
autoitr=_polls.find(key);
if(itr!=_polls.end()). w7 c3 |# {- o. c, q, M# N; H4 u5 Z
{
if(itr->option==option)6 m! ^" x" u# d* K6 \. S) J8 T3 b
{
_polls.erase(itr);
}
}8 I1 L7 i; e$ j1 L. J
}
};
///@abiaction
voidvote(std::stringpollName,std::stringoption,std::stringaccountName)
{
print("votefor",option,"inpoll",pollName,"by",accountName);/ h B* z3 e) C$ n
//isthepollopen: d: N+ \0 S# F/ Q9 K" ]( y6 R0 [
for(auto&item:_polls); a# Y% q1 d' {5 `# f
{
if(item.pollName==pollName)
{4 v7 q* M3 c) S% S9 @
if(item.pollStatus!=1)
{
print("Poll",pollName,"isnotopen");
return;0 i( V6 |6 {9 r' n* Y2 K. c
}
break;//onlyneedtocheckstatusonce
}' v) ?! B3 }) d9 b
}% J3 ~1 ~$ y. s5 F: l3 p% W
//hasaccountnamealreadyvoted?& Q7 \' P# s \8 x( y; j
for(auto&vote:_votes)9 [8 t4 e/ {8 N- v j) I3 H
{. w3 {9 @5 T# y4 ?
if(vote.pollName==pollName&&vote.account==accountName)) t' p4 @, [5 D* t- A, E
{
print(accountName,"hasalreadyvotedinpoll",pollName);* r( y$ M4 m: E
//eosio_assert(true,"AlreadyVoted");
return;
}
}
uint64_tpollId=99999;//getthepollIdforthe_votestable0 N: J3 N# f+ A( _) T3 |2 m
//findthepollandtheoptionandincrementthecount; f0 _7 Q# c6 I, r) p/ `; S
for(auto&item:_polls)
{ [6 \* x+ F9 B/ \/ Z) {) w
if(item.pollName==pollName&&item.option==option)8 m- `' z' i. ?* Y/ R% x
{
pollId=item.pollId;//forrecordingvoteinthispoll4 g* s, O; A" v5 V) i; |
_polls.modify(item,get_self(),[&](auto&p)+ H+ W$ X& _! `
{
p.count=p.count+1;) G3 m: ?* s) h, a3 e' A
});; @& U, I% X/ b' }0 d1 a3 U' V
}
}
//recordthataccountNamehasvoted' t% M" q% J8 f0 z I d
_votes.emplace(get_self(),[&](auto&pv)
{
pv.key=_votes.available_primary_key(); l& s4 y$ X: h- T1 D
pv.pollId=pollId;) L& {& z; k! i7 {' x' k8 ^
pv.pollName=pollName;
pv.account=accountName;- f2 |4 \6 W e1 u# K# ~
});
};
private:
//createthemultiindextablestostorethedata
///@abitable$ s1 @ N \. {) `, ^: ~7 p
structpoll
{
uint64_tkey;//primarykey) ^6 m0 ^9 S2 W! U
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption
std::stringpollName;//nameofpoll1 C: W& Y. _5 O2 S' Q
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished4 P: t x6 ?5 t* v5 p2 a
std::stringoption;//theitemyoucanvotefor$ K9 W( }8 K/ Y6 c+ D2 v4 ?4 a
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable.9 F- z+ a; Q; v8 L G1 a, B+ w
uint64_tprimary_key()const{returnkey;}/ E/ T. l2 H( b5 |
uint64_tby_pollId()const{returnpollId;}& Z; r% e9 e/ V9 _/ i! W# g4 k
};
typedefeosio::multi_index>>pollstable;
///@abitable
structpollvotes
{
uint64_tkey;; b% J0 \( |( c9 @; N) o+ N
uint64_tpollId;3 w( C6 Q* y B- s
std::stringpollName;//nameofpoll
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>10 E: N( u! z! |
uint64_tprimary_key()const{returnkey;}7 Z& N' u- m' f% |
uint64_tby_pollId()const{returnpollId;}
};. i( c- i; k+ a" W
typedefeosio::multi_index>>votes;, _, P/ [% b: r+ J
//localinstancesofthemultiindexes+ R ?$ M4 y3 R! |" F$ g
pollstable_polls;- h% {2 W" \4 h
votes_votes;5 P8 d: u9 n+ s) B, {- q6 {" M0 V% Z
};
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))+ y. m% u0 w$ X4 F! V
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人