Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen; k/ z8 Z2 K6 G: p# `. r
7 L; f: {' ?: H3 g& i0 P2 X
这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。& `$ j9 S4 D% e$ _6 Q
  k3 _8 d8 Y& T) r$ x
SimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。% k5 o" h: r8 o* Y/ c' n

4 ]* ~8 K$ q. A1 S7 i9 Mabigen 可以以下 3 种方式运行:0 A% G- J3 e- z$ t, D
1
- Z3 ~/ W0 O: o6 KDispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数; R. N' A! W6 j. Q/ V
2+ {4 Z6 r, u: W5 v; v' P0 d& v
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约# E! \2 z& o6 q! o- _( L
3
4 g* R. f" q% ?1 X* _# M2 {% vEncoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约
" w: ?; `/ G" V" J$ t, q7 f) v& w% L, ?9 \8 H! f6 e
与 Solidity 的区别是什么?, q( E$ D; o6 q( D- v0 s
6 J( e9 c) d& U6 d8 _2 ^) q
Solidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。
' V' d0 \% y1 @) O9 x+ {但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。$ [/ n$ U) [: X5 X1 |1 p( H9 {
8 y" R/ L4 J; O" c: {
我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。! b, [4 ^7 z: V" @* g

6 \9 Z  X1 C2 m. W" N; H这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。
8 w' `/ B. @0 m+ U8 q% v0 u) i* r& [. {! u% w5 e# G
与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。
3 }$ U' N4 e! y& U4 a0 F
! v3 Q" x) J8 [这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。9 ?) A* I" ]1 V; H* C5 N

+ a3 J; s9 K* F, b2 ]9 O8 xABI 规范
- ^' O* u9 _1 t2 k/ [0 D. F8 ?* o" c' d) k$ Y9 i
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
+ e5 Q% O* {8 J( G4 p! Y4 [, U: ^$ |; y类似 ERC20 的接口示例:
7 R! Y+ m, l3 A# `ERC20Interface( H& @6 M9 c! `8 g. @$ ]
# The first non-comment line is the name of the interface and used for all codegen prefixes
$ I9 E$ o7 y( y( I% S: K# this is a comment2 d; D4 y8 }8 w( _3 Y
selfBalance -> balance:uint64
7 E' _& d$ S5 p2 ~3 n5 Laddress:UniversalAddress balance:fn -> balance:uint64
$ J3 y' c- i- \1 V9 r+ t# {addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64
, y; e7 b. C. j% ]address:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable6 _! n5 ~# P3 `" p3 z, q
: ]! t/ @( L( Q# \0 I5 s8 b/ Z$ p' `
也可以使用数组:
; {3 u$ m! Q5 {/ `) @. d# RArrayExample
: [% S( c+ b/ d' t( g) q7 H#declares someFunction takes an array of 20 bytes exactly
. {! L4 K4 p4 @$ E, I+ P! d- YsomeData:uint8[20]:fixed someFunction:fn -> void
, V$ f5 f3 ^; i# ~$ {* f#declares someFunctionDynamic that takes an array of no more than 20 bytes. R7 R0 S" l6 k) i# @
someData:uint8[20]:max someFunctionDynamic:fn -> void1 ]7 c( {% p5 w8 ?" s' |, n' Z6 W
支持的基本类型:  g/ |9 Z6 D! T" \& r) R
4 t  Q  M$ T) g; b, w4 o
uint8
' L3 D: r4 D: ?; {# Nuint16
9 t: X- I: m! U+ {3 Y+ }$ suint32
" f4 V) p& u( P& }8 z( q* s' Guint64
' V8 s& j) k* N3 fint8
# V  h4 ?2 z* @( v$ H; yint16
& p7 [4 i7 N8 @1 `; ?/ lint32
0 {, O5 D4 p5 i) w8 d. Nint645 `- N  E( f* Z
char: `8 T& k) Y) O3 |) x* E. C
void -- 仅对返回数据有效。对应无返回数据
9 _+ J. E" K( o( \. {fn -- 特殊, F! `1 |6 O( {6 p/ S. A
更高级的类型:
" Q$ ~9 R( ^2 H0 EUniversalAddress! K3 \, M  S% j  G
基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。
, D8 G; E( u7 [( s数组类型:
8 |+ l7 P$ j$ Q& q1 c9 m; ufixed(默认) - 数据必须是指定的确切大小2 g! I6 r# Q6 c# p, r% Z* z2 u9 i* Y
max(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误3 L1 z7 m. }2 S& G2 r
dynamic(动态) - 任何长度都有效(使用前 uint8[])有效+ l& M# G) A% Y' h
clip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误
+ b4 q6 u; n5 `1 `& W1 X7 a
: U1 N0 a' S9 p* L8 f函数编号& w) ^/ ?, f. R* ~& p1 X' x# A
函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。% N& r& S: Z5 F3 K7 ~1 y
8 n9 U+ z2 A. Z/ B9 d* g' g- b  H
内存分配) ~$ U$ B$ `$ j( k% n! ^
大于 256 字节的数组都使用堆分配而不是栈。' d1 g4 Y0 P( N
  H4 _' k' K1 Z/ w' W2 z
接口! [) N! }8 v5 D+ g4 z
一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。
# J! W# r* I. o, K0 A, h4 [包括其他接口:
3 R  b$ U8 F( \  h, `& MMyContract
# o# f9 K- ]  g$ c; A:interfaces ERC20, ERC721, MyParentContract* g) c& W. c2 O+ d3 l
abigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
, T0 F% [* w' R4 ]
1 [( v. E& P- f7 C+ u+ T- g9 @语言
% N! H" h" K+ |! i$ V$ i3 P' V现在只支持 C. 之后会支持 Rust。
- ^% p6 k. v( Z0 h2 T/ u' q示例(手动生成) C代码:0 z2 w3 y9 x& A3 n5 \5 S
struct simpletoken_Send_Params{
3 |/ s2 Z. f4 Z* {9 L   UniversalAddressABI* address;
: a/ ?) V( |: T) G   uint64_t value;
. }; ^  o; J0 E0 [) f- r5 G};. |. u2 q5 |, J
struct simpletoken_Send_Returns{
  K; \2 @' Q# b, d1 V/ }& F   uint64_t recvvalue;
8 @/ m" w' c% @+ w! @6 ]1 |   uint64_t sendervalue;' D8 M5 Q0 F- T5 m
};& t6 x) }1 y& \, i9 b
void decodeABI(){
: R; X, D! q+ \$ ?7 y, b8 w   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint645 f9 e/ C7 U7 o
   //format: address:address BALANCE -> balance:uint6
9 Z3 n6 b; R  _( P& |, s; t   //format: SELFBALANCE -> balance:uint645 x2 |' J4 p3 l/ y, g
   uint32_t function = 0;
4 s3 Y4 ~" f: y6 \0 h* L   if(qtumStackItemCount() == 0){
! V2 N& L$ i" h7 G( S' h       //fallback function... & [. ], U1 j" K, p! Z( ?! D
   }0 Y+ B" W7 M; r' V( ]* w7 g
   QTUM_POP_VAL(function);
! v& [+ F* G6 r   switch(function){/ k9 Q6 }2 W6 d& r8 i; o
       case CONTRACT_SELFBALANCE:6 ~3 q# _& j8 {! q( A, X
       {( Q& P5 q6 |% |7 `5 G0 P+ m; y  h
           uint64_t resBalance;
. O1 L1 }5 T- H! J: b$ H8 E6 F           selfBalance(&resBalance);- J3 P9 Y/ \7 P- S7 J7 q9 R4 N
           QTUM_PUSH_VAL(resBalance);8 ]6 Y2 _+ D; }' z2 H& x1 j
           return;; h. n' Q7 g% Q
       }
6 J- a4 j9 W+ V: Y+ K8 j" V       case CONTRACT_BALANCE:
' m3 f: p- p, e9 g# X       {. y3 O& a$ q- D0 R, A/ J! h/ S
           UniversalAddressABI address;0 _! X) I, M( e3 @$ c6 `0 D) V
           QTUM_POP_VAL(address);% ]" b- R* t1 P
           uint64_t resBalance;
% i6 H. I. S- v& U2 w" r& m           balance(&address, &resBalance);
$ Z, h7 l3 j6 Z! ?           QTUM_PUSH_VAL(resBalance);" M* u! {* o. {5 ~( {6 e8 D) I, C# u! c+ I
           return;
' K1 }4 m& U' b+ @$ }       }0 G5 @7 Z/ b- r9 h! G6 @; z
       case CONTRACT_SEND:
; M$ U+ R( R3 U3 b3 y       {
% \( z6 V5 S# v6 U- H& t           struct simpletoken_Send_Params params;
2 v4 I7 Q. ?( [5 [           UniversalAddressABI __tmp1;% L2 F* N, H6 n2 o
           params.address = &__tmp1;/ L$ Y+ B2 T9 r7 o
% e3 Z: R! D, N% M" w
           QTUM_POP_VAL(params.value);
: W1 _$ t( o* L           QTUM_POP_VAL(__tmp1);
- W4 S0 R( S% T- {) o           struct simpletoken_Send_Returns returns;
$ ~$ J4 @0 Y1 h4 b; D           send(¶ms, &returns);
1 s3 P/ M  m: z% @! m/ `3 m$ l3 B           QTUM_PUSH_VAL(returns.sendervalue);4 ~: q% t* w* w: U+ ?  j( n
           QTUM_PUSH_VAL(returns.recvvalue);) Q/ Z- @3 k* D- o; t
           return;
# K& B% E# X# Q       }8 v- h4 t! \8 j3 {0 n. [& Z, R
       default:
1 R* z( u6 ?  K$ P4 {7 z           qtumError("Invalid function");8 R/ F, ]# E  o+ I
           return;3 G% \6 ~# R9 f/ o/ ~7 l' X
   }1 U3 l& ]9 R2 I
}2 h: a% l8 G$ A& O9 c+ i$ l" N
//format for this:/ B  O0 Y. z+ Z  o! l
//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint648 L! j. O+ t* y) e3 h8 ^0 Y* D
struct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
% @/ H" C; Z/ A0 R   const struct simpletoken_Send_Params* params,
" T4 }$ O# g& x( R1 ?4 a   struct simpletoken_Send_Returns* returns' |5 A6 d) t, Y! S" |
   )1 x; V  n7 b  _3 }8 }
{! d/ n  T: W, F+ O  Q$ i9 g
   if(__gasLimit == 0){
4 {* o4 W8 F6 Y3 a+ k* u2 m. a, Y       __gasLimit = QTUM_CALL_GASLIMIT;
5 Z! r# a1 f: k   }
: T7 O: ~+ j  x" |   qtumStackClear();8 T9 ^5 t) C) j: i2 S- J4 w
   QTUM_PUSH_VAL(*params->address);
4 m5 D, ?9 L. i' W. \8 r$ L   QTUM_PUSH_VAL(params->value);6 ?2 E- r) Q+ u
   uint32_t f = CONTRACT_SEND;
* w8 w( c0 L" T   QTUM_PUSH_VAL(f);( H- `) w. I9 ^# m
   struct QtumCallResultABI result;$ X# N2 `: r8 {4 p6 x  a
   qtumCallContract(__contract, __gasLimit, 0, &result);! y2 h- M# f: o, ?% A
   if(result.errorCode != 0){
$ M- q( H# x. p: D3 `9 y! [       return result;' x7 d! J$ D/ n3 b7 {% V; Z$ a+ c
   }/ A) c# l" ~. V+ w# m! ~- s: _
   QTUM_POP_VAL(returns->recvvalue);' S  d$ [, r4 z; P* S
   QTUM_POP_VAL(returns->sendervalue);
  U/ L  I' A$ a" T# H   return result;
$ U- ]; I' n; q6 O. ~5 \}
1 ^( L7 Q4 N2 U: p$ w  n3 _% V/ z. `; v! n+ M# U
其他) i0 F, j4 }2 X! n7 n2 M
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13