EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
104
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。3 S" S1 Z" t F! S2 Z6 N
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。7 A* ~" Y( v) w3 x( I) J
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。) X8 t- _' P s6 L$ e
1.创建一个结构
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。 C% T$ H: l: k$ {; a' T
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。
///@abitable
structmystruct1 y2 m2 p; C6 Z9 C) B
{6 R1 ]+ j% m2 g& j+ J' B( A
uint64_tkey;
uint64_tsecondid;& [# m9 g. |" X6 Z! H
std::stringname;
std::stringaccount;
uint64_tprimary_key()const{returnkey;}//getterforprimarykey ~* R4 Z: ^/ L- W6 Y, W# |/ W
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey
};% N# y' O: \# P' f
这里还要注意两件事:
1.注释:. \& a2 N9 Z$ `0 ]* g4 Y/ Q
///@abitable) V9 d! q+ T1 S7 F* i
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。
2.结构名称少于12个字符,而且所有的字符都要小写字母。
2.多索引表和定义索引
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:
typedefeosio::multi_indexdatastore;; ~. z; ~. ?' O0 c; W" b3 K
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:
typedefeosio::multi_index>>datastore;5 O" x) `% ]! p( |" @! v7 [! s
注意:
indexed_by>( o' }) G7 d3 Q* ^+ \3 ?
参数:- _" i: i% u- f1 J
字段的名称转换为整数,N(secondid)
一个用户定义的密钥调用接口,const_mem_fun
来看看有三个索引的情况。
///@abitable
structmystruct
{
uint64_tkey;
uint64_tsecondid; u: E( C- i) w7 l
uint64_tanotherid;
std::stringname;
std::stringaccount;5 i0 n' s% s& |$ O P: a4 D* l% B
uint64_tprimary_key()const{returnkey;}
uint64_tby_id()const{returnsecondid;}
uint64_tby_anotherid()const{returnanotherid;}. f' H9 L6 }' U3 N7 B; T& M# ^6 j j
};
typedefeosio::multi_index>,indexed_by>>datastore;1 d* E( P- N. I% q0 x4 ^
更多的就不列了。
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。 R$ H: i1 ?# V$ P, E
3.创建定义类型的局部变量
//localinstancesofthemultiindexes6 p- E% W) }" C5 W
pollstable_polls;" k4 o, K" z7 `( r/ |
votes_votes;4 J, C3 ]; d( t* V
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。7 Y4 M8 h6 x. C$ }
#include f7 f2 D5 L, m& F8 O1 C& z
usingnamespaceeosio;
classyouvote:publiccontract{
public:
youvote(account_names):contract(s),_polls(s,s),_votes(s,s)! B, S( j$ U9 t* n
{}
//publicmethodsexposedviatheABI
//onpollsTable
///@abiaction0 k4 A& n; ^' G& z K6 v
voidversion()
{6 ~5 ?. G+ d5 q! I& ?
print("YouVoteversion0.01");3 H1 S z, _; c/ @ d
};6 _6 j7 L+ E, S/ t& `
///@abiaction% Z0 K5 a& p9 p3 X9 D0 {
voidaddpoll(account_names,std::stringpollName)
{
//require_auth(s);
print("Addpoll",pollName);. N2 ?9 }) @0 e' i v8 }8 u
//updatethetabletoincludeanewpoll5 {/ Q6 R& e7 k+ ]6 \* @* _
_polls.emplace(get_self(),[&](auto&p)5 l$ G- R# s6 I
{
p.key=_polls.available_primary_key();
p.pollId=_polls.available_primary_key();4 ~ X) u) U$ j2 c
p.pollName=pollName;2 I& \- f3 g g, m
p.pollStatus=0;0 Y7 N; {( o% E$ f, q" }7 _
p.option="";& U3 m3 [ A" @! Y- c% j
p.count=0;# t0 w3 M2 k3 W5 Z' B8 t
});
};% ?6 d& [6 I5 Y7 p! S
///@abiaction
voidrmpoll(account_names,std::stringpollName)2 `& H$ c9 Z- p/ a; C( _+ i
{
//require_auth(s);
print("Removepoll",pollName);
std::vectorkeysForDeletion;
//finditemswhichareforthenamedpoll: F5 z( a! h( c8 i+ R
for(auto&item:_polls)
{
if(item.pollName==pollName)
{
keysForDeletion.push_back(item.key);
}6 F* z) y7 x- n5 ?$ X1 s; f
}
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletion)
{ L2 G& E G9 l! q+ C9 y; C" z
print("removefrom_polls",key);
autoitr=_polls.find(key);% ^" w5 p0 e5 B
if(itr!=_polls.end())
{
_polls.erase(itr);
}1 Y- z. P0 b8 \$ v7 g! i1 w
}3 O. Y, Q2 R b0 z0 b! m) k* u
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain
std::vectorkeysForDeletionFromVotes;& n+ E7 Z+ T Z' ]% Y0 B, g3 E) Q
//finditemswhichareforthenamedpoll
for(auto&item:_votes)1 z/ F' N, k4 N7 k; z% N& r
{' U( w% T F3 V& p
if(item.pollName==pollName)& c( D+ H4 h+ z4 k) c3 D5 Q
{
keysForDeletionFromVotes.push_back(item.key);
}+ ?# s7 N" d, A. o0 [, t
}
//nowdeleteeachitemforthatpoll0 |0 I2 j, c3 i- o2 \
for(uint64_tkey:keysForDeletionFromVotes)
{3 l8 s+ n# b) d
print("removefrom_votes",key);
autoitr=_votes.find(key);2 x3 ^8 @ w/ T) t' n
if(itr!=_votes.end())4 @9 y7 L, ]3 j) l( n
{/ E* d' u% Z, y6 ?! L
_votes.erase(itr); q& |7 {1 u) K% Z' q* ] Z
}4 H/ M) G7 n$ @6 Q% [
}6 P$ b2 b: O' f/ _8 Y. L1 P! c
};
///@abiaction
voidstatus(std::stringpollName)8 f1 ?" x+ D [5 Z i
{
print("Changepollstatus",pollName);) w' U: p0 g. C* T
std::vectorkeysForModify;
//finditemswhichareforthenamedpoll
for(auto&item:_polls)
{
if(item.pollName==pollName)" l5 n' V# D- {' x/ L J
{! C1 A3 x) `4 Z+ E
keysForModify.push_back(item.key);
}# z( E: l8 {# f' Q1 R: s9 N9 P) o
}% @5 |$ Y: A: ^9 g# o
//nowgeteachitemandmodifythestatus
for(uint64_tkey:keysForModify): y6 ^) a$ ?6 D: U) \) e" w9 O' T
{1 s' p, x8 v2 m9 b" _8 {9 D. w
print("modify_pollsstatus",key);
autoitr=_polls.find(key);
if(itr!=_polls.end()): C2 Q# q9 d% D6 u" q+ X
{
_polls.modify(itr,get_self(),[&](auto&p)
{4 L9 c/ P& g3 N: ?4 F0 Y! z, b
p.pollStatus=p.pollStatus+1;
});
}
}5 o. ]& W8 Q1 T6 W# T' X' q4 W
};
///@abiaction* F1 `9 ?7 m! E$ x0 M3 I
voidstatusreset(std::stringpollName)! t; a1 D, p2 z7 D" L
{
print("Resetpollstatus",pollName);
std::vectorkeysForModify;/ ^- L/ e, I; G9 z: T
//findallpollitems) q P$ f- p) A0 j- y# z
for(auto&item:_polls)
{7 g) B! \; {) I4 O
if(item.pollName==pollName)
{
keysForModify.push_back(item.key);0 p& v4 y1 r2 H% h$ e% d5 F9 |
}
}+ t# j7 S/ p- k3 B9 ?- s
//updatethestatusineachpollitem( ~) Q0 L$ q; t* b0 g1 e
for(uint64_tkey:keysForModify)
{' I1 ~) `7 \" W: ~
print("modify_pollsstatus",key); c1 X6 Y9 f) K
autoitr=_polls.find(key);
if(itr!=_polls.end())( U0 f/ N1 d: V! u! G* U
{. x$ O0 Q' l6 \3 F5 r
_polls.modify(itr,get_self(),[&](auto&p)# @# x5 C5 z* K0 h6 V! V
{
p.pollStatus=0;
});4 G. c- n. T w: M& p% ?
}5 Y+ n/ [. _* }1 J; G
}% u7 t/ B7 {7 `! g/ C3 l
};
///@abiaction
voidaddpollopt(std::stringpollName,std::stringoption)# b- n& E" l* h: N
{1 q# a8 h3 g1 Q% ]
print("Addpolloption",pollName,"option",option);* M! o. d- j s$ J5 G, Q
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption; [( n* Z) l5 o$ W' L- @( B
for(auto&item:_polls)) l3 i; `4 t! h9 p
{$ ?' V6 A4 u7 c, k# J4 Q3 O
if(item.pollName==pollName); a% U. L6 |) E1 d5 @1 z
{
//canonlyaddifthepollisnotstartedorfinished5 \: p: i+ K Q. i) N
if(item.pollStatus==0)3 D7 Z% L$ C5 c- l% g, t/ m# ]
{
_polls.emplace(get_self(),[&](auto&p). _" L3 X, f0 i# V8 I: R9 o% X
{
p.key=_polls.available_primary_key();
p.pollId=item.pollId;
p.pollName=item.pollName;
p.pollStatus=0;, P7 Q- u: U! {9 y& s7 O+ s
p.option=option;* f D2 ]1 j( z7 ~. E# w$ R
p.count=0;
});* T4 N# L" f& D9 }- U. y s7 x2 M
}
else' K: Y1 m& K. H7 L
{; s( |$ L: k3 K4 d- Y, `* I
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");5 m- O0 m9 N- {! F5 f0 i
}
break;//soyouonlyadditonce
}
}6 Q& a7 P- s& [0 V
};2 j' |, g+ r" X
///@abiaction
voidrmpollopt(std::stringpollName,std::stringoption)- Y; b6 {) B: e% ?" y" Q' e
{7 P+ D2 C% A) a- R8 A8 o
print("Removepolloption",pollName,"option",option);
std::vectorkeysForDeletion; r$ Z0 D6 M- @1 v8 o. x# n4 @- U
//findandremovethenamedpoll( x* X+ {' ~4 E, f: g3 {
for(auto&item:_polls)' Q* W% d0 z8 N: C/ F8 f3 c* T
{6 M' `1 O1 p( H( A3 `. |# \- A! ]5 H# w
if(item.pollName==pollName)- h' V2 A/ |( n9 M+ `- G% y
{2 C4 o) E9 ~0 v0 ~/ p. L7 x- l
keysForDeletion.push_back(item.key);/ q; N, I3 t5 _8 _* q8 H
}
}
for(uint64_tkey:keysForDeletion)
{! U8 Z& |% l1 D5 u' D# U* a
print("removefrom_polls",key);
autoitr=_polls.find(key);$ |1 b. @9 m; v- q2 B9 s* e
if(itr!=_polls.end())
{
if(itr->option==option); e# o4 T2 F2 d- T
{
_polls.erase(itr);6 m7 B- B2 W5 q
}" ^, G7 p; z7 V' f/ J
}
}6 O0 Z! O; i4 G3 g; }$ H F
};
///@abiaction
voidvote(std::stringpollName,std::stringoption,std::stringaccountName)' D6 O6 M8 j6 z
{+ B) _! T" D1 W8 Q- |0 }# L
print("votefor",option,"inpoll",pollName,"by",accountName);) t! j# |& w2 ~. j R
//isthepollopen
for(auto&item:_polls). l. i$ j! A4 C1 f# u+ q0 {
{
if(item.pollName==pollName)$ y6 N- K8 ~' C! n8 n
{
if(item.pollStatus!=1)
{
print("Poll",pollName,"isnotopen");) o$ t- {9 | j- g! F8 p! V
return;
}$ p( g! ?) k$ K4 r( P7 y
break;//onlyneedtocheckstatusonce
}$ t+ P; R& V; F1 W% s; }4 ~% L' t' H- F" k
}# A# Q8 d9 b' C& Z" q, w* I! x
//hasaccountnamealreadyvoted?
for(auto&vote:_votes)
{9 e: M/ V0 \3 d( T/ ]6 Y
if(vote.pollName==pollName&&vote.account==accountName)4 ?5 ~2 j6 A! f7 Y/ x+ m; t
{- a7 F, Z2 K5 y3 N9 V+ i
print(accountName,"hasalreadyvotedinpoll",pollName);: g9 P# o& a$ F$ S, b
//eosio_assert(true,"AlreadyVoted");+ \( E+ ~( S! X3 ]2 z6 I
return;3 x. T! i' K0 f/ Q
}
}' n: V* B4 \* W0 c. f
uint64_tpollId=99999;//getthepollIdforthe_votestable
//findthepollandtheoptionandincrementthecount6 p7 T5 E3 d' j. I+ i' S6 r: k! Z
for(auto&item:_polls)1 J$ F4 Y& g( w3 R9 e
{) t0 H _1 T, u# T) t3 P
if(item.pollName==pollName&&item.option==option)
{
pollId=item.pollId;//forrecordingvoteinthispoll6 ^. K* F* Q" g) k+ ?5 P O
_polls.modify(item,get_self(),[&](auto&p)
{3 N# W9 d6 u0 H% O6 W" u
p.count=p.count+1;
});+ o5 m$ d/ J. l5 k0 I0 D- ~+ U( q9 s
}- y4 d a1 o& t$ ^' C- }0 w
}9 |4 F3 F" j! e* C* a3 |( p
//recordthataccountNamehasvoted
_votes.emplace(get_self(),[&](auto&pv)' f& _4 c' e6 }1 I
{
pv.key=_votes.available_primary_key();! i7 J- J. d& J2 v* {
pv.pollId=pollId;
pv.pollName=pollName;8 R" T. K+ E" \) ~5 Y6 Q
pv.account=accountName;# o1 t" Z0 o0 ]4 u8 }
});0 M$ S9 h4 K9 L; @
};
private:
//createthemultiindextablestostorethedata/ a: C( @4 ?7 f0 G* O4 ^& |9 M' R
///@abitable/ ]4 M8 ]! s' a
structpoll5 W D& F1 N0 ^/ ^$ \8 J
{& E' J M- ~0 S# Y% N
uint64_tkey;//primarykey
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption
std::stringpollName;//nameofpoll+ M$ i5 ]; U$ w7 D$ U
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished% d( j+ b- W1 R" S8 r, X/ e" v0 r, s
std::stringoption;//theitemyoucanvotefor
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable." s u8 x- M* U
uint64_tprimary_key()const{returnkey;}/ W4 W8 `. A% N$ M2 b* B7 R$ i
uint64_tby_pollId()const{returnpollId;}& i/ F' g2 S/ b8 @% I: F
};
typedefeosio::multi_index>>pollstable;2 Z# m5 U. o( Q6 X
///@abitable$ ~) ~* A# v$ [# y
structpollvotes
{9 L1 \) K2 v% q
uint64_tkey;
uint64_tpollId;
std::stringpollName;//nameofpoll
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>1, N& F1 @/ }+ D, J
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}) s5 w& g a7 s o3 S9 F
};
typedefeosio::multi_index>>votes;
//localinstancesofthemultiindexes2 a7 \- T& o" G7 d; `7 j# a2 x
pollstable_polls;
votes_votes;" q. G! [: Q$ v! r
};
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))2 G' m2 Z. c6 E A
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人