Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen7 q  f; W& ^: p" R/ X2 {
8 l1 _) j1 _: P. q% Y* N
这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。7 f1 J. g- L8 o0 h7 K
7 y# M( `1 f0 D8 Y( Q; j9 b
SimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。  {0 S" ^8 a; @) @

' Q* F9 ^4 I# b$ K% P( tabigen 可以以下 3 种方式运行:$ M7 |+ w6 D1 u$ I+ S7 A0 A
1
4 n% L- E) S5 |1 R7 U: a6 pDispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数6 H% G, N$ |" i4 O
2; F( e4 [6 v& V
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约
3 {4 N3 \3 P1 v& ?3
9 h" ^- Z- t( t* W% UEncoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约
4 A! G* [  y9 }- G3 T  P) i, {+ U- m0 t) M+ c4 X; L0 D5 x& S
与 Solidity 的区别是什么?
1 Q0 b/ ^. e4 w7 Q9 a
. w  b+ U: e5 L; p- f2 HSolidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。
  l% H' V6 ?. x8 W但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。# [: E- N( e8 A4 j, H% G$ x

  s- ]* a2 u% s  w6 L7 s我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。
' l7 P" F) B/ N( C" e
& ?( E, L) _0 t5 h( v; Y这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。
( }% i* J. S6 w% W! R$ R/ u/ N- {; I% Y, J2 h
与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。1 C% [( L) Z8 S7 ]* ?: \
/ t9 H* J$ Q& ^$ {0 y, ]; k
这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。5 f& r3 x+ ~" D+ x, N' E# L0 d

5 p, s: W. P# m+ Q2 TABI 规范
% `8 b7 h6 @/ I, f' Y/ O: R# f- }2 ^5 z& l
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
. P% b# e' K7 T2 F$ V% p9 A9 ^类似 ERC20 的接口示例:& L' R0 u, {/ L* r6 C- j1 P) T- S
ERC20Interface3 d& X0 Y, A* \
# The first non-comment line is the name of the interface and used for all codegen prefixes( P' t7 F4 \4 Z7 ~4 t0 C
# this is a comment
7 X4 P* L1 g. z8 nselfBalance -> balance:uint64& }1 W; z7 y7 \  g
address:UniversalAddress balance:fn -> balance:uint649 Q8 i* m1 j; I+ _" i8 i# i+ w1 ?0 |" N
addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64
! ]) w9 n9 x% \  p! H  Yaddress:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable
% N  Q  Q$ C4 L( }  W. G5 G1 v
6 H' d4 S! O- H# g: O也可以使用数组:4 p# ~) K  `1 h2 y
ArrayExample% h% H. g5 _  E* J2 v
#declares someFunction takes an array of 20 bytes exactly
) b. X" i' s& I7 b% W! msomeData:uint8[20]:fixed someFunction:fn -> void. M4 n1 z( P, T- O$ O
#declares someFunctionDynamic that takes an array of no more than 20 bytes+ D4 U. I# d6 Y1 O. y# b
someData:uint8[20]:max someFunctionDynamic:fn -> void' R+ ?( b, s& U
支持的基本类型:
2 H! |6 j# b$ c4 R2 n4 s- Q
' {' u& i; O* d0 N" l5 puint89 G0 h+ Y% o( C% y
uint16
! e9 g1 U' z! r8 ~2 euint32
, w7 X2 P9 z: m5 N* l2 luint64
4 v" y# S7 B, B* k' P; Z0 Sint87 d( D. D( B/ ?
int16$ k6 q) I8 s3 [" f
int326 O* B! n( Y+ I; {( s' t6 Z2 U
int64
4 j/ J' c; N7 {/ R  N8 _3 X; jchar
. |! V2 g. p4 o4 Svoid -- 仅对返回数据有效。对应无返回数据- S/ y  G1 _$ W
fn -- 特殊# e% L% n  h" T# j; O5 ~' f
更高级的类型:# J7 s: z9 \2 Q* t6 {1 A7 {
UniversalAddress
8 J6 V2 D& t0 s" w  ^% B基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。
4 w) f. x# _8 n* f" o0 s数组类型:
* f, h0 r) B9 m- rfixed(默认) - 数据必须是指定的确切大小
! Y2 X- d& [: ~+ J0 v  cmax(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误
$ F! m. O2 p0 R2 A" i2 Pdynamic(动态) - 任何长度都有效(使用前 uint8[])有效
  w2 z! Z! B4 I* ?clip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误! o- F7 s4 b/ Z- U1 L7 e+ R

: M1 B* A0 Y; O, K4 z函数编号
  J1 {7 N2 e  a  K; v/ n  a! {/ Q0 a6 q函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。
( T# L4 V! ?5 p* F$ K$ R- Y* p6 K* M
& k* g- D4 L) [6 y0 m- k内存分配
  z1 X  L. B( x4 N+ E5 b* o/ C大于 256 字节的数组都使用堆分配而不是栈。
9 D8 n( G1 V5 Y: Y' H8 E  @( `5 k8 V
接口! i6 W0 l$ z1 g2 M
一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。( A7 O3 P# F# w4 ^+ ^' |5 p
包括其他接口:
+ M  I9 J3 j5 Y! o4 l. l$ j* NMyContract4 c! t. l7 T% G
:interfaces ERC20, ERC721, MyParentContract
/ N" a# Q# n& ?; v* M- Wabigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
5 B: a7 d, U% \, r4 L# K' v) @
8 i2 k8 m+ o5 v+ ]语言. I3 G' y; r  g
现在只支持 C. 之后会支持 Rust。/ J" A. t) f* [& {) ~/ H
示例(手动生成) C代码:1 j, Y- G" y$ D4 U$ p; n
struct simpletoken_Send_Params{
1 h8 }/ d9 g* z& M   UniversalAddressABI* address;
* x) L. J- x9 y- r. ^9 m   uint64_t value;
& b! F8 M+ W2 m( \+ e};
0 S8 }) A* z6 O" B% U2 wstruct simpletoken_Send_Returns{4 \8 s9 a* p9 r3 x
   uint64_t recvvalue;
: W, R( L0 q) ]' h4 D" u   uint64_t sendervalue;* |# S% v! ]( N& y
};7 d/ c# U. r. n9 m9 I
void decodeABI(){, j$ ]; u- m7 A' B2 D8 S
   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64' V* A1 C8 h7 n0 Z7 z- ^* g3 e
   //format: address:address BALANCE -> balance:uint62 M: A; w5 i5 ~. d/ V
   //format: SELFBALANCE -> balance:uint64
4 x2 K% m3 f- M4 Q   uint32_t function = 0;
+ a% k% \7 U$ `% C; n/ t2 d* j   if(qtumStackItemCount() == 0){* S2 F% H" H  Y. h5 z; m) ~0 n
       //fallback function...
+ m7 r# k. v: v9 ]5 H( C; _   }1 s% j1 z4 u% W  K  P
   QTUM_POP_VAL(function);
4 O6 R& k! O- ~' q- X' ]6 A   switch(function){) g7 H7 `8 A* a
       case CONTRACT_SELFBALANCE:4 e- r) Z% _, X1 ~$ F% {- O
       {. n) x9 h, {" A( ^5 a( Q! y
           uint64_t resBalance;5 G7 M) Y' `* m1 X) R/ {
           selfBalance(&resBalance);
7 R# @8 h. ]/ q6 |           QTUM_PUSH_VAL(resBalance);: q( Y, z2 m* k' w( s/ d6 z! G
           return;' d6 [: y+ K8 ]2 ^. }  g+ Q
       }
5 o; o1 c% b5 e! ]6 U0 @       case CONTRACT_BALANCE:$ X. C1 B6 z7 W
       {
8 r5 j) U& @1 H' I7 x1 ]1 `           UniversalAddressABI address;4 h) ?' G! n/ r* u" f
           QTUM_POP_VAL(address);
4 }* V3 k8 K/ s" k) K           uint64_t resBalance;
  g* y5 t% @) H4 l) `! P. N; [           balance(&address, &resBalance);
, o- P2 C- [% M% ~, P8 n0 Z           QTUM_PUSH_VAL(resBalance);2 m* u% C% N" e5 f$ }) O$ x& H4 U
           return;: I. \. _! d' n3 O
       }
7 F/ v  m: T2 H3 x( g8 L0 `       case CONTRACT_SEND:: j1 f6 c- o% z& B9 r. S9 \
       {
7 Z0 {% ^9 ?$ e1 m+ I- ]% V           struct simpletoken_Send_Params params;3 r3 l: j: N7 ]7 d2 \5 A, |2 a
           UniversalAddressABI __tmp1;
4 [9 Y% o/ S- a& w           params.address = &__tmp1;9 j+ q0 j* ^9 s) B
; y, F/ V8 G- K+ ?9 z3 K7 u
           QTUM_POP_VAL(params.value);, n9 P- V! g4 r* y6 d
           QTUM_POP_VAL(__tmp1);0 A+ s  A& q9 y6 P' c8 V
           struct simpletoken_Send_Returns returns;
2 y5 s# |+ `( z           send(¶ms, &returns);
5 K6 G6 b0 N9 [( K           QTUM_PUSH_VAL(returns.sendervalue);- _: l. Y, S3 {2 A4 T# E
           QTUM_PUSH_VAL(returns.recvvalue);8 v5 ]( q% X  y* d) _& H, N* h
           return;7 K: `; G' l4 r% G
       }# y4 t8 V& k9 R/ h! D! g% _
       default:) _6 Y! o1 o$ a& O! E+ a
           qtumError("Invalid function");
0 L7 X7 U8 ~& V" R# @           return;1 m3 r% [. N/ W2 O5 B
   }2 K) {6 g0 y0 W. p! N( k
}/ x2 B- i& s" I( Q% d
//format for this:
  D  Q) s5 D: Y  n//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
4 X- L* o, P, s' s/ Xstruct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
+ |+ P% Q5 n8 Y+ }5 S  V   const struct simpletoken_Send_Params* params,8 n  ]% g* J2 h( s4 C" H
   struct simpletoken_Send_Returns* returns
' Q6 S9 V+ m2 B; ~7 s   )4 U" d8 |9 B& X" h, _( w/ T# d
{
2 y! ?  }9 ^7 X" Q2 r4 ]   if(__gasLimit == 0){
9 R% Y3 F! U9 r6 d1 @       __gasLimit = QTUM_CALL_GASLIMIT;
( h! r4 f* c0 q$ m   }  w0 e4 u5 [- b$ l( n6 ?) y
   qtumStackClear();
, a! J6 j/ [/ V9 q6 p   QTUM_PUSH_VAL(*params->address);* T7 t* ]3 F7 E! B2 d4 R0 f
   QTUM_PUSH_VAL(params->value);: p& N3 ]* E, e5 N
   uint32_t f = CONTRACT_SEND;/ A' Z: C( L" W" O7 ~
   QTUM_PUSH_VAL(f);
6 s% a. d% Z3 W% j- D" @( `   struct QtumCallResultABI result;1 P3 j0 c+ Z* q  ]3 b
   qtumCallContract(__contract, __gasLimit, 0, &result);9 ?' Y9 c2 i* X# v' J% e
   if(result.errorCode != 0){6 Q) U: ]* P0 e& d) T: r
       return result;
9 L& F3 y/ l' e; V: n! i; e   }
: a& |0 q4 T) z8 Y) d: r   QTUM_POP_VAL(returns->recvvalue);
+ p, J$ g6 P3 D1 b0 e5 L   QTUM_POP_VAL(returns->sendervalue);
& ^* w% p1 u* S9 ^' H1 y+ H   return result;8 d! q2 b! J4 y$ U( G
}
% ]3 \& [* ^3 c) A2 V) ?) ^/ h& x5 u9 v* m2 @' {1 S
其他  B  x0 {# \9 O
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨小公子君莫邪 初中生
  • 粉丝

    0

  • 关注

    0

  • 主题

    13