Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen
; t4 J% h$ a- H+ P+ ?4 R
, k1 Q/ O1 H0 u) l- @# W* u* C这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。* A. ]3 t& D7 W8 p9 w3 j* J9 z
0 K! u; b! f- A7 T
SimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。  ^9 u, }- ]. K& r
: z  J1 I" e6 ^9 N
abigen 可以以下 3 种方式运行:& N( s! `' ], w& Z  }7 Z) b
18 G& g8 l% W2 E/ Z* J# q/ `
Dispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数. p- G2 {4 l, v! u% l
2
( c4 x3 X0 ?* g7 GCaller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约
: r3 K9 }: L9 Q' j) D3: E( }/ q4 H) u! R3 J& z
Encoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约4 _3 G  m4 Z- q8 ]4 U  S& S3 r
% m" m8 Y5 \1 G3 P# ~7 W7 }2 P
与 Solidity 的区别是什么?
; m1 K; o/ Q# a5 F5 l/ `" H
2 q4 C1 S" @; ]Solidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。
" q! d. ]6 K& d$ ^8 i, g但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。: ]: d2 U4 |9 i; i* L+ l
" @  Q/ a6 y9 e  v2 F3 s5 f- \
我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。/ Y0 @; u. D( _7 Q1 v3 q
- W9 f" @" ?) y) o- B, N, l3 \
这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。0 t0 d4 q# Z$ b2 K
3 z) g# i# @( F: P6 n* d0 f5 ?1 X
与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。1 G0 m# N! j2 s/ O, V  S9 D2 t

2 m) B; S  f: h6 @" [这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。
6 R2 h% t! R7 V% u( R
0 E+ w0 t2 Z4 d  H* `# q/ b) g2 {) jABI 规范- ~+ E* V  z( `& V$ I

, |( J( O6 t, @7 F& l2 EABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
3 C5 J9 o3 l$ O& ]% v. S/ R! r类似 ERC20 的接口示例:
' x/ F/ V$ a9 uERC20Interface
" s! O: X8 o4 c- G# The first non-comment line is the name of the interface and used for all codegen prefixes6 n( D1 f/ ~9 C5 c! X: ^/ r
# this is a comment
1 A9 |  ]' \; ~9 BselfBalance -> balance:uint645 j" \! `4 N2 v, r( d2 ^
address:UniversalAddress balance:fn -> balance:uint64; H" x$ C' ]$ E, g
addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64
; ~% c1 ?1 o: O2 G8 Laddress:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable
! s( l% f% g. q7 Y- ^( E. H
# |( A6 [! y9 s也可以使用数组:; }* @$ e9 v/ r" \  ]' |
ArrayExample! r8 u* g# Y6 \" f
#declares someFunction takes an array of 20 bytes exactly
! U1 q. C; n4 e0 r7 V7 M  SsomeData:uint8[20]:fixed someFunction:fn -> void
9 w, C- i* Q( N; N#declares someFunctionDynamic that takes an array of no more than 20 bytes
( F5 G% `6 b( Q2 v! Y( h, f0 y. hsomeData:uint8[20]:max someFunctionDynamic:fn -> void" `5 W% w% n2 G) a, _
支持的基本类型:% ~/ q; M# y; X! Z! u, N! }
( l! D2 q$ ?9 _) i" h
uint8
# c- g/ [& w" e9 }7 B: R. I( Guint161 R" \& N! t+ k
uint32+ R- [0 {' X' l* l7 e+ u0 p
uint64, g& J9 M" {1 y% R9 e2 R
int8
0 W; \+ B. k; X$ T- K1 U0 o4 Bint163 o. l% Q* W4 R. F
int323 z( C' e4 J) m) W) v
int64  G% O& ~" `- @% a% W& u2 J
char" F$ |2 G7 s9 y% I5 V2 |( |
void -- 仅对返回数据有效。对应无返回数据2 g' }7 x; P5 E0 o, d- ^& U* R  Q
fn -- 特殊
$ y+ R3 a3 l, d5 }* H8 ^" A更高级的类型:
0 ~8 T; ~# M$ y( `* u, kUniversalAddress
) e+ E6 W' _( X$ H基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。
3 f5 ]" q2 b6 W9 _7 D数组类型:
, x) H% C- H  }$ R, O8 ?7 Ufixed(默认) - 数据必须是指定的确切大小% t/ g& \; [% B: M; R
max(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误
0 S* O- D1 v2 W4 V, ^1 G, F) e2 Mdynamic(动态) - 任何长度都有效(使用前 uint8[])有效3 N' K* x& D0 w! a8 w
clip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误! p% k3 p. T* F; s& j/ x% C
$ h% ~! B' c1 M/ s5 g8 ]- g; y' k) B
函数编号
& \8 D9 c& {* w函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。" g* D: {6 i" Q# U% V: ?
3 Q- B& d& D4 `0 w# T
内存分配
! g8 ?! V3 Q5 F% b/ m大于 256 字节的数组都使用堆分配而不是栈。* j; p' @9 }$ F! ^( \! f

% f" \0 V1 V5 l& Y+ i接口8 D7 @/ H6 v* X* S1 `! H
一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。
- z, A5 J9 D& P, }6 N包括其他接口:+ q! L! t0 f. V) ]( Z, a9 I
MyContract
  w+ F: ]  k: v, K  G& d3 U:interfaces ERC20, ERC721, MyParentContract/ u& D9 d3 \* Y; X" y& n0 n- C) C
abigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
! d- D- [4 F& g* p. Y- x4 Q5 V4 U5 ~: h# [/ z2 f8 b. _
语言
3 ]& ~* C" j; H8 X; N+ ]现在只支持 C. 之后会支持 Rust。
$ B5 m* U6 W; W8 @6 y- {! c示例(手动生成) C代码:/ o% i# r- }' G4 q( Z  Z6 c
struct simpletoken_Send_Params{
( L' k3 E! j" C   UniversalAddressABI* address;2 N. a1 q' H: v; Z" H
   uint64_t value;: V7 x- a5 I( [4 d
};
. M* M7 o. P- `6 H# G; ]struct simpletoken_Send_Returns{
6 D/ n3 D' Q8 a6 U3 s; h   uint64_t recvvalue;6 ]/ Z/ k% Q9 h. J+ j
   uint64_t sendervalue;
2 I. D( @2 Q' R) U6 t6 t- C};$ |1 x& ~- a, n" h
void decodeABI(){
6 |1 n1 v) d$ u$ ]% V7 Y   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
3 ]& B# K0 K7 T   //format: address:address BALANCE -> balance:uint6
: z$ B. B. H& H/ d8 a' P   //format: SELFBALANCE -> balance:uint64
% {) s8 I) N0 d   uint32_t function = 0;
  \- x* N$ v5 @7 I/ o% I4 H   if(qtumStackItemCount() == 0){# T- x& ]0 ~8 t7 y% ^: [
       //fallback function...
4 {7 _. U4 Y& Z/ _* R" a   }- g+ @5 `* X) t, S% S
   QTUM_POP_VAL(function);0 u3 M# V3 v9 F9 N1 C
   switch(function){
$ c8 |8 P& e$ N9 A) f$ J       case CONTRACT_SELFBALANCE:
) g/ b% F* d/ G9 E       {; K! D6 @# d9 o% p
           uint64_t resBalance;- O9 n+ }( t/ i, Y# v: H1 P
           selfBalance(&resBalance);6 d# y) @0 c4 x
           QTUM_PUSH_VAL(resBalance);! N$ Y3 _5 }7 {- ~
           return;/ R, n- L( Z$ i; j+ }7 S
       }. j8 w  }; E) j8 Z/ @6 O
       case CONTRACT_BALANCE:6 H: W3 C5 {4 i8 k2 B  d
       {
+ u7 s# b7 J( e! B           UniversalAddressABI address;
' X; H7 f0 x; p# w6 N5 J5 R% k           QTUM_POP_VAL(address);
" g& Z' m. U2 _! _           uint64_t resBalance;
3 M* b* a) p# ^. V7 y           balance(&address, &resBalance);
) ], R8 L- a* L4 p           QTUM_PUSH_VAL(resBalance);! \8 N  O8 K4 }1 I
           return;$ E1 j' x- m8 E4 o: L: y$ o
       }2 F5 x- \6 M) g: h& ?$ a
       case CONTRACT_SEND:2 p6 }1 `( C2 }* q$ Y. H% W; U# u
       {
  X# X. c8 v, ^2 y* B' m           struct simpletoken_Send_Params params;) Y8 M$ t& K  n2 G" R
           UniversalAddressABI __tmp1;
- J6 k/ E4 K- i& ]1 B           params.address = &__tmp1;; q0 F' b9 Q- H. x
( A% @4 M! R) \  P, X9 ~
           QTUM_POP_VAL(params.value);$ n6 D$ \: e3 _- m5 R! o% v5 I
           QTUM_POP_VAL(__tmp1);
6 n8 }" Y6 E$ O  z; Y; V; s           struct simpletoken_Send_Returns returns;0 h6 ?* z7 _7 g/ f, Z8 ~8 U
           send(¶ms, &returns);
" j7 K  z; K9 `1 y5 W* e) L           QTUM_PUSH_VAL(returns.sendervalue);" k, {) q+ _) Y* f$ z0 e
           QTUM_PUSH_VAL(returns.recvvalue);
3 ]5 k( R- I* A3 d           return;8 y; g9 _3 L' w4 `5 R8 e  F
       }6 w% C6 }7 e' R
       default:3 B3 o; }: U" z* ~/ I( Q
           qtumError("Invalid function");
- |  W' t8 U' ?8 t8 c( I           return;0 J4 U' n5 y9 C3 U3 Q2 `2 L
   }) n8 l$ i( L: W/ l
}
( I4 R6 ?& E- U//format for this:% I# |' A8 V" X+ b
//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
# _8 M9 ~" P# e8 |, V) wstruct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
3 V* X6 x% L* i+ ?, F: g   const struct simpletoken_Send_Params* params," A& j; b: q$ V& H9 t
   struct simpletoken_Send_Returns* returns# G5 A' l% H" U9 K+ D; p
   )
8 b8 I/ U$ A/ J$ K+ \% A. F, }{
) I5 H+ ]2 Z( b! q   if(__gasLimit == 0){
6 ?* m4 W. |* f# d; ]       __gasLimit = QTUM_CALL_GASLIMIT;- H7 O8 b% c3 V% o$ a
   }# b' b6 a: m+ L& X, S; T
   qtumStackClear();+ n; G& `5 u1 I% x2 S8 d  ^
   QTUM_PUSH_VAL(*params->address);
& \( w# ^) }& t+ \7 V   QTUM_PUSH_VAL(params->value);& {7 `0 b$ G, p4 s/ P4 F5 k
   uint32_t f = CONTRACT_SEND;. F8 K8 ~( G2 R  D! W
   QTUM_PUSH_VAL(f);
8 f+ {) {8 E5 n; q   struct QtumCallResultABI result;/ }; C. ?' ]% \* b- e: U4 l
   qtumCallContract(__contract, __gasLimit, 0, &result);8 Z7 x8 y* C0 x2 q
   if(result.errorCode != 0){
+ b2 o' }& H6 G) K( {       return result;' u  R8 g: Q2 q- [8 I+ N! N
   }
6 E% ?2 r' t3 \+ J6 ]7 r   QTUM_POP_VAL(returns->recvvalue);
3 H5 g' o$ ?# E9 q  a$ s   QTUM_POP_VAL(returns->sendervalue);/ ]; @9 |. e; ]& I2 Y5 e  V
   return result;7 j; y; @7 m4 R" X: Z  c
}
2 L6 t7 Y' R" f" e. I
6 c3 D8 i  s+ a" c1 \/ J6 a. H. B其他
' g7 j, e$ N8 z% Z' [5 Y对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13