Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen8 g, ^: d9 V0 ~% W

1 g0 m- B7 q% [# o3 ~3 _/ x这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。
& [' P: W6 z" W  M/ x" |7 w
* p* |" s" a. M. WSimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。
- R* a8 U3 u" H% q( h
4 o3 v$ @% }1 _) x% Babigen 可以以下 3 种方式运行:0 C: X, q  T2 X: r/ V. Y0 b
1
3 f# N: @" ~" z7 U; t% _Dispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数
( m  r1 i- W* s- [" C26 u2 a. v. d. r) L3 c3 j* G: n
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约
6 o9 \% [+ {0 \* |2 Q& x# D0 v& [33 u5 H8 X# J5 i* @3 T% d
Encoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约1 v& Y+ M. C1 l( x0 z% f$ j

8 H; y5 S8 t) ]# `1 ?5 o) v* _与 Solidity 的区别是什么?. d! c- U+ a% }' a9 j! O
8 j/ V- d8 G3 W3 \8 Y
Solidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。, F0 C' U: y( j$ S, z6 u0 G
但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。
7 l9 X7 R- l* Q& c! ]! a) h" A" |8 x# t- ^. ?+ S4 A
我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。# f+ x1 w6 r3 m& L

2 x% y( ]) t. Y9 u. K1 a* z$ ~3 q这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。: M, l# A# R$ p* v9 M: P; j/ k, J4 O

( X/ [% M* ~" s0 u5 R% W与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。' |- c$ }; E; M9 T
. [& a6 Y5 k, M
这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。
3 I4 u* ?. C/ V# h, s
7 l% A( ?3 ^$ AABI 规范* q% N: O; N: Y9 l( N) N' m5 M

8 k2 I' }+ I% I2 s$ p& EABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
! y* Z: k1 L: R9 u: ~4 v8 N类似 ERC20 的接口示例:0 f& Y: b. r. R
ERC20Interface
! w' R7 K) |' o& u4 g1 `# The first non-comment line is the name of the interface and used for all codegen prefixes$ ]* j. `7 B% U& d
# this is a comment
; g. D2 Z' [  {5 gselfBalance -> balance:uint64
3 n" E( `+ ~/ I% y5 ^" haddress:UniversalAddress balance:fn -> balance:uint64
8 B3 t4 m1 l9 W3 [: h9 i! baddressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64" {& |$ m. `# j9 b7 n5 U
address:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable
8 M5 p7 }: u. E' h: u# _6 c1 V9 A' ~
也可以使用数组:) ~$ a& b2 l: y/ K- s5 F
ArrayExample
$ q2 |* J9 l) x) b0 S#declares someFunction takes an array of 20 bytes exactly: ~# V4 j7 Z! P8 I+ ]! v) u2 D: o
someData:uint8[20]:fixed someFunction:fn -> void" y" T. k1 r8 H( j
#declares someFunctionDynamic that takes an array of no more than 20 bytes
, S3 q* s8 [! y1 V# lsomeData:uint8[20]:max someFunctionDynamic:fn -> void4 n2 n  O1 Y" h) O1 i4 C  S9 r
支持的基本类型:" [$ `8 A) l3 b! B% {
1 ~5 P; p# z5 P4 B5 D' `5 T
uint8
4 _6 q6 p' H& g! a" Vuint167 v8 A1 j6 @* O! s
uint32. E' E3 O! A3 u9 `7 E" M+ ^' u
uint64
" R2 e( l4 K* }5 cint8# j. U- p7 V( s3 J
int164 [1 T) T- Y3 ?4 ^" j1 O8 W
int32
% u) b" E5 [3 z$ d( Fint64
7 O7 H" B! t* |7 Q6 Tchar. v- d, V1 r" B3 b+ A) ^; R
void -- 仅对返回数据有效。对应无返回数据9 R: _$ H( k. A- q, U7 Y) c$ b
fn -- 特殊
1 X) f2 s5 I5 a; {# V3 d更高级的类型:
0 d! J  B: S/ G  ^UniversalAddress
: `7 e, `( L, X% f' [1 O$ P基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。
0 ~# n/ R- Y; y6 B& a" q数组类型:# s' |8 O& u: V( S2 V) H9 V
fixed(默认) - 数据必须是指定的确切大小
/ G( r2 F! @1 p, @% U! v, p3 bmax(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误
9 c* K# N) P& C" B* L# odynamic(动态) - 任何长度都有效(使用前 uint8[])有效& s/ p% Z* T, {- D. d& N
clip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误% z5 ?3 k3 c* V
% N5 J8 c! J! l6 |' k% E" E6 q
函数编号$ t" O7 F0 W7 k/ r' a
函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。
% f2 G; D! a- U$ Y* `! V' c6 x, _" y( g! j) {, k) S2 C0 f' ]
内存分配: Y0 D2 z( W$ r1 T
大于 256 字节的数组都使用堆分配而不是栈。
6 j! l6 {6 r# K8 D; e# [  m2 u/ Q4 r. m' U
接口! e$ k$ ~) i! I  T) k* \7 h
一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。  {/ Q" ?8 ~3 A+ ]
包括其他接口:
& P. @! z4 q6 G2 U8 [7 t" m" Q+ LMyContract( f# q$ X+ i& X7 \- ~9 a0 k
:interfaces ERC20, ERC721, MyParentContract
% w7 Y* Z( J( e3 U% N$ Fabigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
9 e! A% K1 {) _4 |& q  S* m' u* Z7 v1 ^
语言( y; ~$ i& o$ K1 q1 e; m
现在只支持 C. 之后会支持 Rust。
& n! b8 j4 l, W示例(手动生成) C代码:
1 \! u1 G) ^% i! ?2 v8 istruct simpletoken_Send_Params{
8 o- G0 ]2 g5 _- O1 y   UniversalAddressABI* address;; t  y% Q. z0 h# s9 F
   uint64_t value;
: t1 E( t* [& U/ R7 Y2 i4 G};
# T1 ?1 e2 f3 t$ E% h% Rstruct simpletoken_Send_Returns{
( q+ f" z& I; k7 m7 G0 p   uint64_t recvvalue;
7 k, {$ A- ^% l, C   uint64_t sendervalue;$ p" b9 t0 h3 d" H* L+ @+ v2 P
};% U! i$ c; i2 r$ o/ [" C
void decodeABI(){
0 r3 u0 c" U6 c, b- f   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64% D$ R! d' w; z& D' a6 O0 `
   //format: address:address BALANCE -> balance:uint6
5 ~5 v+ t* l: L   //format: SELFBALANCE -> balance:uint64
1 [+ a9 f$ ]3 t9 w! Q6 T   uint32_t function = 0;) ]5 u* w! A+ K  U9 x/ G1 Y; E
   if(qtumStackItemCount() == 0){9 N. F2 f9 \; x9 W9 N
       //fallback function... ) m/ W1 V  u$ ]  a# g; n( ?
   }" X2 c: J& k% |, }7 {8 f# M2 C
   QTUM_POP_VAL(function);
% l: I% g1 y/ D( H) s& T   switch(function){
  z! j$ @8 J8 K: n" \0 t. L$ r       case CONTRACT_SELFBALANCE:
3 `6 d" ]# _- h  A* W: F5 z       {
0 o0 {, I- F$ }( @' b" U: ?' w           uint64_t resBalance;5 f+ w6 C' J, V/ b: T4 J$ N
           selfBalance(&resBalance);* x$ B. g4 t6 P9 D
           QTUM_PUSH_VAL(resBalance);
/ R# P$ j% j& F; y9 N           return;9 J( g3 \' B3 ^& ~, b1 m; P
       }5 o8 P  T, Z3 X, w( M: A
       case CONTRACT_BALANCE:
1 Y) K2 x+ }7 u' ~       {
# g  ?! W+ B$ H0 M% j6 M           UniversalAddressABI address;6 q3 d9 x5 ~6 F2 i
           QTUM_POP_VAL(address);
6 k3 g' A. M, u+ }           uint64_t resBalance;1 J% I6 W/ L, B
           balance(&address, &resBalance);
' a. y- @/ i" _! n; {           QTUM_PUSH_VAL(resBalance);
$ o2 n6 d  e7 z  w+ J1 Q8 r           return;( M6 Y6 e8 Q& J& ]  _2 @- o- G
       }
9 }* |0 g- g9 W       case CONTRACT_SEND:
# Y: H- Z3 k: L  K' u       {7 |) w" Y- i+ A$ j, F/ G  w
           struct simpletoken_Send_Params params;
, W$ m) r9 }/ Z           UniversalAddressABI __tmp1;
! k7 s9 V; `$ [3 w: i, n           params.address = &__tmp1;
9 u9 @$ d3 i$ u5 T
# W$ o8 [1 {/ K, e6 X# n           QTUM_POP_VAL(params.value);
0 _( E/ E0 E" c% I( l7 i$ j           QTUM_POP_VAL(__tmp1);
% o8 K5 x: \; ~2 ^) ?% j           struct simpletoken_Send_Returns returns;
& @; P3 ^+ p( z) r8 Y! M           send(¶ms, &returns);5 Q* |: O6 R, K4 i% \: x
           QTUM_PUSH_VAL(returns.sendervalue);
7 d1 O' d2 Y/ P4 d. P5 F. E/ k. H+ Q           QTUM_PUSH_VAL(returns.recvvalue);! Y2 B/ I0 z. v% `0 ~. Y
           return;
7 \, ^4 n+ V' r" j       }" ^; ?( b; @* N6 j8 t1 V
       default:. h  r0 ?/ P: l3 [) T; b
           qtumError("Invalid function");
( Z! J9 o2 _- ~/ _! f           return;! Y( t! `6 \3 ^3 x' n
   }! S% R0 a3 r  O* \1 q  j9 ~$ E' Q
}
6 ]9 n# S, u' r% c$ Z; T//format for this:
: ~: i6 Z* `5 N% N$ {//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64) Z) U+ U* A: k7 u
struct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit," U  s$ y! U; D6 b" {: ^6 l
   const struct simpletoken_Send_Params* params,
7 t" D1 B  E' ^, K; g) j   struct simpletoken_Send_Returns* returns9 H: M  }( f3 n6 [6 m
   ); N2 t7 t5 E' A/ V8 K: ~
{
1 V7 |; w' k4 w7 ~$ m   if(__gasLimit == 0){7 p- |: U  ^. a4 E, L  m- s0 @
       __gasLimit = QTUM_CALL_GASLIMIT;; L0 z1 f% c2 L6 _: B# g
   }
  W0 j( h. k+ Y! p$ N   qtumStackClear();; H+ R3 {: B7 ]1 I9 b) L: {
   QTUM_PUSH_VAL(*params->address);6 \5 n! u3 ^2 H- P/ x3 \' j
   QTUM_PUSH_VAL(params->value);
; t' u, |* _# H* B8 u& Q   uint32_t f = CONTRACT_SEND;- \2 K! O8 f2 a) b& ?3 y" Y* f
   QTUM_PUSH_VAL(f);
/ {5 ~1 _3 R; b$ f* k   struct QtumCallResultABI result;0 O. D5 @% Z! u# I3 D' F* V+ N( m, b
   qtumCallContract(__contract, __gasLimit, 0, &result);
5 U0 ]" ]- K) |; J3 `$ p' R2 _   if(result.errorCode != 0){% r9 R3 F9 v: z& r; q; z
       return result;" F% p' w; |! }2 f* Y
   }
; u, l9 ~1 m  z   QTUM_POP_VAL(returns->recvvalue);# n3 E& u3 t2 S( {" O7 b- P
   QTUM_POP_VAL(returns->sendervalue);
  Q5 e5 s8 q8 d   return result;7 B3 }% ]. i& Y3 K; n5 }- ~+ D
}& B' \: k/ D9 k( L

5 M) U; p6 _. Y8 s其他: h8 R" [- C/ h3 z# A
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13