Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen
& i7 x( Q) O5 v# `
0 n% ^7 E: E* }1 Z& p这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。3 @; ^/ D. ]7 U" C- `( J

* A0 C% C8 h; V8 z  V9 jSimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。$ H/ G1 l) _3 g0 A0 ~$ g

  [- W. Q& S! g7 i  O; y5 Eabigen 可以以下 3 种方式运行:4 h2 k- c2 s& m7 B
18 C9 D+ ?+ j3 z. @; D4 X
Dispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数, t8 M/ S2 a, q9 ?
2
+ Z. I* ]8 U/ W; A- I1 k# J# }9 DCaller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约* u1 a4 ]! {# \7 g9 M8 G! `, t
3
7 E1 @. D! t) x2 P2 @+ W) ]Encoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约
2 p: P* T  C0 _
% F5 \" u1 w' p* l' w" F3 u与 Solidity 的区别是什么?
( u4 f, u* s4 J+ L! ?, P! y6 [1 X/ D: I2 \. M2 W( J$ ?
Solidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。
" V* h! T3 [1 s. D* p, L9 T但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。  Q1 X, q7 J& b: q/ a7 g% w; P
8 I7 d3 J9 }+ Z( B* Z' R
我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。% ^( o* N" r$ g

( H  o4 Z. A4 g这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。* \0 ^: U7 j% J1 g9 C* @
8 M* D# K# q3 m" C% I  q
与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。, ^7 C* s9 v% ]7 Y

, l% B6 @& C, w3 I# _2 m这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。
7 l( w. U$ ?" B6 M& X
6 X# {' b6 }  C! o7 uABI 规范
8 m9 Z' s8 T1 p8 u% c) m* B3 k% ^2 o( b) o, M9 P
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
* E/ s) w) [& j6 {4 X' s1 _' @' D类似 ERC20 的接口示例:& P+ B! B& i. L, g7 M3 [2 s
ERC20Interface, g! D4 z* S% @( B6 O" P  ?* K
# The first non-comment line is the name of the interface and used for all codegen prefixes
) Z/ y1 t+ v0 G8 {# t# this is a comment, |% X; e8 ?$ k* I4 q7 ]. e
selfBalance -> balance:uint64, V9 L% R/ _  [4 [5 x
address:UniversalAddress balance:fn -> balance:uint64
- s8 r) _4 k- G5 `addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint641 q8 Q6 u$ O% `
address:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable' w4 ^3 w+ c( V; w2 u4 f

- F0 S+ n3 g# V2 C. B1 C- r也可以使用数组:8 ~# j/ `+ T* l0 B3 \4 C6 C" K
ArrayExample
2 C/ f" I9 e- ^! d& A& X4 M  I  l! V#declares someFunction takes an array of 20 bytes exactly
: w; M6 `' k3 @( |6 e' y. A  AsomeData:uint8[20]:fixed someFunction:fn -> void
6 e. i/ d4 S0 I#declares someFunctionDynamic that takes an array of no more than 20 bytes9 K; Q- E* k2 v4 b0 k3 y
someData:uint8[20]:max someFunctionDynamic:fn -> void
1 Y6 l, O, p! L支持的基本类型:* {8 u  V3 P& P2 h& \

, K/ G5 [& ^8 Xuint8; {. [. J: k. m0 |* C& p3 I
uint16
! ]- l7 \# z. D6 u+ Y8 h) |uint320 z9 ]& ~. X1 G9 p$ L8 O6 R
uint644 o9 L& }* Z  S( |' E% O2 n
int8
9 N* b  ~' M3 f' N" h$ Q; z6 vint16. @, |# b' N8 ?
int324 F! H3 T/ x6 \% Z( H5 ?9 g
int64; q6 r6 b5 ^, r8 Q3 I- S( d
char
: p9 F! e) {+ P2 [2 \void -- 仅对返回数据有效。对应无返回数据
& h! b- [2 R5 I  ^- p. Tfn -- 特殊
; Y/ Q: e1 M+ F: D& f更高级的类型:
( \/ a/ w+ @# w( }UniversalAddress
6 `% R" g; P; ?4 k: v, s2 Z+ a基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。
7 l, D' E; I$ U1 R! J数组类型:
# H( S( ~; V/ g0 ]: m2 x7 vfixed(默认) - 数据必须是指定的确切大小* H  R+ F( v8 E  V
max(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误
& `" _8 X5 a4 T# b- h3 J9 ~" B2 y$ gdynamic(动态) - 任何长度都有效(使用前 uint8[])有效  X! h' W" @' u* F, `1 s
clip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误3 @1 F/ ~3 }0 X3 l

" Q) Z& |" t/ O# {9 o, Z- ]5 o函数编号
% z1 ?: {" _; O" y函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。; z' |$ k: H$ u3 T
9 R( _2 o2 e& ^, n% f2 i
内存分配
2 L  {& R! J! M4 }" @0 |' q大于 256 字节的数组都使用堆分配而不是栈。6 @7 |' l" ^! @/ }  l
* J5 I7 C: u( d0 ]4 _9 v
接口& ~9 E8 ~9 u& L1 Y
一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。" c) M$ \) W) e; e
包括其他接口:
5 w0 n+ W, Q8 g. l0 F1 ^MyContract2 c; x; {* L$ ~+ `' R: n
:interfaces ERC20, ERC721, MyParentContract# B9 M$ K+ }2 |4 P6 b
abigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
; V! z* g1 P: Q+ W7 U1 V3 J* E, \7 {9 ?& h/ ~
语言5 L8 n( N8 D, b9 _+ P. ^
现在只支持 C. 之后会支持 Rust。, A* K3 u8 V4 X. {0 Z
示例(手动生成) C代码:7 z  r% \0 z0 x/ a& j
struct simpletoken_Send_Params{9 P- j* @8 m( o3 L/ x' f
   UniversalAddressABI* address;6 s& N3 T5 U- U. c* ?! [3 A
   uint64_t value;' s$ p- S  m0 T! y' u2 X1 h5 B
};
) f0 A' c- [' J; s7 @: E9 ~struct simpletoken_Send_Returns{/ k" W+ w& i' X: W! b7 u* [( d
   uint64_t recvvalue;) e0 H6 L: A5 ^6 W
   uint64_t sendervalue;6 ~8 |6 {4 }) L/ ^% J) |9 w
};
) x, k' k: i4 P! I6 vvoid decodeABI(){, ]2 Z/ r; I( v2 d3 ~# Y
   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64) T& ?! v( B, H$ n6 b
   //format: address:address BALANCE -> balance:uint6
% W6 [7 X1 H& {' m   //format: SELFBALANCE -> balance:uint641 I# s/ f% Y: V8 w
   uint32_t function = 0;' L' Q: u" \9 [6 z5 u% _
   if(qtumStackItemCount() == 0){
3 ]; T5 e) Y. t4 M4 Z       //fallback function...
* X, i0 K% U  Q: R, k$ C% Z, l( p   }
5 I- o3 }/ ?! d( W% y. \   QTUM_POP_VAL(function);+ F7 R- r" p* k
   switch(function){3 h4 O3 n/ t+ _) g% C* _
       case CONTRACT_SELFBALANCE:
4 `7 y/ h2 m1 `* A2 b" y5 h       {3 h- t4 i. M5 N2 U3 j) @+ r; k
           uint64_t resBalance;
3 A1 |% h& D7 H* W           selfBalance(&resBalance);
7 O9 }( P7 v- [           QTUM_PUSH_VAL(resBalance);) [: `' r: {6 P" M9 k! |
           return;% e% B! T$ N% Z
       }
* K  z* ]7 @; ~* o" |( R. C3 {       case CONTRACT_BALANCE:3 }; f& ~! }. O% i% z3 e: [4 }
       {1 V+ _  `  R( U5 F4 f& y, f
           UniversalAddressABI address;
$ }; i- t  z1 [# e3 F, h0 c           QTUM_POP_VAL(address);4 P; Z) o+ G7 {, i
           uint64_t resBalance;
4 H' x5 Y' h( H8 E5 p           balance(&address, &resBalance);; V' i9 p) R/ |( S3 U
           QTUM_PUSH_VAL(resBalance);3 ~( x9 A( ?3 k3 M' Q
           return;
" F% x5 C6 R+ M4 _; p       }. r* o0 x9 h4 |! ]
       case CONTRACT_SEND:
3 J* W. S& t( v       {, c- T0 }* v. X, w
           struct simpletoken_Send_Params params;" w) L% g3 i: @2 q' p& u
           UniversalAddressABI __tmp1;
5 [, p" W6 m3 \, [$ w" N           params.address = &__tmp1;
, B; g, O$ c6 o0 e1 U  I/ h/ G0 i* S% p! ~0 D' U) J. ]
           QTUM_POP_VAL(params.value);8 k5 a6 U: e7 `2 x3 n
           QTUM_POP_VAL(__tmp1);
' a3 K" i! n: u7 l7 R0 E           struct simpletoken_Send_Returns returns;
$ |( m8 M$ s1 n. x& s9 m& z           send(¶ms, &returns);0 m$ S( S( J: N4 L3 Q. _
           QTUM_PUSH_VAL(returns.sendervalue);
4 [" g; I3 k; w           QTUM_PUSH_VAL(returns.recvvalue);
* E& v( C5 U/ @9 C: ^0 y; u( B           return;
) M7 [3 n' U$ m# |       }7 a( y5 k% }8 ~5 O9 m3 e! ~  c# m
       default:  B: F. d7 E1 E; z0 }9 }: P0 O) ]' j/ f
           qtumError("Invalid function");% ]8 V' V. E$ K
           return;
% d# ~1 j; P8 r2 }1 D; `   }
4 T- M  d' \( `, K5 i2 c" |! Q}
+ _/ Z" Y* [7 y; _//format for this:
4 E# [. b+ N# q" F* l) }  P+ @7 I) Z+ {//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
. r8 S3 u0 v5 y7 e( }+ X6 x: B* h6 Ustruct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
( r" l3 E. |) `* _( S   const struct simpletoken_Send_Params* params,; Z: P% w- t! U# ]4 R5 s& N
   struct simpletoken_Send_Returns* returns
+ k* o9 L) f- f) l0 w   )
# u. ]) x3 w% g% q5 a{
4 `' e4 l) _& e( W% z4 _, O/ v   if(__gasLimit == 0){% h5 ?) }( c, u7 e
       __gasLimit = QTUM_CALL_GASLIMIT;( X; s! l, ^5 _3 @
   }! C5 c0 z5 V  b+ e7 U  j8 C' t
   qtumStackClear();/ j3 k3 S0 p# |# }# F
   QTUM_PUSH_VAL(*params->address);2 N" m. N4 f# O/ l4 y' j9 ?
   QTUM_PUSH_VAL(params->value);
! g/ }+ L, |+ f1 E3 m, Y   uint32_t f = CONTRACT_SEND;- x2 q0 ~# c+ p! ]8 F
   QTUM_PUSH_VAL(f);
! q/ Y7 v4 N  T: |! A) P   struct QtumCallResultABI result;2 f4 \) X0 M$ y/ B
   qtumCallContract(__contract, __gasLimit, 0, &result);9 A: P$ T3 s/ K6 E% `$ ]" K
   if(result.errorCode != 0){
8 @. A$ m' x) t- g. x       return result;: y! W$ z2 X2 o" u* B
   }
# b, a( J! h2 K- u  t3 g8 K   QTUM_POP_VAL(returns->recvvalue);, ]. H- K. Y2 x2 e8 V% m' n; P
   QTUM_POP_VAL(returns->sendervalue);
! N4 {$ `1 ^( `0 `4 ~   return result;
8 L6 D+ h8 [1 s}
" |3 e4 C! S0 {! }( c, m
# ?* i3 X! [9 u7 a) z, M( D其他  y/ C4 a/ X; L/ L0 K. Y5 j6 b) {
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13