Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen) r7 u5 {8 i) w( g6 h
4 I% M1 N8 w3 B/ }0 K3 o0 c
这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。/ t) j) W' u5 J& z0 {

" ]$ P) b) P. @) T* ~4 e) nSimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。
, F2 t- i( Y8 f# a2 P! d
' G2 E* G, |+ J' [$ {+ eabigen 可以以下 3 种方式运行:' V, ~' I6 q1 X8 A3 u
1- X0 F9 H! ~4 h: q9 G
Dispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数% ~$ ^0 t( z6 A5 D
28 k( ]* [" k' W- V( K% t1 M
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约5 P+ X! }! Q* X$ P" X' g+ l: q; I; {% x; e9 K
3& t, [  r: ]1 r2 ]: ^; M/ O5 }
Encoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约
5 u8 w% b1 u4 f$ C8 I2 g! I4 a  [  v
& ^( x7 N8 ]& b+ C与 Solidity 的区别是什么?
( P3 H" [3 ~$ A* u
$ Z; e' J5 M3 p. ^' k; O3 ], t. i9 MSolidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。" t) Z6 d2 v  j/ b
但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。$ Q( `$ `- `" T, s& g

: O; M, |2 k  h" ], S+ B+ n6 Z我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。
) R  U8 H; {% K$ J0 b- S' P& H3 D8 T
这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。
8 m* J1 t) G( p- J- r* b0 d5 C1 W4 G0 i
与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。9 o( G6 g/ B; f! N0 P+ o  p( b
9 f/ G6 h5 Y4 q5 [3 O
这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。# e; j7 B3 n' Y) |' N1 ^: S
) d) d* _4 b/ |% \
ABI 规范/ g7 J1 |1 X: F
0 M$ a. l5 H9 P! K- o; R5 |
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。) ?6 @- v" i' a: M
类似 ERC20 的接口示例:' }6 N5 J; L  i9 ?3 ]" E' h) f
ERC20Interface
" S* ]% Q3 J, j, L' a: u7 I. S# The first non-comment line is the name of the interface and used for all codegen prefixes7 p: b3 ?3 w' b. _0 [7 ^7 I
# this is a comment
$ }5 W2 U0 B# k7 r6 eselfBalance -> balance:uint644 u) r. n8 r. F# E
address:UniversalAddress balance:fn -> balance:uint64
2 L$ k' E" R" A& n9 m0 VaddressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint643 ]. g/ E& N; @. `1 l0 g
address:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable! U7 p9 U* d8 V5 X% D7 ~
7 F- ?' E! ?' M( }) x1 k
也可以使用数组:
/ Q  ^' Y/ L6 E+ K1 U) sArrayExample
; N* ]* h9 n+ {% S#declares someFunction takes an array of 20 bytes exactly! i6 Q# S9 j" B! J: o, \! J9 _5 |
someData:uint8[20]:fixed someFunction:fn -> void( L7 C. {  K# {# \- z8 z
#declares someFunctionDynamic that takes an array of no more than 20 bytes# n; p4 n% A; [3 j% o7 C
someData:uint8[20]:max someFunctionDynamic:fn -> void
3 M. s( P: r0 S9 e& s% S支持的基本类型:
/ a. ]9 K# w" ~" d0 b8 Z6 F# G! N+ B- }. G( q2 c
uint8
' X. G3 i8 W+ P9 P1 R3 buint162 A1 H# y4 ~& x2 W4 E0 Z( @5 N
uint32
2 I- S0 b  R# i' m4 u& w8 p0 Quint64& B3 ~6 i+ n$ W) H! F$ J, E6 C
int8
& N( F- I$ X1 O: H5 d- g. @/ vint16
4 l2 C) v2 A7 {/ ~% R4 _9 r/ j2 tint32
1 M: I2 T6 N) x: j' C! R# x& Mint647 Q% p* X0 V9 \9 B3 E
char( H( k7 }; w0 T: B
void -- 仅对返回数据有效。对应无返回数据  e- n" g8 I6 _
fn -- 特殊- u. ?" y: N  P8 K' c. x, D0 Q
更高级的类型:
$ U4 {, g/ \1 p1 kUniversalAddress/ J: s3 M5 A7 ]- ]2 m9 B4 ^
基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。# w9 _( b4 V: E1 W' X/ `1 n
数组类型:9 E0 y! ~; d/ B0 t/ U1 |
fixed(默认) - 数据必须是指定的确切大小+ S2 m: U$ K4 i' y) X
max(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误
1 B5 Y# x# {  \5 F1 a# adynamic(动态) - 任何长度都有效(使用前 uint8[])有效- L5 D' @- R& E5 A' ?5 ~9 O1 X
clip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误( g8 c. Z; b* R# T0 ^; w1 Y

+ G" |$ o! j8 l' E2 ^) D函数编号/ L  j, M9 ]* c  ^$ L$ C7 t0 X
函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。
; B* x; J: U! R3 ~3 u7 Z# d1 U
内存分配
5 a/ Y& t; o: r* r% n4 O大于 256 字节的数组都使用堆分配而不是栈。
. o" }) c  \- L' z3 l; Q' e8 F& s: d- n7 m- C' l  f1 l9 s, O
接口
1 S+ G6 d* L( C! R& s- s一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。9 N/ N( E9 g$ F1 `6 s) I
包括其他接口:
0 k2 E8 u, U5 t( w, O  X* K( gMyContract
2 d# L) P+ G* i! x! o9 k+ f+ q+ R:interfaces ERC20, ERC721, MyParentContract2 ^, {& E# V. d# U
abigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
6 v& H" G) b& X
2 S* @1 S1 i) j& A$ g# K语言6 T* }& {0 L: h2 g# p( l/ I
现在只支持 C. 之后会支持 Rust。
# Y$ s' w8 q; j示例(手动生成) C代码:* B, P% T) g  f+ G0 @
struct simpletoken_Send_Params{- G. M7 _+ T+ V% o( Y
   UniversalAddressABI* address;. w7 E0 e& C; u
   uint64_t value;2 l# N( \$ }! {0 W
};: `( n* H, A) R: H; g& t! q
struct simpletoken_Send_Returns{
; F  @& P7 e3 r% @   uint64_t recvvalue;
1 p4 w% v& h5 Y7 v9 _0 n1 O$ L   uint64_t sendervalue;0 G6 b. q( P1 I4 V
};) g" ^3 e$ m  s; r" X% E  }
void decodeABI(){4 a9 v% t1 y( p7 a0 B/ }( b7 q
   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
$ y+ f2 ^6 \. ]9 e   //format: address:address BALANCE -> balance:uint6
) l1 A4 w8 H( w! k7 z. e   //format: SELFBALANCE -> balance:uint647 X$ r" J* v6 r! G
   uint32_t function = 0;  M0 Q1 N+ R, i# [7 U  d3 l) W
   if(qtumStackItemCount() == 0){0 v) w" x/ k( f5 p( D% Y
       //fallback function...
( B0 z- i2 g4 r$ }# `   }
1 Y: J7 W9 M3 y( x; F+ }2 ]   QTUM_POP_VAL(function);: T: u4 M- w' ]) q) W, }$ N& Z
   switch(function){
$ Q# C6 u# X1 P0 F       case CONTRACT_SELFBALANCE:
5 c* B% a  L' {; h' d" r       {
4 M6 X$ X4 ]) ]5 z           uint64_t resBalance;
0 o6 `+ g1 \1 A5 V; V4 P  w. A; C4 D           selfBalance(&resBalance);# i  E  Q0 {" v: {9 Y0 w4 ]
           QTUM_PUSH_VAL(resBalance);0 P; D9 g5 ]& }9 J3 ~) k: Y
           return;& Z4 [) I( v' K/ a* h+ @$ o
       }
: A+ ~) Q3 x& l* I! V       case CONTRACT_BALANCE:5 w! c0 {% T* H6 z  n
       {
" O  r% d) C& _1 @* u9 O           UniversalAddressABI address;; }( P1 f5 b8 x4 C3 T
           QTUM_POP_VAL(address);3 x# t0 R/ q& U$ I) l9 }( g
           uint64_t resBalance;
+ c% Z! h- O0 j" J2 g9 j# u0 `           balance(&address, &resBalance);
2 Q: Q  o, C0 c/ O! V2 K           QTUM_PUSH_VAL(resBalance);
9 T: x3 _! v1 G& b' B  a2 |           return;
$ |5 w, D# h8 e; S  _3 G       }
& E& x# I; Y+ a5 v% t* p) i; t       case CONTRACT_SEND:
6 n( p3 B0 M2 @' V; w/ I% H3 _       {
( _. G4 V' M3 ?; I6 C2 d$ G" u           struct simpletoken_Send_Params params;1 t' y- M" ?) z
           UniversalAddressABI __tmp1;
' C! S) N( n$ t' S  Z* z9 B           params.address = &__tmp1;7 r* l; H$ K  A0 D" }, a

+ m- |" Z" Z$ y           QTUM_POP_VAL(params.value);
4 i) W9 b1 B, y& W! r; p  \           QTUM_POP_VAL(__tmp1);9 H. `' j) n) E: C" N/ e
           struct simpletoken_Send_Returns returns;5 v. C  a3 y/ s7 z& E
           send(¶ms, &returns);- D% h. A: G5 J+ e& ^, m
           QTUM_PUSH_VAL(returns.sendervalue);
2 L- P4 _5 t# U% B( J4 c# f           QTUM_PUSH_VAL(returns.recvvalue);
0 z2 B8 d' P! i3 `6 N$ n           return;
( _$ ?3 P! V4 J- ^# [       }4 x4 O9 q( @* s# m& M6 f& q  j
       default:
8 w  r5 G" E/ G: ?9 O" H4 X           qtumError("Invalid function");
$ _5 y# L# L. ]) w, L" D% D+ R! n           return;/ u, V- Z- l6 l2 H4 ?
   }
, ]3 B% f2 j6 D0 v: ]/ S}- X) i) R9 X* S1 e9 K* v8 `( Q
//format for this:' D7 K5 M' E+ O+ \/ _
//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
$ e* }9 _) s/ l7 J9 f( Cstruct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,, a5 A3 u% ^8 M) ^& f/ F0 m6 K
   const struct simpletoken_Send_Params* params,
' W5 W2 ?( a# j# ^! X) d( D; B   struct simpletoken_Send_Returns* returns
- j3 [1 P+ U7 M" ^3 V: \   )
" C  D2 Z5 g  E) Z{
5 s4 R3 h, M0 I   if(__gasLimit == 0){/ \& f8 k9 B3 {. @% q& F6 U
       __gasLimit = QTUM_CALL_GASLIMIT;
/ S0 i4 q6 `) M; m' T0 p2 D   }/ v* M9 r! O" N2 }1 H( \( x
   qtumStackClear();& h& c0 d9 Q; |: g0 i/ ~$ b8 C
   QTUM_PUSH_VAL(*params->address);
# }( Z5 E$ y' M0 J   QTUM_PUSH_VAL(params->value);) B; N% }4 T; d$ k! Q; m# F1 l
   uint32_t f = CONTRACT_SEND;1 [* N: W  b( v+ B9 f& _5 P( k" m9 x
   QTUM_PUSH_VAL(f);5 E" r. [, ~+ E( \) p8 \& c1 k" G5 a
   struct QtumCallResultABI result;4 I6 h; c3 |5 ?$ y& ?8 t
   qtumCallContract(__contract, __gasLimit, 0, &result);
0 x  V- P" n9 C) A   if(result.errorCode != 0){
" k$ I# K' ~7 d8 N) _  |6 E0 l5 x- L/ R2 d       return result;( b2 P# J; {) K+ y& r
   }
5 \* j/ A+ O2 M   QTUM_POP_VAL(returns->recvvalue);  ~0 J  t7 v6 W. g  w% D+ q
   QTUM_POP_VAL(returns->sendervalue);
6 q: [. _  m0 y3 g   return result;
4 L2 C/ O* _0 A; h; q}! Y, i2 j( {7 d1 i1 c

/ _* Q8 [) r8 [& T# q其他/ c9 p9 ^3 n$ c6 t7 E* f
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13