Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen
( c3 |. u; E, x% a
  `$ q( j% T" g1 f这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。2 _: n; O* i' t
: ^2 Q9 d  P/ w% m8 L
SimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。
' o/ ~- @# `2 c# b5 E3 I3 k9 O
  w: n6 {" F. l4 Q  x+ Nabigen 可以以下 3 种方式运行:
  Q8 F3 C, m2 l5 p: D  q9 B7 e8 ~1
  S, S' t: Q, ^0 \6 I7 vDispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数
8 V6 a( k& M6 `6 k2; H* W' Z: V; `% K, @
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约
3 m- [) L2 |, {* q9 m3
! t  l  {# h2 C# j' `( oEncoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约  u2 K/ x5 b- z& F9 `

/ b3 E, T& D  C2 d+ Q与 Solidity 的区别是什么?3 r  H' P' Z% _9 e# }
' |. y8 `+ a  J/ f+ ?
Solidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。
8 o/ M6 _- h1 i' S5 q7 D但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。5 f; b) q# t- V5 G2 J  ~' h/ ^! m
& T9 g3 d# q# c2 P0 u: b
我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。8 k2 y4 s2 [4 v& R. n- L

( H: }" g2 l$ p8 Q5 \- O+ s这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。0 h. I- L5 M+ R0 e( V

, i; [8 J) m) a5 {  _8 p) F9 c与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。6 [! F' C' ?% ]. I# T
5 \8 F: e0 }9 f) Z6 l
这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。
7 {2 r. P9 l# s6 r% l
7 @2 y. @( y1 DABI 规范
3 ?2 k6 P; c& q5 T+ U* d' n# ^% R5 R5 [- V8 y) b7 T
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
7 _$ ~+ A! G1 @3 ?类似 ERC20 的接口示例:
1 C1 i0 ^/ h6 F3 U5 r; b& Z+ tERC20Interface; U+ b  ?1 j4 V: P; V
# The first non-comment line is the name of the interface and used for all codegen prefixes* o; `/ r' M0 K, B1 R
# this is a comment
% O& d7 W, J  W4 j) a! XselfBalance -> balance:uint64
, h( @& J' I2 S1 N+ Uaddress:UniversalAddress balance:fn -> balance:uint64, h' d- V$ U% p" |8 ?2 o
addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64
0 H9 E5 M1 X0 Y# u9 R5 vaddress:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable
9 p6 A' W! K6 e
! c- p( Z& H* \, ~$ G# ]4 [4 ?也可以使用数组:
) H: _7 c& [9 U3 v0 {ArrayExample: [* c/ ?- f2 ]& |; ]6 {8 ~1 v
#declares someFunction takes an array of 20 bytes exactly
: K3 a2 L. m% ksomeData:uint8[20]:fixed someFunction:fn -> void7 S4 Q4 d* H6 m% H! m
#declares someFunctionDynamic that takes an array of no more than 20 bytes
3 R- ~- T& ]4 p6 P- i2 VsomeData:uint8[20]:max someFunctionDynamic:fn -> void+ |) E' z) ?( G8 e
支持的基本类型:
: f8 _6 @0 L8 h$ a. V' P4 K1 J
9 @% y+ A$ @) }( @: @7 t$ ~uint8+ u. W) F5 ^" Y" i6 r0 U
uint16. g# ^  q# M$ y
uint32  c9 c& `  T* R& X& [& t
uint642 ~! ^, j1 `% b0 e5 c$ ?
int84 E0 N% |8 k% J4 \# }
int16/ j. ?0 F9 d' I  T
int32% y4 a( t8 e; l
int64
2 n% a+ L% W+ vchar. V% P+ c' B7 p. ^
void -- 仅对返回数据有效。对应无返回数据6 f8 |  M: r2 v* z. L
fn -- 特殊
0 |1 {9 L- J6 V6 @9 N& `1 }: d- X2 ^1 J更高级的类型:
- c3 q! n0 u3 U2 rUniversalAddress
+ w6 Z2 S1 G1 J2 k8 D基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。9 Q0 r6 V! @# f
数组类型:9 `8 o* _, n! }8 X. Q
fixed(默认) - 数据必须是指定的确切大小
9 F. c) M+ c0 x6 E1 Kmax(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误7 T/ i8 r2 x. J- |) ]
dynamic(动态) - 任何长度都有效(使用前 uint8[])有效
6 T- S8 u& ?  O, pclip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误" f" r5 e* m$ o. B+ r2 X
; q1 u& c, W9 P0 a. ~( b$ Y0 g
函数编号
2 m2 F: J/ J3 E9 S' p% \& n函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。
! V- r% y% `! n  i9 r2 j" i1 K7 d
* l" b5 k7 B+ n4 y内存分配
2 \# c7 y8 A' y' a: O' s% u大于 256 字节的数组都使用堆分配而不是栈。
" t/ I8 _6 i- C/ k/ ^3 v4 n" m- Z) L% i  g# o% B
接口
0 h: n. e( `9 k( \+ \1 h! e( w一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。
9 C* N8 u* q& [! Y! R* [( Q  A包括其他接口:# H8 M0 Q! W% H( F! u5 ]2 ^- Y
MyContract
, i5 p, X* ]3 m:interfaces ERC20, ERC721, MyParentContract
+ L9 k2 `7 t( `6 Y0 [$ Oabigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
: w) Y( P3 A. l0 \; z, ?' D
1 g1 r. M$ r6 r+ [- b* ~语言. {( ]; u# _" d
现在只支持 C. 之后会支持 Rust。
5 ]( p6 e; x* E  I* W& ~* u示例(手动生成) C代码:  |) X+ M6 t3 I
struct simpletoken_Send_Params{
$ ?/ f3 L  m! b; ^+ f3 e1 G, |   UniversalAddressABI* address;
3 |0 t$ a+ G3 Y2 ]8 c   uint64_t value;; I( R6 q! q; R! P7 G! d
};
" }# j- B, m! A# xstruct simpletoken_Send_Returns{
1 B2 U" [8 m+ r! N6 M* h* g- f   uint64_t recvvalue;
" c# u7 v6 U' \0 n6 q6 ^$ e. ]; e   uint64_t sendervalue;
7 H! u: r2 N5 @! G2 K};6 T' |( L4 O: B8 E3 m8 n3 @% j
void decodeABI(){
8 R1 c' v, x5 q+ |8 H2 ~   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64# x" y. k$ p2 _$ g* H+ `( l9 T
   //format: address:address BALANCE -> balance:uint62 N, v$ ~- r0 x1 }
   //format: SELFBALANCE -> balance:uint642 S/ x7 M$ L! d
   uint32_t function = 0;
9 f- d  c) G' y$ h% V9 x" E   if(qtumStackItemCount() == 0){
7 r/ U6 M. z! D! D1 {2 ^  F  O       //fallback function...
2 J/ i4 V4 }# ]   }
$ Q2 w/ E) X$ C' K& Z* M3 u; p   QTUM_POP_VAL(function);
6 Z8 i5 ^0 n+ r7 V1 ^/ X   switch(function){8 E3 e4 U) T+ x6 Q3 M
       case CONTRACT_SELFBALANCE:
' {" H8 i5 X- I       {5 r# Y8 n) i8 [: C
           uint64_t resBalance;
6 }) j- g7 L/ |- H3 a2 d, c* q" \! w           selfBalance(&resBalance);
: `  p7 `8 D' N. y  d4 P           QTUM_PUSH_VAL(resBalance);
. l$ k" |! @/ E* p* ~% M( [           return;+ p1 n) e* [5 u/ ~: U" S9 v. b7 p
       }9 i( \  H# W0 `- ^  ~7 F
       case CONTRACT_BALANCE:
1 Q' O) B5 b' Y0 T( E       {2 b* `4 i1 q. m& @2 S7 t6 x+ H# S
           UniversalAddressABI address;4 p& J" x& v# M) g$ W2 b$ E) O
           QTUM_POP_VAL(address);
+ `5 w1 [, _3 l8 u7 }1 K           uint64_t resBalance;
' k7 U* c. E2 X6 b& O: g: \6 A+ ]           balance(&address, &resBalance);/ Z' q& U; E6 N8 v/ I9 p) r
           QTUM_PUSH_VAL(resBalance);
0 y2 L9 A: v- Z. N: N) O, u7 K: h           return;0 n/ y/ Z; K2 Z2 x
       }" G5 Z: D" y7 \5 D2 u* l
       case CONTRACT_SEND:; f5 ~! Z# v# X8 l# w, m
       {% X; _- _: u/ b: [
           struct simpletoken_Send_Params params;
4 a( i  t& e3 r- l& l. d3 U           UniversalAddressABI __tmp1;
, V4 b3 B' ~  I; I" n* m+ \6 m           params.address = &__tmp1;
7 b" ^0 N6 M# A; D/ L% _/ L& ?- `1 H, J& ?
           QTUM_POP_VAL(params.value);
: t, z. q' x- _( D+ d6 f* F) ~           QTUM_POP_VAL(__tmp1);
" o0 \. E% E* y' q7 L  A1 x& P           struct simpletoken_Send_Returns returns;. b' A" Q7 {0 W+ e! n( Z
           send(¶ms, &returns);
3 ~, Z6 q4 W8 r% s9 O( y! C           QTUM_PUSH_VAL(returns.sendervalue);
' O4 \, j" [  C6 e5 ~: O5 B           QTUM_PUSH_VAL(returns.recvvalue);' h1 Z4 U- }$ t
           return;1 j& N- }9 C: ?  {: O1 Y" S. Z# H
       }, k/ ?: P1 g9 o8 e2 |2 k
       default:
1 z/ ?' S$ E* n. L' ]           qtumError("Invalid function");% i8 c$ K% m; J6 s6 ~1 M( ^
           return;
( Y/ K2 B* ?5 K9 R" R/ H& ?   }+ g6 d% G  Y2 C" h6 _( `
}
9 V# s2 O  a+ [" o- L. }//format for this:
/ b3 F, a. e2 D. U1 v5 L$ T$ h//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint649 m/ b% U9 ~' X4 f5 c' F$ f; T& r
struct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
6 B( {/ C" J3 d3 O6 M3 t' [3 \+ [   const struct simpletoken_Send_Params* params,* @: k2 W! r# e: z0 Y( K& Z
   struct simpletoken_Send_Returns* returns
3 A' `) |9 K1 z+ Q   )# F, ^, t' V: Y- s
{' g$ J/ K6 h+ X" s# F
   if(__gasLimit == 0){
- c9 v- B  w* r& O: I) l       __gasLimit = QTUM_CALL_GASLIMIT;. x; S) T% a2 @/ ~& \- g' b
   }
+ I0 e" x8 o6 z   qtumStackClear();
  Q+ h# a9 K% t( }) D" |   QTUM_PUSH_VAL(*params->address);' g5 G$ T9 I, F9 s2 H
   QTUM_PUSH_VAL(params->value);
* q# ^9 I3 e$ k9 v- S   uint32_t f = CONTRACT_SEND;
3 U$ D0 l) l. G3 O$ m  O   QTUM_PUSH_VAL(f);
& ~% b* j4 W' ^/ X  B4 P   struct QtumCallResultABI result;  ^5 W# X* I2 r! L6 k
   qtumCallContract(__contract, __gasLimit, 0, &result);
' n, p3 [- Q% B3 i3 L   if(result.errorCode != 0){5 G. {# I+ |6 Q( T% J2 s0 I
       return result;1 s4 H% B/ e: Y) |9 m
   }
( z* H# u2 j5 F" l   QTUM_POP_VAL(returns->recvvalue);  G! A2 ~6 x% t* N: Q
   QTUM_POP_VAL(returns->sendervalue);, l4 {6 \) d+ B% ^0 B; P5 }2 C
   return result;
$ }& z9 e6 h" p* C5 m, N}
7 p: [* \2 Y5 f3 U. [: t0 ]+ e; X; ]( w- N0 C4 ]
其他6 J) @' d8 M7 \% w" s2 _, m0 G
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13