EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
111
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。' ^4 e |9 k/ L) D3 J8 l+ I) s
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。
1.创建一个结构( g1 [. e6 t' F2 O) y5 p0 u; b
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。
///@abitable
structmystruct- b' m+ l# m# y
{
uint64_tkey;
uint64_tsecondid;* K" q1 {8 m( l# q2 _ e
std::stringname;0 Z! V5 E' r" s2 f% U; s
std::stringaccount;* n/ ?) H' `* f4 c! i& E0 O
uint64_tprimary_key()const{returnkey;}//getterforprimarykey3 ~" i/ m3 e: R( ]+ N9 |
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey( x6 a# t1 P3 u, k* o, X' e8 `
};
这里还要注意两件事:, h) D+ o5 y: ^$ y
1.注释:
///@abitable
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。2 V* N/ _ Z* h+ R) ^
2.结构名称少于12个字符,而且所有的字符都要小写字母。
2.多索引表和定义索引
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:
typedefeosio::multi_indexdatastore;
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。' v# R) [& [. C9 L2 W7 q6 j
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:
typedefeosio::multi_index>>datastore;
注意:# ~( L7 n( [# P- u" J0 a8 G$ a
indexed_by>1 c8 c$ A1 B, B3 T" |4 R, T
参数:6 G( I# B/ B0 `, I* \9 v
字段的名称转换为整数,N(secondid)' V) `$ ]0 t: n* T) n
一个用户定义的密钥调用接口,const_mem_fun9 z+ v, J3 k, c5 y+ y# J+ T' ?
来看看有三个索引的情况。
///@abitable2 T: U( g( F- b6 o
structmystruct
{
uint64_tkey;
uint64_tsecondid; d2 S! ?1 W/ v7 r" w
uint64_tanotherid;- J1 K% ?. H5 x- f2 ? W9 K4 D
std::stringname;- G( m, }, ]2 d3 L
std::stringaccount;
uint64_tprimary_key()const{returnkey;}
uint64_tby_id()const{returnsecondid;}, J* x4 k9 o! @! @% U& n
uint64_tby_anotherid()const{returnanotherid;}
};/ J# h! M$ E! t1 n. p7 l
typedefeosio::multi_index>,indexed_by>>datastore;
更多的就不列了。
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。6 ~, C \# |4 A. N d
3.创建定义类型的局部变量. j* S$ q( |2 R
//localinstancesofthemultiindexes! H+ I7 N4 m' E: t5 f1 y# C% Y
pollstable_polls;3 A3 U1 F4 f( }# a
votes_votes;. z; D* k8 L( X9 s$ ^, |& D* U/ m
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。7 b7 g# o4 e) C0 B4 \$ t
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。
#include3 u. _% W; z" E( P
usingnamespaceeosio;
classyouvote:publiccontract{
public:0 m& r* o1 z# {; Z, c; ~# C
youvote(account_names):contract(s),_polls(s,s),_votes(s,s)
{}
//publicmethodsexposedviatheABI& c- k) I( ]* L' b8 [
//onpollsTable
///@abiaction
voidversion()
{; E; ~3 f2 S7 A- N/ C; @
print("YouVoteversion0.01");8 X$ r# X5 H; E" ]. d0 u
};0 x- k) _4 D6 ^
///@abiaction) w0 }5 s7 V7 D( M v+ V
voidaddpoll(account_names,std::stringpollName)- v5 e+ ]5 L* r; U. i0 O3 I
{$ r5 ?4 g, d" \" F) H/ X
//require_auth(s);! ~" H' N/ S; q$ ?
print("Addpoll",pollName);
//updatethetabletoincludeanewpoll: i9 ~* G5 `' g
_polls.emplace(get_self(),[&](auto&p)
{
p.key=_polls.available_primary_key();
p.pollId=_polls.available_primary_key();4 Q+ [5 V. s8 r5 q; S( A; x2 l4 g
p.pollName=pollName;" T, b* |. ?4 V. m" g, g* o
p.pollStatus=0;1 ~- C- I: R( C9 ?; S/ s
p.option="";
p.count=0;0 s( L `7 I5 o2 e
});8 u9 B% Y5 f, A6 ?5 S
};
///@abiaction
voidrmpoll(account_names,std::stringpollName)2 f7 F# p# j' C$ L! G4 R0 V
{
//require_auth(s);) R. }$ Y1 |- q, L. {0 M: ?
print("Removepoll",pollName);
std::vectorkeysForDeletion;
//finditemswhichareforthenamedpoll
for(auto&item:_polls)
{7 S. ^7 v9 n2 r$ C# M% X
if(item.pollName==pollName)& g$ f8 j7 Y+ O% K" C7 z0 K. ^
{' o* |" d% A6 H; G; W/ ^
keysForDeletion.push_back(item.key);' P. n6 c H7 l% {. I' e
}
} a4 S7 O- ?( X8 J
//nowdeleteeachitemforthatpoll# A/ S$ @" `' H* G8 G
for(uint64_tkey:keysForDeletion)
{
print("removefrom_polls",key);0 }- X) o9 Q( d/ f4 H* J
autoitr=_polls.find(key);
if(itr!=_polls.end())
{/ k& G- |/ q! M T5 D( Y3 L+ A
_polls.erase(itr);
}! A* W- @, @. y3 [ b
}
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain7 D' `& k; `5 C5 y8 G; r
std::vectorkeysForDeletionFromVotes;' n( J( B# |, X9 \8 q8 Z
//finditemswhichareforthenamedpoll) A( r* e9 o' s) d) c3 m) A
for(auto&item:_votes)# o7 @2 V3 m) X7 C( L
{
if(item.pollName==pollName) s4 {) R) b; p
{
keysForDeletionFromVotes.push_back(item.key);4 W+ W6 h, N, d8 f6 k j$ U
}4 d, Q5 l7 P/ t% t
}" J: r. j( W0 q" D' U* a3 ]
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletionFromVotes)
{% }+ n2 s' s) W( ~
print("removefrom_votes",key);
autoitr=_votes.find(key);3 _% }- s( O$ ^! M% b
if(itr!=_votes.end())
{+ g: B, u. I! j0 n) f
_votes.erase(itr);
}$ a% }4 I# t" G4 G
}
};
///@abiaction
voidstatus(std::stringpollName)
{( K: U: t! l9 B2 B1 I2 k' h0 k v
print("Changepollstatus",pollName);
std::vectorkeysForModify;; c- w! E+ _6 T
//finditemswhichareforthenamedpoll
for(auto&item:_polls)
{. x% L; U/ V# _+ Y- k
if(item.pollName==pollName)" K: J* \& x7 ?& o
{4 q9 }# ?: u0 E
keysForModify.push_back(item.key);6 t5 k. T6 z7 ~% w( L
}+ a$ w/ u! X- s( t# X( S
}# o0 W0 w5 b0 K1 Z, E
//nowgeteachitemandmodifythestatus; K& p! k5 s4 ^" k- p
for(uint64_tkey:keysForModify)
{1 f7 x9 X7 M& g
print("modify_pollsstatus",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())0 n$ p5 p: |0 p" w
{
_polls.modify(itr,get_self(),[&](auto&p)
{, d1 v+ O# f) m7 N( u
p.pollStatus=p.pollStatus+1;
});
}
}
};
///@abiaction" Z1 g5 L& O5 N7 F- {
voidstatusreset(std::stringpollName)
{
print("Resetpollstatus",pollName);
std::vectorkeysForModify;
//findallpollitems" Z4 V' x: I9 a
for(auto&item:_polls)- h( b s0 G( G. V; A
{
if(item.pollName==pollName): p/ D1 Q# E" c# I+ I6 F8 T# R% h
{/ I+ _, S4 v9 ^# s" G1 b$ _8 X
keysForModify.push_back(item.key);: i3 j6 M0 }: T* M1 H0 f8 l
}
}9 h- \1 m! g* f$ E- s
//updatethestatusineachpollitem$ H- N4 @6 p: `2 o" E
for(uint64_tkey:keysForModify)
{5 z! D3 J, q6 o- r' p
print("modify_pollsstatus",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())( P7 ?8 Z* d \% J$ [4 h& v
{
_polls.modify(itr,get_self(),[&](auto&p)
{* G% ?# d/ M& `- ~1 o; w) G
p.pollStatus=0;
});
}3 G Q% \6 ]% i* }( I
}
};
///@abiaction
voidaddpollopt(std::stringpollName,std::stringoption)* ~$ r% B* _2 d3 b* a0 J) A
{
print("Addpolloption",pollName,"option",option);0 d' k/ {7 j: i! w; G
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption
for(auto&item:_polls)
{2 J Q' J2 U, M& e7 k( g9 t6 Y
if(item.pollName==pollName)
{
//canonlyaddifthepollisnotstartedorfinished
if(item.pollStatus==0)6 g0 D$ I6 M. b/ ~
{' I! N& T0 `# c) p6 i0 `. |9 Z
_polls.emplace(get_self(),[&](auto&p)/ [) `" k. w8 B' n! `9 a! |
{* {( X% R" C8 g! n
p.key=_polls.available_primary_key();
p.pollId=item.pollId;5 i7 j4 U, L" H" G+ H* _( w. H: _
p.pollName=item.pollName;) t9 i5 ]2 I- A( P
p.pollStatus=0;
p.option=option;
p.count=0;
});8 B4 t; v( _ H5 _2 R& x5 C
}
else U( y0 `( f) R l9 D
{
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");3 K1 c& C2 N- g% J! v
}: i+ l F) @7 Q/ _
break;//soyouonlyadditonce
}, {" m- `( F" V- f
}
};
///@abiaction2 C! L, M w7 C0 p0 D( Y
voidrmpollopt(std::stringpollName,std::stringoption), l5 _( e5 [: d3 T! v ]# R
{' y4 J2 Y3 \2 X* I
print("Removepolloption",pollName,"option",option);
std::vectorkeysForDeletion;
//findandremovethenamedpoll
for(auto&item:_polls)
{4 o6 u* ]3 R$ X) F
if(item.pollName==pollName)
{ L7 R" p" N# A( B9 ?
keysForDeletion.push_back(item.key);
}# |# ~$ m2 B& W. B8 y
}, ^) |% `5 p& V5 W# e
for(uint64_tkey:keysForDeletion)) w7 `) r+ ?& |0 _1 w) ^% c
{
print("removefrom_polls",key);
autoitr=_polls.find(key);. u M0 @1 [( I s% Y/ O
if(itr!=_polls.end()). v& u. U. k' B7 Z/ y* r
{+ m( b, l3 y$ K6 {
if(itr->option==option)- L1 [ l1 W' h+ u$ w' }8 W
{ ]) p# G6 J r0 g
_polls.erase(itr);
}
}
}
};
///@abiaction. }3 Z: s3 x) i. ]- K. e
voidvote(std::stringpollName,std::stringoption,std::stringaccountName)
{, e/ j# C9 a9 c) W r9 I3 [7 }
print("votefor",option,"inpoll",pollName,"by",accountName);2 @1 n2 P- `! X. Q7 i
//isthepollopen
for(auto&item:_polls)
{
if(item.pollName==pollName)
{# n/ Y; a- Q x" B' s
if(item.pollStatus!=1)
{
print("Poll",pollName,"isnotopen");4 H q- [. l: |. p- w0 c B& q
return;
}
break;//onlyneedtocheckstatusonce- ^, D9 z- y4 Z' r
}
}
//hasaccountnamealreadyvoted?
for(auto&vote:_votes) K+ W, `6 D4 P; p7 o
{
if(vote.pollName==pollName&&vote.account==accountName)- W7 ~; h0 E- R9 ~7 n7 t
{
print(accountName,"hasalreadyvotedinpoll",pollName);
//eosio_assert(true,"AlreadyVoted"); @' x2 x6 x+ c8 I
return;+ n, `+ @( D( F% S
}2 B7 b& Y9 s! b. r1 Y8 k
}
uint64_tpollId=99999;//getthepollIdforthe_votestable
//findthepollandtheoptionandincrementthecount8 v& y# A4 B8 G
for(auto&item:_polls)6 h' ]1 \/ M' L! a/ L4 N4 [% Y
{" p+ u) y; X; x0 S
if(item.pollName==pollName&&item.option==option)
{
pollId=item.pollId;//forrecordingvoteinthispoll( `4 a- l% A5 j0 z$ f6 p5 {
_polls.modify(item,get_self(),[&](auto&p). O# w9 `; B+ j5 t+ p* t* c9 Y0 Y
{
p.count=p.count+1;6 a6 h2 p( \6 r7 a! Y. q
});, Q) Z0 c/ L; F/ B# O" {$ D- p
}
}) ]* J& h1 K! Q& H9 S9 T
//recordthataccountNamehasvoted8 c# i8 q7 x5 {. @/ N" |& k d
_votes.emplace(get_self(),[&](auto&pv)
{
pv.key=_votes.available_primary_key();" S# a3 O$ c7 X4 {9 L3 U
pv.pollId=pollId;
pv.pollName=pollName;
pv.account=accountName;
});" V0 K1 B! `' s7 i: L: _
};+ `/ C! I& s7 q' x
private:7 x" P& Z% p6 _5 c8 B6 g* n( M" K
//createthemultiindextablestostorethedata+ N3 t& z5 e9 U3 H e2 h
///@abitable! |( L6 n m0 |5 j( W1 v5 n
structpoll
{
uint64_tkey;//primarykey% h, }5 H* z4 ]3 {0 \
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption
std::stringpollName;//nameofpoll
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished
std::stringoption;//theitemyoucanvotefor
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable.3 X0 \9 u3 ^& ^: u# k3 z T8 J Q! _
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}& I. R( V7 S% O3 F# M0 _
};
typedefeosio::multi_index>>pollstable;) @. W9 B% n7 P" K6 q4 _
///@abitable
structpollvotes
{$ e) G, D0 k, Q
uint64_tkey;
uint64_tpollId;8 ~5 b, G) ?0 d6 d0 o
std::stringpollName;//nameofpoll4 ~/ i1 |" Z- ?: g0 X
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>1
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}
};2 L- }! t8 W. v5 i/ v/ |, U, b
typedefeosio::multi_index>>votes;
//localinstancesofthemultiindexes) M, d$ H) [% D1 F, U
pollstable_polls;
votes_votes;
};
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人