Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen
. C4 V6 ?: r$ y5 _/ h3 D8 V3 T
% C3 S3 b+ L) y这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。
  z% G5 Y( F: Z5 Z# F6 B1 W# t! n5 K" ]  o7 G* E3 M8 U9 Y; C
SimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。' a# l0 o+ l: {9 e; M

. y& }7 v% r+ o3 o# G+ `& Rabigen 可以以下 3 种方式运行:
: F9 s/ @. x0 v; g5 I, t/ b1
* H1 K' t4 N+ E) i* ^: @6 YDispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数
2 E. C# N, f' A" P! H, c5 ]2$ q0 G& n& W0 c3 A* @$ `5 d
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约1 C7 ~" D3 F7 T" Z
3  U0 S; g$ I- ^8 U' w) M' y
Encoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约
0 x8 _8 d6 _* ]& n6 H7 O8 {1 Q; u' K3 b3 b2 d0 ~' ^
与 Solidity 的区别是什么?2 V+ x/ P( p$ C2 @! I8 U

2 U( U' R! ]) e0 A6 O1 F, JSolidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。" }5 A" o/ G: }  {
但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。; J+ y3 M3 Z& w" \* r
9 m0 U* h( }7 ~* m
我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。5 X9 m8 v6 E7 y
- @, e1 C' O# F$ D+ t
这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。* A) c/ u# M+ Z' a7 \
! Q7 h& B/ f3 }  Q
与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。
. W! L7 r3 F* g
2 B; Z8 W8 c0 p! D' y+ L这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。
8 ~% G3 I8 b7 P, q; |, L' d" n( o% @% L& J2 ^
ABI 规范
, S) H7 W9 N4 s
# m$ Y9 `1 _" x: c1 ~ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。* l. D  h+ ?$ B6 Q# i
类似 ERC20 的接口示例:
8 U$ y6 {- d& @$ h' J/ bERC20Interface
  M+ I1 T. E! h( N: \3 {2 V. \# The first non-comment line is the name of the interface and used for all codegen prefixes$ V/ o! b7 A/ s: i4 o
# this is a comment; n3 \/ v; `  O9 v
selfBalance -> balance:uint64
: y8 H$ ~4 ~: P* S' D& zaddress:UniversalAddress balance:fn -> balance:uint64
( u3 y) E% S' [  d4 j4 E( \addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint647 M/ Z8 {8 Y7 X! e, s: e9 M+ s
address:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable; @& B) t; a! {# M! E7 S/ ?1 @9 I
! P/ N* \: ^4 @% J) d; ~+ Q
也可以使用数组:( g+ ^6 H" z) }7 ~% i
ArrayExample
! l& W, m3 o* H2 s. h$ F#declares someFunction takes an array of 20 bytes exactly3 j" b" L2 n' w, ~2 a7 Q. r
someData:uint8[20]:fixed someFunction:fn -> void, |! G8 Y' K, K& a1 g) x6 x. m
#declares someFunctionDynamic that takes an array of no more than 20 bytes# [& J2 X1 K' r. I% [
someData:uint8[20]:max someFunctionDynamic:fn -> void
. ^0 v. k- \9 k, O支持的基本类型:' H1 V9 {0 m- N( I5 A& B& N+ @8 D
) L- B( s5 t( B3 _# S+ [- _4 [+ W
uint89 k( V1 I# E1 ^- _# Q
uint16+ w) ^: I6 B( z' U
uint32, i: z0 p$ C: Z! n+ S
uint64
( G1 N. H0 ?1 S; {# P  p$ g) Qint8
3 a* l# f( w" j8 kint162 u% y( E; X) Y
int322 ]1 D7 F  ?1 V. a& ?! j
int64
( n  a1 u( g2 r7 ^2 B8 ychar
) U: E# k; A  [# {void -- 仅对返回数据有效。对应无返回数据& j9 l& {) ~9 y1 J- _) N- q" C
fn -- 特殊
5 P9 ~& p  I. y# A( c更高级的类型:
+ C5 F4 u  G: r% ^% G  tUniversalAddress
0 x0 A; P# x" o9 C; b" T3 P9 w基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。
7 g6 n8 V9 m& J+ a' w数组类型:  K* q8 A  p; @  u& b! R& w' b( |
fixed(默认) - 数据必须是指定的确切大小
# z! ^; L- Y6 P) Y/ R5 K% p) Mmax(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误$ g) R/ y; b7 V* U
dynamic(动态) - 任何长度都有效(使用前 uint8[])有效
8 @% x" K  m8 R' Lclip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误
' Q7 x: ^- [" |3 I/ v+ \/ ^( ]' z& T4 \2 c% b$ A
函数编号
# m& Y: O: E8 ?( M5 D函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。) f; y+ ]% x8 ^: Q/ s$ O1 q  b8 @4 J  Z
! f5 v/ p7 t9 x/ H! |) C: K, G# n
内存分配
/ ~& ]4 W- m0 R; l* T0 o大于 256 字节的数组都使用堆分配而不是栈。2 B: n$ v9 ]! K

' S) V" q' }- F  c接口
, E/ ~6 K( f7 i4 r, f一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。; d- P2 @) m2 O3 u" {) I7 e
包括其他接口:
6 w  C+ y/ F8 DMyContract# h, U1 j) o& Q2 r7 O6 s
:interfaces ERC20, ERC721, MyParentContract
# ]% A* Q: ?- u9 D' Vabigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
; J+ K" m. w" k1 z- v5 A" r  G3 ]& \5 |1 I6 i+ q$ D
语言& Z8 j1 g  E2 l& A; @
现在只支持 C. 之后会支持 Rust。
1 G7 B5 v7 ~8 z# W) F  M: ~" r# ^示例(手动生成) C代码:
9 q  C5 M& x$ t2 ~9 B7 ?% r! Jstruct simpletoken_Send_Params{( |8 F$ w  U2 x5 S
   UniversalAddressABI* address;! \  _- O8 z1 y% K
   uint64_t value;8 X7 @6 K* r! S- }+ w# J$ n
};
, A  v- D* G3 n2 ustruct simpletoken_Send_Returns{
* ?" n' X$ t8 X7 p   uint64_t recvvalue;8 f4 L* K$ i" P" G" b
   uint64_t sendervalue;
. M! {1 v* j5 j/ M};
& s) j- q1 _; I; h- C/ yvoid decodeABI(){" J$ P8 N  Q! W$ f) X0 N  Q
   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64& v; X+ i; s# p% N+ Y3 X$ j
   //format: address:address BALANCE -> balance:uint6
- y# k: K& D$ ^' Y   //format: SELFBALANCE -> balance:uint64# w5 Y5 j3 T' A  ~- H- e1 K! G' w( b/ q
   uint32_t function = 0;
# m' D- t  b9 M6 r5 |2 F1 _- N) ~   if(qtumStackItemCount() == 0){
: e9 V. Q6 }; q& [3 a) k5 X$ w$ y+ R       //fallback function... ; f3 A" t! D' y& G( v6 e
   }9 K5 v& q- n8 K. A
   QTUM_POP_VAL(function);$ p2 U% r) G) Z0 z0 u
   switch(function){7 ], C/ a2 G. {5 ?+ S& _, U5 N/ T
       case CONTRACT_SELFBALANCE:
" O4 c4 Z' T- J. Y       {! X9 Y- T( v% @' r+ n
           uint64_t resBalance;
! d3 W* g3 r& M% s: s5 y5 ]/ H# B           selfBalance(&resBalance);* k# p; z; m. X: k% _' ]7 o* _
           QTUM_PUSH_VAL(resBalance);
* @5 Q3 o  D! t( ^  M& q4 n           return;# k5 t9 T9 u; Z0 z% ~% ?
       }
/ ?% S$ G$ a% X  h, t8 u9 Q       case CONTRACT_BALANCE:9 J& z8 K1 y8 @+ f/ K6 ?2 F
       {
/ i9 j& t9 x% }9 z; _0 k$ J           UniversalAddressABI address;& g9 X6 j9 z% J! F
           QTUM_POP_VAL(address);
  f) @& q% c5 W  R- @5 N           uint64_t resBalance;& Q2 B* Z/ `" T% M1 ~  g* I
           balance(&address, &resBalance);" ], w# b: D. U3 T- h, k  \# e8 C: n
           QTUM_PUSH_VAL(resBalance);
" k! A$ w/ j5 M; T) J           return;
: _1 y# ^( |6 |( g       }
0 u8 x; n' O9 \, W9 [       case CONTRACT_SEND:
" v" _/ z1 H7 T       {
) J/ j' I, B* n3 P; F           struct simpletoken_Send_Params params;
" \% L3 J4 c' U- Q           UniversalAddressABI __tmp1;. A# O3 H, w  _5 u6 N; b9 V* S
           params.address = &__tmp1;, j% o9 J5 f; r: ~5 D% N( b

3 s$ L/ L8 e* I, ?7 [% Q, O7 R           QTUM_POP_VAL(params.value);
( D& O, m( o2 Y7 Y           QTUM_POP_VAL(__tmp1);
( ~. M  Z) x3 f8 A0 L           struct simpletoken_Send_Returns returns;
( f1 v! Z, s2 a6 w/ y           send(¶ms, &returns);
! t! {; b8 B/ F  w           QTUM_PUSH_VAL(returns.sendervalue);0 |3 X7 ~0 B; N2 L, o
           QTUM_PUSH_VAL(returns.recvvalue);4 j( a7 T: T& n- @* U" A
           return;- j* Y: j' v; f$ Y1 k; e
       }7 N% q6 `3 X3 X
       default:
+ b# u8 P1 y  `- H$ O. x; |- T& e           qtumError("Invalid function");
' f8 f6 s: u; h+ F9 L           return;
8 s- Z2 V( y- N' H   }
0 k7 V9 j  j/ |# L+ X}8 O% z" n: p# d, G5 X5 G
//format for this:
$ {  r4 d7 ~4 c: A. @8 @//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint646 K. q! z8 J) m- _
struct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,7 s2 s6 q/ ]: \
   const struct simpletoken_Send_Params* params,
5 B4 `! W, Q5 }; }* D& O$ D& B% f   struct simpletoken_Send_Returns* returns
- c2 _/ ]' x/ M5 v" V1 ]) r8 s   )
* u) v6 _+ Z$ g* V9 s6 h4 g{
, z7 D' u1 C8 ^; u& I; s: e   if(__gasLimit == 0){
+ G: ^, j$ s4 z$ u) r% f: k- s0 {4 E% `) Z       __gasLimit = QTUM_CALL_GASLIMIT;
! n4 g  Y. i+ f; s   }
1 n% d" [7 Z" Y  S4 ]5 X3 w9 R   qtumStackClear();: |) y6 c4 `7 _' Z. [: u% {- g' X' e5 u
   QTUM_PUSH_VAL(*params->address);
8 }. J( y  R* L' i( Q: G- L   QTUM_PUSH_VAL(params->value);  }% u" G( y7 g
   uint32_t f = CONTRACT_SEND;
0 H* z) b, S8 q* y: x0 l1 D   QTUM_PUSH_VAL(f);
9 M' r1 x9 ^( h4 T$ E   struct QtumCallResultABI result;
5 d  F1 B% U! |4 R  I3 B! @0 z0 Z8 _   qtumCallContract(__contract, __gasLimit, 0, &result);1 E2 \3 O  s: L# @
   if(result.errorCode != 0){1 a3 ^9 E6 _* a6 m1 Q: s
       return result;) ]' E' ?/ ~* ]- {% I7 v1 E5 z& }
   }: |! H8 ?" n$ @" D$ {% s. d% Y
   QTUM_POP_VAL(returns->recvvalue);4 H  g) O( d, j) l
   QTUM_POP_VAL(returns->sendervalue);0 e* t7 k, X! I9 K
   return result;0 @9 I+ |+ m5 U/ I- \% g/ Q
}7 g  E6 f9 U* X- ?

( ]& {  t6 y. o+ t1 l- X0 h1 z其他) s( @9 z3 g: Z
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13