Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen
3 g4 p; k  c& `1 v  F9 `3 O, P9 B0 O& D! k, a& l1 W; a' q
这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。
8 M+ A1 x" O% y5 t+ e  y5 \( Z* T$ _8 ]3 G% z. r8 I7 U  W, o0 R* w
SimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。
! X8 a* x# A& \% ]! F0 r6 y2 ^& W& Y6 y# i. b7 m0 o
abigen 可以以下 3 种方式运行:
3 O6 ^* `. [. d$ E0 e1" K" t" }' t" T
Dispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数
) @6 c- G) R0 h( r2/ z! u+ y. m& Q& ^  h
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约
+ K* q( p1 G" T! G( N7 o3
  k* I' `8 H8 ^. _7 kEncoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约
- {! d9 E; I- e6 O; p0 F# X6 @
6 X3 r& V: C8 a8 q7 o: A: [与 Solidity 的区别是什么?
2 g+ S/ L! S/ C/ G
' t7 V. Q3 J% kSolidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。3 E- @  U( s/ y# p) c5 O
但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。
( Z4 S& T& O+ {6 j+ t; e& d. p& q" ~1 p, i/ J
我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。
. u- Q1 I# J6 w% y/ N
8 y4 N$ U) w  b* o; T这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。: [& h! E& b6 a  S
. t" u- t3 F+ V& z
与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。6 m2 s0 X8 ~' p8 [" P) g+ P

7 l/ P! x/ q4 D7 q这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。2 _) x* q) R2 z; E: V: }# R
& m# b( b% |' E4 V& D) ^1 J* x
ABI 规范/ v1 M3 D/ N# u# U' G
" O' f( l& G6 i" K
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。6 n8 C  Y" G5 p! O" v( E; V) c
类似 ERC20 的接口示例:
3 g. g: {% V" |4 fERC20Interface8 U9 [3 ~' Q, o0 d) N
# The first non-comment line is the name of the interface and used for all codegen prefixes+ [7 ^; v( ?- X5 S, `6 g3 o
# this is a comment7 z0 s* a0 s3 {* c5 {1 s' n: j( f
selfBalance -> balance:uint64
4 y# v0 p4 h0 ?, H8 E( jaddress:UniversalAddress balance:fn -> balance:uint64
, q/ {: q( {$ T9 b4 T( ]addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64
$ d" i! q" d9 laddress:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable+ U; }3 X% _7 {% q

5 C2 h: N, {9 R- M' I2 h也可以使用数组:
3 j1 _/ Y( l- G+ ^7 {- @  gArrayExample
, b1 g" A; p- n2 s#declares someFunction takes an array of 20 bytes exactly3 L3 t: y5 G4 z3 n/ [! z+ U: D4 R
someData:uint8[20]:fixed someFunction:fn -> void' q& j, Y! u- O( f7 M
#declares someFunctionDynamic that takes an array of no more than 20 bytes+ E& B+ l, R8 }0 `* j7 z" K
someData:uint8[20]:max someFunctionDynamic:fn -> void' A# C) j) k6 K9 f9 l5 R, H
支持的基本类型:4 f2 p% J( F# w7 E: b. l; _, I0 V

, o# Y% O1 T! n6 Juint80 c$ v. v( L+ ]4 t5 h$ }, e- A  c
uint16
* v2 f2 Q3 }7 k% M( Kuint32
9 S$ a7 V) g" iuint64) Y1 y, @" V2 |! C, X; X
int8$ p6 z; W( O- S2 D" U0 K( Z
int16. W9 @' g/ Y0 O- y
int325 F2 P* q$ m! a
int64( X3 N: i/ H, b- k6 E4 H
char
$ W$ N; p6 a" q& uvoid -- 仅对返回数据有效。对应无返回数据
4 W4 \+ C5 `" i) X' D( i. C: u; Pfn -- 特殊- t6 P7 h  {2 u6 R
更高级的类型:
9 Y2 D+ h( ^( j" b/ G% }7 q" z' Z6 SUniversalAddress
0 V- d3 m$ S; v# I6 _基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。
/ r" e' Y( ~0 h; l数组类型:; j) ~: Z6 E5 D# [
fixed(默认) - 数据必须是指定的确切大小
; N) U) }: L. Q2 G6 W) j8 Lmax(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误( ~5 `8 @6 ~% m0 p
dynamic(动态) - 任何长度都有效(使用前 uint8[])有效
2 k4 g0 F. w* O. Y# Wclip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误
- k# {2 w) u1 s1 Q' w6 |- m, T
$ U$ f  T: ]2 F* {( Y函数编号
: f6 ?7 D5 f& u; V函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。$ b* G8 k6 h& O+ c5 Q/ d5 B: I
- X. d3 Z2 ~: Q2 U: |
内存分配
& o/ b- @% W& `$ a大于 256 字节的数组都使用堆分配而不是栈。; u( {; }& ?, A: G

( |' O9 o8 G* Z% _: E! W. a1 {接口
. g1 b  j- p! q2 U1 c* n一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。
+ j( F2 r4 M2 X& z0 t包括其他接口:
# |3 E0 u$ D  {3 U, l( F5 z: aMyContract1 O* x* \3 F- }% ^
:interfaces ERC20, ERC721, MyParentContract( {; `9 m  d, x- ?, a# x" p
abigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
; c. i+ Q! J; ?* D, |  r$ E* v. [) d+ ~" ^
语言
  Q" c& }7 Z  }现在只支持 C. 之后会支持 Rust。
( M0 ]0 y2 \, \5 B6 Y6 A; m示例(手动生成) C代码:
8 r8 k7 l- ]9 b" W( ]- pstruct simpletoken_Send_Params{0 S! v: X5 n/ a# ^
   UniversalAddressABI* address;2 y8 [3 e1 c* Q& X' ?8 n* D! [0 l
   uint64_t value;7 }$ f9 R! q" B7 D* q2 U
};" F5 K& d' |; T/ \8 G
struct simpletoken_Send_Returns{
2 o5 J) d5 Q( @" q   uint64_t recvvalue;
% q) t( y. H( R9 T   uint64_t sendervalue;
0 ?& Q, Q  N) U" r- D};4 l! \8 w5 N. _" b2 {- b
void decodeABI(){6 t# u, z. b) B) U+ T& z! I, m
   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint649 m( _, J# d1 h4 N. X) Z
   //format: address:address BALANCE -> balance:uint6+ w( ?3 R2 r4 o9 n  h, A) E
   //format: SELFBALANCE -> balance:uint640 s8 t4 h# f3 P
   uint32_t function = 0;
. f# a, E! a, f/ r: A% d2 S0 l) T( S   if(qtumStackItemCount() == 0){$ B: ?0 f  }1 l- j" Y
       //fallback function...
; h3 a$ o  |) }" X) S   }* r) i" ]# `" i
   QTUM_POP_VAL(function);1 M% u$ a! L0 ^& N7 Y
   switch(function){
4 K8 D, D- |# \. l/ S       case CONTRACT_SELFBALANCE:
, D  ]$ |6 L: B8 i/ c) Z, l/ n/ j       {
. `: u. L5 |2 n& v7 c           uint64_t resBalance;
3 Z  c( P9 R% {5 X6 A           selfBalance(&resBalance);
: m: P; ]: {0 [" F- t7 U; b" `           QTUM_PUSH_VAL(resBalance);
! x  N2 m) U; P1 I           return;$ U8 h1 V' J0 A3 w5 h; J
       }
, p  g. Y3 {# V2 d7 \2 H% B       case CONTRACT_BALANCE:5 A' O$ z; C7 x: [  i* |5 m# q
       {. O' v& \+ b4 v# d' A2 j+ S  L- F
           UniversalAddressABI address;7 E2 U: J& t: `5 }/ o
           QTUM_POP_VAL(address);
6 B- p: E: G  c! o" b5 u! [) ~+ e! {           uint64_t resBalance;
5 ]* M7 p& T. U/ e, {4 W1 j           balance(&address, &resBalance);3 E* g/ E7 ]# P% t
           QTUM_PUSH_VAL(resBalance);  M9 ]" z  @2 |+ B7 T6 w
           return;
/ H* c  Y# w) v" V9 ^- d       }9 W, K. m( U7 R$ t
       case CONTRACT_SEND:: n2 V  j8 I6 p% R8 H
       {
; ~/ p8 B0 s0 m: }: u           struct simpletoken_Send_Params params;
' h% O9 l, N9 U; Y+ B: Z" M           UniversalAddressABI __tmp1;" s( ~" N: `; A9 A! w. V( A
           params.address = &__tmp1;2 @) K# j  b. ^2 q. u

7 S4 W( B+ b$ K5 N3 Q( p           QTUM_POP_VAL(params.value);
; B- O9 l3 |! n7 G; r2 k           QTUM_POP_VAL(__tmp1);
7 _( E! z- ]; p0 z           struct simpletoken_Send_Returns returns;
( h& b+ l" f( m           send(¶ms, &returns);& V# g# k: y1 t, d. ~/ k  l( Z7 r
           QTUM_PUSH_VAL(returns.sendervalue);
6 g2 R1 y! j& S; M1 x. f           QTUM_PUSH_VAL(returns.recvvalue);0 d2 X& S$ C2 s9 Y# Q4 Y
           return;
$ N  W% S: K; C+ p5 b       }7 Q" r) o2 n$ j; Y
       default:
2 w  ?; _3 M' \& F  r- o+ z9 B$ K           qtumError("Invalid function");% \* R/ y2 e  ^4 G6 p' l5 F
           return;
; a- p1 l- R4 Q2 y, e   }
2 E' N7 w2 m8 D* t! l}' ^8 B5 @( O' `" L6 R- o
//format for this:
8 h/ p" p' z3 E; Q//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
9 }- B/ J1 V2 H+ \struct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
4 B" I( G& M: y% k. U5 B7 \: A   const struct simpletoken_Send_Params* params,
, N4 e1 |' a% H8 \: ^$ r/ G3 m/ Z   struct simpletoken_Send_Returns* returns7 b. r6 ~9 ^  A9 M% Z% }
   )
4 |, N% k( t* T& Y- g  O$ {4 r{
7 G( F( ~4 z5 F  ~, I3 [   if(__gasLimit == 0){8 K) U! ], d% y0 ], U! @) _
       __gasLimit = QTUM_CALL_GASLIMIT;6 L: v$ O* j. N) S" l6 s! q8 k
   }
/ _6 G! j$ k5 |4 q$ `   qtumStackClear();
$ M; ]9 W+ ^2 |9 D   QTUM_PUSH_VAL(*params->address);( Y2 S4 X# Q% b6 w. q, N: o* b
   QTUM_PUSH_VAL(params->value);
- f' T7 ~6 e1 ~$ u) ?   uint32_t f = CONTRACT_SEND;
# z6 E. x+ G. k% P, {1 K6 G  c   QTUM_PUSH_VAL(f);/ l$ g& _5 A9 m) F& a( }" h! _
   struct QtumCallResultABI result;
, d6 V) F9 r1 Q2 K   qtumCallContract(__contract, __gasLimit, 0, &result);) g8 S1 p1 E  s9 N
   if(result.errorCode != 0){
% O0 E, {5 H& ]  E- [6 J, x) f       return result;+ _% _, a% x/ p% V0 n6 J. P3 C
   }
* A+ R, f4 b0 w* U   QTUM_POP_VAL(returns->recvvalue);6 E8 i  ?+ C' U6 l3 o% ~5 e' \3 L
   QTUM_POP_VAL(returns->sendervalue);0 `% q( ^4 }0 [$ S6 ~* p8 k
   return result;
, v/ u0 e4 f8 ]! R) c}
* |  G$ L! D; B! e  T" ~: R3 l/ ?. X
其他; Y% G6 l  M7 J/ C3 J: H
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13