Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen
3 t3 ^( Z, A7 j% h+ S2 x" l1 g/ G. O3 j# X! j9 {" w- q
这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。2 n1 Q. T1 H; ~: L& e

  O3 D% q4 P) x4 V# {SimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。$ G- d! O/ _0 d
. L. [9 t- Q. B
abigen 可以以下 3 种方式运行:
* v$ P) b1 r5 |  S; ?* w  C19 {' k9 q2 Z5 G# h% F0 X
Dispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数
1 C4 a& P! h) g! \26 o% L: R& O6 b
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约: v, o- ]( J9 m% n3 H
3! G8 @) W. n$ a2 A. j6 F0 \0 R7 |
Encoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约
- N0 w; W  c/ U# I) e$ j5 [4 T$ U+ w5 f0 Z8 r$ V" `
与 Solidity 的区别是什么?
. D/ S4 Z% L! W
7 Y; K) X5 k0 Y( s8 `Solidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。
; ~' R" k+ ~: f9 ?- ]但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。
( E) I& ?% B* ^* R. O  ~4 A9 h, v- m9 O/ J. ?" W
我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。
2 A' `. N' V' F
3 B1 y, \7 x, \0 h+ j/ P, N9 R这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。! s7 f' u2 u3 A: z% P

/ Y0 r! \1 q  z( [" C与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。6 v& l* R1 g* r' E6 v4 w0 a
& o; t# ]/ Q6 v8 e: ^
这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。
  L* r9 O+ o; }1 G! i$ \; e9 _% ^5 E" ~6 C6 }2 J1 w( E! ?9 E7 D
ABI 规范
& o4 u, n6 N7 u0 `  x- s3 d# C+ E  Y' x) k! R$ b6 S' A! J
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
* t% j) E3 V$ K9 F( F! J, H类似 ERC20 的接口示例:
& U8 V; T5 r, ]: u+ y: GERC20Interface
+ ^6 X9 @2 x, n# The first non-comment line is the name of the interface and used for all codegen prefixes7 j' E5 b) W' b- I& p" ^6 k0 K
# this is a comment9 c1 {2 y; a( o) U5 V0 y
selfBalance -> balance:uint64
" o) x5 o0 A$ i" {- |4 N3 _) `address:UniversalAddress balance:fn -> balance:uint64
, T8 t% R) T  r( @  SaddressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64
% ~8 J+ X% M) O- a( ~- Gaddress:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable
6 n! J* ?$ _+ V9 C1 H" X" u; r
* o0 H& F0 F' B也可以使用数组:9 Q( ^6 @: O4 Q8 c
ArrayExample
( f6 q9 m. x" ~8 c: ^+ [#declares someFunction takes an array of 20 bytes exactly
0 k4 H* w4 G6 b( Y* @: x- E8 esomeData:uint8[20]:fixed someFunction:fn -> void
9 k5 M5 s8 X- f#declares someFunctionDynamic that takes an array of no more than 20 bytes2 e& V& z7 i1 s% [3 l8 S9 ^
someData:uint8[20]:max someFunctionDynamic:fn -> void$ n* O' g  P: L# r8 @6 s0 K: x4 x, ~
支持的基本类型:6 I& {6 o. x# _+ Q# _$ L, `( W( q
3 m2 w1 X& n& V3 c* N
uint8+ H6 M; @5 T, b# j8 s# R. S' Q9 R
uint16
* ^8 T5 |" K3 b) s3 cuint32' E" b* {0 K8 e+ F/ N! X9 H
uint64% {: m- |% W+ N* a3 y
int8, G9 x- l- w, v9 X; h; |4 x. I
int16
" L8 x0 d  Z. }: Zint32; U3 b: e$ |/ @
int64: d6 |3 P4 H3 B5 x4 L5 ~
char4 w5 K/ r$ E3 V  F7 ~" s/ f5 w
void -- 仅对返回数据有效。对应无返回数据. b2 F. @0 A* U. `$ U6 w
fn -- 特殊
' ?* \" P  g  d5 A& ^2 a3 R更高级的类型:
7 X4 o5 |& d# q) S; D3 CUniversalAddress; Y- Y' Z3 w& w' l5 l4 I, b" u
基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。* n4 Z1 c9 I- }4 A9 j7 H; S
数组类型:
2 W6 G5 u! Z* J+ u# _" Sfixed(默认) - 数据必须是指定的确切大小5 R' }/ d- w( ]+ ]% F0 m
max(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误
4 ]( _$ N( u7 i6 P1 L8 ?5 idynamic(动态) - 任何长度都有效(使用前 uint8[])有效
, w: b1 P' A% A* X! v4 yclip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误0 J" Q6 k9 o6 ?" a# D
& `* }9 S% K6 c; W4 U
函数编号
% e- m  S! g7 J函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。
( `4 e+ O% B) H/ [8 C5 }1 e
" r8 S/ x7 o+ e# R2 w内存分配
% n/ n  M; w/ r  h大于 256 字节的数组都使用堆分配而不是栈。
, n8 q4 ?% m# C; w+ P
: q* R2 q) ]: W8 D接口2 g: w$ S6 e) ]6 x
一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。
  e' q/ B" l( o7 K包括其他接口:
8 _8 c% _: I0 ?7 p  I% O! AMyContract
5 M7 q9 }" |$ Y9 F* w8 E( C0 j, C:interfaces ERC20, ERC721, MyParentContract3 e2 \2 v& j+ J  b" z- c' ^9 x
abigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
" F, X; e$ T+ B- g& S+ K7 p7 s0 O
语言
- ^3 L0 B) t' `7 ^# ^. J6 d现在只支持 C. 之后会支持 Rust。) b& v9 F7 ], h% M
示例(手动生成) C代码:& w# l5 `& M0 m4 @
struct simpletoken_Send_Params{/ `  u6 p( j7 Y
   UniversalAddressABI* address;
/ d1 [2 S' Y& h3 O* T; X1 ^  }* W   uint64_t value;6 {1 J: z2 f0 ?$ x% ]6 G
};
" o: d( a9 N* s+ E, |. M5 K- _; lstruct simpletoken_Send_Returns{
, H& z1 S3 i: a- Z. q   uint64_t recvvalue;. y% `8 G7 [* T. M
   uint64_t sendervalue;1 H' p/ _; p; C5 K  t; D
};5 t% x; t+ q: s+ b+ `6 J1 W
void decodeABI(){
0 U9 y7 N  z8 A' f9 L2 P- W/ }   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
. [5 ~% N2 M1 `" m   //format: address:address BALANCE -> balance:uint6
2 ?  k. }8 f* l   //format: SELFBALANCE -> balance:uint646 p8 \, C5 J& V1 V
   uint32_t function = 0;+ p7 o; c8 g+ V! |: G9 ~
   if(qtumStackItemCount() == 0){: Y( p, v6 b3 d
       //fallback function... ) P# u  L; g& I
   }
- f2 [- J( ]4 W/ ^1 Y# s   QTUM_POP_VAL(function);
6 e+ L, p! B! U! `) L$ t9 E; s   switch(function){3 a, J9 W' `* @8 [& @% P: u+ n
       case CONTRACT_SELFBALANCE:% V" |% G# p  {  \6 {& K, P
       {
' o$ B5 s8 W* J( S2 ]' U9 z9 n           uint64_t resBalance;# w( y. I7 `: s7 }. S
           selfBalance(&resBalance);; X" s+ @0 O- R5 |  y
           QTUM_PUSH_VAL(resBalance);
' |' _3 f) o2 l3 {9 Z& M/ v% @           return;
! e+ c; P: r) ~1 L/ ?       }% O/ S( }3 Q5 F, a# [3 \
       case CONTRACT_BALANCE:6 f' ]0 E" U' W3 ^9 t
       {
; {9 z" f9 Z: A2 O- L6 f           UniversalAddressABI address;
- j$ K6 f) \& }& G9 {% C" M0 `           QTUM_POP_VAL(address);
# j  x6 m+ _. m           uint64_t resBalance;
  m3 `& S, J  W* X2 x9 C           balance(&address, &resBalance);
) M' D$ R7 b, Z7 h           QTUM_PUSH_VAL(resBalance);
% w/ G  G) e8 b. @" Q# u           return;2 B6 V' B) l( V) X$ k* b
       }
3 j( T! u# B0 Q1 \# t6 U       case CONTRACT_SEND:
3 k' H/ {, }/ Q9 A2 P' u       {1 R" M, i1 H- ^
           struct simpletoken_Send_Params params;
0 f( O/ @* j- f1 m  C! y0 S9 G           UniversalAddressABI __tmp1;
9 J/ }6 K$ X" L% _9 e. b           params.address = &__tmp1;
  `: p0 y, ?8 x! b3 C0 a5 n" P8 P" {4 h2 C
           QTUM_POP_VAL(params.value);* N# Z  ?- t3 v0 w! j; x
           QTUM_POP_VAL(__tmp1);; {& \6 s7 L( E. c6 W7 v
           struct simpletoken_Send_Returns returns;- ]* c/ `4 g& v
           send(¶ms, &returns);/ |% p5 r3 a( {  N) _5 ?$ v
           QTUM_PUSH_VAL(returns.sendervalue);
' u+ b* e1 Z( j- G           QTUM_PUSH_VAL(returns.recvvalue);
4 |! \9 ~* K  E( t           return;
, L5 X. P2 V0 u6 l, P       }
3 l; A. ]$ p$ L0 s       default:
" o7 ?. x- u8 |. W' A' W& B           qtumError("Invalid function");- O7 r/ Y! n" l$ O6 ]
           return;* @( Z- J3 t2 n( v) a
   }
. T  W; Y$ y1 @+ |, r}9 x4 ~) v$ k% D3 h. `
//format for this:6 X3 p# z  Z: \; S1 Z7 {, m3 k: r
//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
* m+ m3 T$ g5 \9 {8 {& ?+ e1 Nstruct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
' l8 K8 L. T* X6 f2 j. W( h& y   const struct simpletoken_Send_Params* params,. I6 o5 w4 y8 x; u7 V  Z6 [# V) q
   struct simpletoken_Send_Returns* returns
; k' z+ a+ ?( D# W, m3 H   )
; Z4 d2 }" ~6 t' N, y; \: K{4 s! P' V+ n1 L0 _- ^
   if(__gasLimit == 0){  o" J/ w8 `7 N5 G" }1 U! m8 n
       __gasLimit = QTUM_CALL_GASLIMIT;
$ _3 ^/ @* n- B. Y- ~   }
2 q( z" R" b1 W4 V- W  O   qtumStackClear();1 q. f0 T( o# o3 O  S( G
   QTUM_PUSH_VAL(*params->address);  H+ _3 f! i  y+ m5 B- Z8 h
   QTUM_PUSH_VAL(params->value);% T/ G7 L6 F+ c9 g- ]5 C
   uint32_t f = CONTRACT_SEND;
) B8 }" k/ B1 q5 k   QTUM_PUSH_VAL(f);
; \! x. g8 R, b; I$ {, S   struct QtumCallResultABI result;
0 D9 X1 _7 c' F: ?; _   qtumCallContract(__contract, __gasLimit, 0, &result);0 Q" W# x$ T+ b3 d8 b
   if(result.errorCode != 0){
9 D8 O5 M6 h1 @7 L, L& M       return result;. P/ l' l- b2 r) N- H
   }. J3 H: }! Y9 I( E! n$ K% c
   QTUM_POP_VAL(returns->recvvalue);
/ z$ r# L  t2 q$ o2 I3 E9 x$ m- k   QTUM_POP_VAL(returns->sendervalue);/ v3 t3 x! v2 b& [) X
   return result;; h4 ~- f4 @6 b& d4 J
}
2 M8 m% s3 R# J0 ]" L& [/ Y0 [* u9 \& x, Y+ L4 k
其他. o* t. T6 D' I( h- \# ^
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13