EOS智能合约的多索引表table
西门幻雪雪vj
发表于 2022-11-13 23:50:55
180
0
0
多索引表提供了快速访问数据存储接口,是一种存储智能合同中使用的数据的实用的方法。在区块链记录交易信息,你应该使用多索引表存储应用程序数据。
使用多索引表,因为他们支持为使用的数据建立多个索引,主索引必须是uint64_t类型和唯一的,但其他的索引,可以有重复的,你可以使用多达16个,类型可以是uint64_t,uint128_t,uint256_t,doubleorlongdouble。
如果你想你需要使用一个字符串做索引,需要转换成一个整数型,将结果存储在随后索引的字段中。5 e v6 @. L- ~% H/ v0 o7 c
1.创建一个结构5 c3 J9 \6 n: n
创建一个可以存储在多索引表中的结构,并在要索引的字段上定义getter。4 e# k% w+ R9 k
请记住,这些getter中必须有一个命名为primary_key(),如果没有这个,编译器eosiocpp将产生一个错误…"itcan’tfindthefieldtouseastheprimarykey"即它找不到任何一个字段被作为主键。
如果你想要有一个以上的索引,(最多允许16个),然后为你想要索引的任何字段定义一个getter,这时这个名称就不那么重要了,因为你会把getter名称传递给typedef。
///@abitable5 r& D# o& u! P8 f
structmystruct
{
uint64_tkey;, E& s$ k7 b8 n6 P, b. I4 Z
uint64_tsecondid;, r$ \$ ]6 `2 W7 v1 F* k0 Z7 d
std::stringname;
std::stringaccount;
uint64_tprimary_key()const{returnkey;}//getterforprimarykey. T2 G9 A* |4 R
uint64_tby_id()const{returnsecondid;}//getterforadditionalkey
};! W4 n l! g: [" B6 b7 S
这里还要注意两件事:3 {$ p+ s" ?5 a! K
1.注释:
///@abitable! ~) n) c8 x; r0 @3 ?) v
编译器需要使用eosiocpp来识别要通过ABI公开该表并使其在智能合约之外可见。
2.结构名称少于12个字符,而且所有的字符都要小写字母。
2.多索引表和定义索引/ O3 d' O" k) d+ D, Y1 F
定义多索引表将使用mystruct,告诉它要索引什么,以及如何获取正在索引的数据。主键将自动创建的,所以使用struct后,如果我想要一个只有一个主键的多索引表,我可以定义它为:+ E) }$ c1 s$ x$ p- d) c) r# i
typedefeosio::multi_indexdatastore;$ O& J3 U0 A8 K* O" ^# w. H
这定义了多个索引通过表名N(mystruct)和结构名mystruct。N(mystruct)会对结构名编译转换到uint64_t,使用uint64_t来标识属于多索引表的数据。
若要添加附加索引或辅助索引,则使用indexed_by模板作为参数,因此定义变为:
typedefeosio::multi_index>>datastore;. |5 y0 e& a' V* p, P Y4 u/ i& B
注意: E& Q$ h8 d, e0 P+ e
indexed_by>& v/ A3 Z6 x) z, T
参数:
字段的名称转换为整数,N(secondid)5 H% B9 _! m% X3 s
一个用户定义的密钥调用接口,const_mem_fun4 i$ C C% N/ M* `; Z5 M2 U
来看看有三个索引的情况。, F! @3 d! J2 g+ E5 n
///@abitable
structmystruct
{& h6 w/ @# T; ]2 q2 @
uint64_tkey;
uint64_tsecondid;4 @( w+ }/ O" |" v0 E1 s
uint64_tanotherid;3 J9 |* C w9 W0 j: ^( ?
std::stringname;
std::stringaccount;
uint64_tprimary_key()const{returnkey;}/ M G$ ]8 G. n
uint64_tby_id()const{returnsecondid;}8 f; O6 k q( i3 x! B
uint64_tby_anotherid()const{returnanotherid;}
};) p' S8 J6 p1 ~( Z }8 i$ H" C
typedefeosio::multi_index>,indexed_by>>datastore;7 P% t% V1 ]7 O
更多的就不列了。
这里要注意的一个重要事项是,结构名与表名的匹配,并且将出现在ABI文件中的名称遵循规则(12个字符,所有都是小写的字母)。如果它们没有遵循这个规则,则表不会通过ABI可见(当然可以通过编辑ABI文件来绕过这一点)。
3.创建定义类型的局部变量- p7 k( W2 d+ n: |6 i& u
//localinstancesofthemultiindexes* n* i* S6 k6 [* y1 H; H
pollstable_polls;) [* _; R) d8 x5 G. t
votes_votes;) _7 ~: z) m3 K; W1 E& K, I
现在我已经定义了一个带有两个索引的多索引表,我可以在我的智能合约中使用它。
如下是一个智能合约使用两个索引的多索引表的例子。在这里你可以看到如何遍历表,如何在同一合约中使用两个表,我们未来将增加额外的教程,利用多索引表。
#include
usingnamespaceeosio;
classyouvote:publiccontract{
public:
youvote(account_names):contract(s),_polls(s,s),_votes(s,s)" B9 z! M5 }- x# X- _4 u0 k- b
{}& J8 R6 h& P$ M
//publicmethodsexposedviatheABI4 u& o( W# ~! Z! F* s* X; C/ b5 E; M
//onpollsTable- a; ?( j. U3 J" u# V' s
///@abiaction
voidversion(), q: m& i* `! T& t+ F
{) c* ^. {5 E9 w4 \
print("YouVoteversion0.01");: y& a& r" L, l( s1 c' }# I
};
///@abiaction- F/ X& K0 e0 n. z1 t
voidaddpoll(account_names,std::stringpollName)8 W& W* }3 k2 _6 i; }8 j& n
{/ X* O/ D7 Z' i# }/ s: ~) e5 t0 t8 A4 i
//require_auth(s);) S! Y8 N7 x7 `1 Z9 t
print("Addpoll",pollName);+ V5 n/ D9 H1 g* r
//updatethetabletoincludeanewpoll
_polls.emplace(get_self(),[&](auto&p)
{; v: \# t4 O+ e
p.key=_polls.available_primary_key();
p.pollId=_polls.available_primary_key();
p.pollName=pollName;
p.pollStatus=0;
p.option="";
p.count=0;) H$ p5 \) j: C* U
});
};
///@abiaction1 F- K0 d$ f1 L3 h& d- \
voidrmpoll(account_names,std::stringpollName)
{
//require_auth(s);
print("Removepoll",pollName);
std::vectorkeysForDeletion;
//finditemswhichareforthenamedpoll, i3 {0 ]- M$ [: D
for(auto&item:_polls)
{( b1 l' F( B4 l6 ]1 a% O
if(item.pollName==pollName)% Q& y0 A9 I7 f) }5 G' E
{" m9 S" E# h9 E5 X
keysForDeletion.push_back(item.key);
}2 e0 O/ D; O, i2 s
}0 y! Q$ h4 \9 z# L
//nowdeleteeachitemforthatpoll
for(uint64_tkey:keysForDeletion)! _6 h, m6 x3 |: L& h8 ^ L
{
print("removefrom_polls",key);
autoitr=_polls.find(key);! T9 {3 ]8 k8 x0 a' x" q) ~" r1 C
if(itr!=_polls.end())7 ^( V4 h, j* D& k/ H& U O9 N" ~5 q
{
_polls.erase(itr);
}9 V9 @( T1 o& @5 `1 d7 o8 T' D( L
}
//addremovevotes...don'tneedittheactionsarepermanentlystoredontheblockchain
std::vectorkeysForDeletionFromVotes;1 G- [5 _! b+ M' } M
//finditemswhichareforthenamedpoll s" w0 |, b! t% L& Q& `2 s
for(auto&item:_votes)& ?% u( c1 r6 P; {( `
{1 b9 o- \' W$ |
if(item.pollName==pollName)
{' ]$ m; @( A# ~" L& X8 u
keysForDeletionFromVotes.push_back(item.key);$ R! C& h' ?# K5 L7 j% v0 Z6 l
}
}- A9 q8 p) N( [! I5 Z0 d: f
//nowdeleteeachitemforthatpoll" i2 b5 S7 ~3 F" w# a3 Y- T/ [0 [
for(uint64_tkey:keysForDeletionFromVotes)1 ^; E' m* ^4 g. E
{
print("removefrom_votes",key);
autoitr=_votes.find(key);# \9 z9 F1 \# m: X( ]" Z" L
if(itr!=_votes.end())
{* b; t" s3 p" y, `
_votes.erase(itr);
}
}# N5 M" L2 ?0 h
};
///@abiaction! ?: h/ w# p0 N3 r* |, }
voidstatus(std::stringpollName)% }4 j8 E! \; `
{% B# T! h' a# h" Y0 H% v+ ]
print("Changepollstatus",pollName);4 r8 n0 ?# Y8 F d0 o, d
std::vectorkeysForModify;4 E. y0 [! e- e# H5 r2 i* r4 k' ~
//finditemswhichareforthenamedpoll% J8 ^) G E+ O9 s& W9 ~! Q% x
for(auto&item:_polls)
{- _: w0 O/ O0 u
if(item.pollName==pollName)
{) X+ D; P9 b1 t2 B" f' m. ?' F1 i
keysForModify.push_back(item.key);
}/ o* i4 w% z) l
}( C3 N" Q1 ~% n& F+ Q
//nowgeteachitemandmodifythestatus
for(uint64_tkey:keysForModify), F, Y. [4 W8 U E) \
{
print("modify_pollsstatus",key);
autoitr=_polls.find(key);' ~& h$ F, v X& f. D! v0 e
if(itr!=_polls.end())
{
_polls.modify(itr,get_self(),[&](auto&p)6 x: Y$ |, k+ A' Q( \
{7 \ R9 B( d2 D7 |9 }3 E M" x
p.pollStatus=p.pollStatus+1;! G! x y" Z; ^$ E$ i
});
}
}, I& ?2 ?; G% y( Y; e! E( @+ k' f
};& G {, Z9 j1 P! ~# O4 k8 q0 l; `
///@abiaction
voidstatusreset(std::stringpollName)% Q+ s1 U2 V: E1 k- e! U
{
print("Resetpollstatus",pollName);
std::vectorkeysForModify;( j) A/ w+ {: j9 j0 w$ ]
//findallpollitems
for(auto&item:_polls)
{5 J1 p6 I$ a" b! y7 ?
if(item.pollName==pollName)
{1 d0 P" n$ t$ t- w+ H& y
keysForModify.push_back(item.key);2 R3 h p0 ?4 `5 _; h
}# H* }4 i1 v' \5 X
}
//updatethestatusineachpollitem5 I2 x3 K ]+ @" ~( x
for(uint64_tkey:keysForModify)
{7 j' w8 P4 g9 T& }+ u; r; _
print("modify_pollsstatus",key);
autoitr=_polls.find(key);- k" {; t. x' i) F
if(itr!=_polls.end())) Z3 |9 ~! D. l" o
{0 h9 @' M) P6 E _: v
_polls.modify(itr,get_self(),[&](auto&p)
{# x7 T/ h% v8 f- v
p.pollStatus=0;9 F1 d; \. N2 {# X5 F
});. s/ Z. s. q8 H' c( r
}* D+ C5 U v' U. a4 L! K3 S
}" s' O# u! |' E
}; S: p" x' s7 ^% ~, f+ I
///@abiaction
voidaddpollopt(std::stringpollName,std::stringoption)8 g0 G0 w4 o* Q5 u
{
print("Addpolloption",pollName,"option",option);
//findthepollId,from_polls,usethistoupdatethe_pollswithanewoption3 t% _ E/ i$ {* d- \; R D6 s
for(auto&item:_polls)4 O; k! p2 @6 ^ d2 O5 D
{! a$ H, K, o+ Z j' Z
if(item.pollName==pollName)6 l2 `# x6 `' u" @* P% U+ T
{+ V. ?8 w3 k0 o" g5 W
//canonlyaddifthepollisnotstartedorfinished
if(item.pollStatus==0)
{
_polls.emplace(get_self(),[&](auto&p)
{
p.key=_polls.available_primary_key();
p.pollId=item.pollId;( Q% |. d% p+ g; o1 w/ H& ?5 x
p.pollName=item.pollName;
p.pollStatus=0;6 h; X# R$ ^% o- ?
p.option=option;
p.count=0;
});
}+ T+ Y: m' B3 S
else, E( p6 X; M, I9 n3 H. s
{
print("Cannotaddpolloption",pollName,"option",option,"Pollhasstartedorisfinished.");
}
break;//soyouonlyadditonce! d b. K [8 w: u: Y- Y
}3 x& X' |+ d& w8 h8 r- u
}' N9 n/ `. D; W
};0 F5 Y3 X7 |5 {% t" a( J
///@abiaction, @$ k/ k: H. s; a- i
voidrmpollopt(std::stringpollName,std::stringoption) Y) q* J J# f* O q/ C
{. [3 F" r! t4 \9 j0 b6 a% J6 k
print("Removepolloption",pollName,"option",option);5 V- X }. m/ w% j' o$ K$ Z9 z( N. Z
std::vectorkeysForDeletion;
//findandremovethenamedpoll
for(auto&item:_polls)1 ]( g' |1 \, \
{8 n, ~8 `% c# j, A. a
if(item.pollName==pollName). q" k! u6 a! y" D7 L# c n
{
keysForDeletion.push_back(item.key);
}
}! ?1 a2 ?$ A, c, S D0 M6 x
for(uint64_tkey:keysForDeletion)
{* C7 d) ?; q2 ]: w1 N
print("removefrom_polls",key);
autoitr=_polls.find(key);
if(itr!=_polls.end())* x4 V# |1 f8 T' E+ R, M/ C
{+ m8 C: d1 M1 o% r! i5 j. K4 l: k
if(itr->option==option)
{+ _# f7 P- j( H
_polls.erase(itr);
}) @1 J2 W6 p; L6 ]0 {" I& [
}8 B" L" K% a' [1 Y5 U/ t1 h
}& [. Q5 S: b9 L9 E& [- O
};
///@abiaction
voidvote(std::stringpollName,std::stringoption,std::stringaccountName)- [( W; I/ F' F8 M
{
print("votefor",option,"inpoll",pollName,"by",accountName);) j# D/ I# V1 R" ~$ g% b
//isthepollopen
for(auto&item:_polls)- _, J' F6 R7 J0 g
{# ^. z x- W/ X' `! x3 Y
if(item.pollName==pollName)
{
if(item.pollStatus!=1)
{
print("Poll",pollName,"isnotopen");! w, a: u% x/ I0 Q% g/ c
return;, B* I# ^( r' Z" d
}+ { A! r( @8 X8 Y- B& ]! f: u
break;//onlyneedtocheckstatusonce9 v. p D" h; q: x
}
}, A6 q$ z5 C# c" Y' `" p7 U/ `
//hasaccountnamealreadyvoted?
for(auto&vote:_votes)- S* ~/ C# b1 j
{
if(vote.pollName==pollName&&vote.account==accountName)0 I9 n% j/ g! g0 p: F
{9 P" k! N" n& j1 q9 y/ w
print(accountName,"hasalreadyvotedinpoll",pollName);4 a/ t: P. v, v) f
//eosio_assert(true,"AlreadyVoted");
return;1 Z# s# @8 S5 G H" j
}
}
uint64_tpollId=99999;//getthepollIdforthe_votestable0 G; @% O# N \' D3 g* Z( \' L1 c* l/ i# \+ T
//findthepollandtheoptionandincrementthecount
for(auto&item:_polls)5 L. a& X- W6 l+ B8 c8 Y. U- I
{
if(item.pollName==pollName&&item.option==option)5 M4 L# {/ w" s2 x& N# T
{. }: z0 S; W7 [9 p- A9 D& `
pollId=item.pollId;//forrecordingvoteinthispoll. P9 |2 O! Y& \
_polls.modify(item,get_self(),[&](auto&p)
{
p.count=p.count+1;
});
}% K9 |$ |! Q2 G) G/ w0 v
}: J$ k0 I4 O6 E' I8 h
//recordthataccountNamehasvoted
_votes.emplace(get_self(),[&](auto&pv)
{" o% _6 x+ Q7 {* C' p
pv.key=_votes.available_primary_key();! L8 f. r6 e7 x2 X! L9 S
pv.pollId=pollId;# l) e, B6 d2 s2 ?6 C
pv.pollName=pollName;
pv.account=accountName;
});
};
private:0 k. E P+ l9 r; t$ Z
//createthemultiindextablestostorethedata) c8 E: n2 u5 |! ?6 w
///@abitable
structpoll1 G- O S% S2 ]
{& \/ P( y) c8 d; y
uint64_tkey;//primarykey: s6 m z: k! Z6 p! ~
uint64_tpollId;//secondkey,non-unique,thistablewillhaveduprowsforeachpollbecauseofoption
std::stringpollName;//nameofpoll
uint8_tpollStatus=0;//stauswhere0=closed,1=open,2=finished, k- c! i+ P% I3 ^
std::stringoption;//theitemyoucanvotefor
uint32_tcount=0;//thenumberofvotesforeachitme--thistobepulledouttosepartetable.
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}
};1 Y, z8 d/ Y- U5 [' q
typedefeosio::multi_index>>pollstable;7 G- S2 Z4 p, L+ R0 x
///@abitable B/ z. t n- J5 J
structpollvotes
{ V6 K- L9 o; n5 O7 ~8 \) r5 R
uint64_tkey;
uint64_tpollId;
std::stringpollName;//nameofpoll0 r% h' a9 |: ~, `( B
std::stringaccount;//thisaccounthasvoted,usethistomakesurenoonevotes>1
uint64_tprimary_key()const{returnkey;}
uint64_tby_pollId()const{returnpollId;}$ Z$ C( x/ ^/ F; P7 e
};- g4 M+ A2 @; }" U( n
typedefeosio::multi_index>>votes;
//localinstancesofthemultiindexes. b. V) F4 i! q4 K6 R1 ?) `! M9 ?
pollstable_polls;- ]1 Q: j) {+ Q3 K: d
votes_votes;
};
EOSIO_ABI(youvote,(version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))% U, a0 g/ h9 z& P2 I
注意EOSIO_ABI调用,它通过ABI公开函数,重要的是函数名与ABI函数名规则一定要匹配。
成为第一个吐槽的人