Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen
5 f1 i! [0 i. d2 h# N, M/ f2 o
7 {% Z$ Q" a$ A, X这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。+ A5 f1 [1 }; N- H1 m1 m
: r. a: p, L8 _2 T% S: a
SimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。" n* U- H9 C+ _, H. q% n# G

% \' ^* u7 Y  ^* b7 Mabigen 可以以下 3 种方式运行:
" D6 P$ e( G. b* b1
, k' l, k3 z! a1 X9 X/ \5 H3 j. I+ G. uDispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数
6 ~5 L: M0 y  k8 q2# I& b* p* L% X: S# C( H
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约
2 j: E' C2 x* K6 Q# i39 [4 p! s' k3 h0 `: T. e
Encoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约0 h* B8 x) m6 G* W6 b  Q0 L! g
: r- G) N" T. u0 W  k1 z; A6 r
与 Solidity 的区别是什么?/ A& R2 k0 d" @- N& M; ^2 L7 k4 j

6 t0 X$ r5 H3 ]7 `* E1 GSolidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。
. t8 H8 h. l: w1 w( I: M. u但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。
% z* S& r( |1 P9 Q( c. F
+ m9 W& q  h' h" G我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。
  L# }: m. Z2 a/ {9 m* Z  r/ ]" F3 u: Z
这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。$ ~' R" I4 m8 j- z1 E
9 n2 @3 }# k& a& Z7 O5 N
与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。* d  [. i7 J$ }- Z; c. X
# E' k& }. c) _9 |
这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。
, G, \. {: U8 M4 \0 R/ j! a1 k* K) s- [: R) f* r9 L3 ?+ ~8 |5 M
ABI 规范
* ^# P0 @, g: U
/ Z/ f; j/ b, J! TABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。; z$ v9 i9 v  _) x2 m  @0 U! B
类似 ERC20 的接口示例:4 G" Y$ T# P" _
ERC20Interface8 v, V: R5 Z' b4 m
# The first non-comment line is the name of the interface and used for all codegen prefixes1 n; k% ]- r# M$ a; l" S# h3 i
# this is a comment
% Q8 w* ?" `" J0 t: ^. x! _+ {1 ?selfBalance -> balance:uint64
) m) ^/ V9 n1 Yaddress:UniversalAddress balance:fn -> balance:uint64" t; I, N3 q( j
addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64
( A7 B& o4 _  S1 ^9 jaddress:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable
6 E5 r0 ?8 M8 d2 B1 g& B% }$ ?3 b% r3 g" k& }
也可以使用数组:. A( b; b( h# A$ h
ArrayExample: ~6 b; E# A2 Q5 B5 C" S+ H
#declares someFunction takes an array of 20 bytes exactly
5 {; h0 c2 r: o$ `someData:uint8[20]:fixed someFunction:fn -> void
" C" W; x  c/ D8 u6 e- s#declares someFunctionDynamic that takes an array of no more than 20 bytes8 |* ^4 Z' }- F. D) c$ ]
someData:uint8[20]:max someFunctionDynamic:fn -> void
( J% k' _  z& T  p$ K" W' f支持的基本类型:5 Z; Y+ b# R* z% P

8 u" W4 R( t/ L* x" Vuint8; m) Q9 E2 {, X8 @
uint16
( i6 a. [  k: u* K/ N5 `uint32
- G' G; V) u4 u: T8 w- L3 juint64* U3 t. N' k2 x/ ]1 T# R
int8
- G, l, M0 b3 [5 cint16
8 d: o9 J9 o# D' iint32
( F1 T6 M- \2 _1 c/ h! b& E5 _int64
/ t/ [- r0 W" v9 Schar# u6 G( I* j3 b1 p
void -- 仅对返回数据有效。对应无返回数据
4 p8 ]; S# Y  |; c5 O4 q4 dfn -- 特殊* s% f1 k) x0 x& e
更高级的类型:
8 i- u0 X& e4 T6 a, R& oUniversalAddress
4 Y1 }% h- F; d9 J5 a4 L- O& W3 }基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。! U" W- L1 q) `7 {- K
数组类型:
& G# I  x5 j& x9 Gfixed(默认) - 数据必须是指定的确切大小2 t! D" q# B! I! Z* ^8 r
max(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误+ l3 w! Y/ r# n$ o, o' \  z
dynamic(动态) - 任何长度都有效(使用前 uint8[])有效
- [  C' v* E0 Z, c2 t5 ~" G8 cclip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误
# I4 G& r* F, a" V8 H
+ ]/ Q8 ^; W% e& J; ?/ a函数编号
" f2 E" j8 z$ P6 z函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。* r) ]5 h+ a4 j' i/ B7 @  e
% [& q" P1 w+ B* M# u4 B, a0 g8 Y9 J* C
内存分配
7 }9 ]7 w( M/ S, d6 g: y大于 256 字节的数组都使用堆分配而不是栈。
6 B+ C) G& r0 I% n0 B7 I6 o. T# W4 k) Z1 p: |- ~' T7 Q
接口
( x- r9 u& n. z+ L. V3 o一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。
" Q+ \6 j  d. |% x; q包括其他接口:
9 U; p  d  n# L% ]4 dMyContract
, M% W9 P  g. |/ q) z:interfaces ERC20, ERC721, MyParentContract+ c0 O- H- ?& o- W
abigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
7 I' e/ R. f- A. T* f
; s6 N0 M% t: [' |* G5 l( {语言
* D* f$ T! m. \3 H8 F. I现在只支持 C. 之后会支持 Rust。
$ J0 m% f' t: ]2 r  G5 F& n" M0 X示例(手动生成) C代码:& O/ H: r5 h! K- ?* Q3 X' _
struct simpletoken_Send_Params{& i( ^2 D: S: X8 E% [5 |0 p5 D
   UniversalAddressABI* address;
6 @4 u4 N- A* L' Y+ }4 Z% L( ^/ o   uint64_t value;/ g/ k8 j& W2 f: m& o! {
};( g& _( R* o0 e- P% p+ `5 w
struct simpletoken_Send_Returns{0 q7 y" P' l. Z( t
   uint64_t recvvalue;6 g/ [- q! _( c8 i
   uint64_t sendervalue;
% F: i9 l: d, M) w, F};
/ A: }! U' J/ _# b( ]- Ivoid decodeABI(){. ?" C6 k. {# a; S2 X+ g2 `
   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64# w* @6 D* L3 Z* N+ N
   //format: address:address BALANCE -> balance:uint6" X# U" B7 e! t! n9 `; h
   //format: SELFBALANCE -> balance:uint64' O6 Q6 p. t  ^3 w4 X, ~
   uint32_t function = 0;
0 Z. w6 c) H& J# i! O   if(qtumStackItemCount() == 0){
2 t+ `. C9 Q4 [1 z       //fallback function... ( m, U0 k& f4 c7 \; y8 M7 ^
   }
' O0 e2 a( Z# \) m2 U   QTUM_POP_VAL(function);* y# l9 E; N( D% X5 r
   switch(function){
4 j/ C' G) p! p; w. k! j       case CONTRACT_SELFBALANCE:
  K% j0 x  I) Y, m       {
' e( q0 |! ^3 M0 y8 C4 }           uint64_t resBalance;
! U- t- E* M3 M           selfBalance(&resBalance);
! U, I. V8 v% w. j# v           QTUM_PUSH_VAL(resBalance);
6 T, r4 S* m1 y           return;1 U7 b0 Y9 _) l+ S/ m: s0 U/ r6 j
       }
  U; B2 E0 v' x6 f, t       case CONTRACT_BALANCE:
0 ]9 H$ h! Z( a( b       {
3 x. G0 d; l* E/ ?2 ]           UniversalAddressABI address;
. @6 r0 f1 h( i) m, C           QTUM_POP_VAL(address);
7 B- F# O( k" T& S3 c           uint64_t resBalance;
5 F1 @$ D* ?1 d% I           balance(&address, &resBalance);
" ?# Q& [; L( z8 S1 e" y. @- U           QTUM_PUSH_VAL(resBalance);+ [2 z* [  H  E3 A5 b- m" k- w
           return;8 y: t5 E5 n3 T8 O  o
       }9 A4 k! S% P- ^: J0 g" @5 f% N
       case CONTRACT_SEND:
1 r( _9 B$ I) _3 D- S9 y& M       {
1 L- [1 t- K2 s& B. ^  U# j) P           struct simpletoken_Send_Params params;' G6 w0 f4 ]3 D8 u1 B
           UniversalAddressABI __tmp1;* [' S5 W; s- w$ a' [; J
           params.address = &__tmp1;
  ?% F6 w( A/ g* p6 W& \. I/ S2 z; @2 [' u  ~$ t" m7 c
           QTUM_POP_VAL(params.value);6 x* m! H" w% s' U7 e1 |/ _1 x
           QTUM_POP_VAL(__tmp1);) ], b7 X0 G: k
           struct simpletoken_Send_Returns returns;2 o$ D# A5 J% D/ F% l: N: G$ F
           send(¶ms, &returns);) O& f  W) o. U# R
           QTUM_PUSH_VAL(returns.sendervalue);
9 Q' p6 M. Y4 ?/ t           QTUM_PUSH_VAL(returns.recvvalue);
+ |# _# l) G0 C+ U           return;+ A6 ]( S6 a7 J9 {# n, J/ \- N6 n
       }
/ ?2 W: D# @- [       default:- Z% e/ B/ `8 ?' C
           qtumError("Invalid function");
0 r; }" O3 o  ]/ K  [9 ~           return;4 _7 ]+ g" }' Y! X
   }( u! C4 F* R: o( x0 X- @! u0 a
}; _& P5 }2 d' R7 M1 \# \
//format for this:
% F& e" H- ?6 s: T//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64$ n3 g2 R+ Z7 K/ K/ E* v' F
struct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
! o" X; ^+ u$ R* {/ \5 {/ r   const struct simpletoken_Send_Params* params,
/ K0 v# E- x$ U" W0 J   struct simpletoken_Send_Returns* returns0 V" }* F( J' P5 x, E- J6 H% e
   )1 ]9 X: X! x- Y- M2 f
{& A' x# A* i, T# P4 p. Q+ M
   if(__gasLimit == 0){
9 s: v- K+ `. g" I6 I" v% [7 g& s       __gasLimit = QTUM_CALL_GASLIMIT;
' y0 N" m8 U& h+ X( @* n3 M9 t   }4 n. ~0 B7 {9 o# n! |6 E) v# @
   qtumStackClear();1 M* X7 K  t( U# {5 m9 |
   QTUM_PUSH_VAL(*params->address);
0 B, k0 f; W- A. S0 C/ U   QTUM_PUSH_VAL(params->value);
2 H- M) X  j( ]   uint32_t f = CONTRACT_SEND;8 B9 X1 ]. X4 u8 x
   QTUM_PUSH_VAL(f);
- k, g+ `$ ]2 x) U$ E) N/ k- Y# @   struct QtumCallResultABI result;
* F' W$ _& P/ }6 Z2 J) b* B7 g8 G   qtumCallContract(__contract, __gasLimit, 0, &result);
0 O! G& [$ d/ a   if(result.errorCode != 0){: {' J: G4 m2 U5 S
       return result;4 W. R% |' }1 }5 g4 r
   }% k) q" u0 b. ~7 p% v: {
   QTUM_POP_VAL(returns->recvvalue);3 k* _( H$ T" {' D7 [* ?4 t2 H
   QTUM_POP_VAL(returns->sendervalue);
/ n$ _+ D" Y: g1 ], F   return result;
) ~' f5 }6 T6 s/ Q}
& x+ E0 p. ?4 {- M$ _9 N" c( _- W$ C! O3 n! U/ F  J' |  o
其他* R' q  x. R" n1 P; V, D
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13