Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen/ N3 I5 |; h- V' Q6 v/ o
, I+ \7 J4 f9 v, M5 ?" L
这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。
" C5 \, @, t8 v2 J6 O4 `) T; F9 T$ X9 ]8 ]" W- W
SimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。
7 v2 U1 x% N1 ?- _& h4 i7 c' q# `; n$ i- u0 m! T( x0 y
abigen 可以以下 3 种方式运行:  s9 }$ A& c+ }5 ]* O9 R" v- t4 u
13 }% b- U- C: a$ L" o8 k) @
Dispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数5 q9 A% G3 h+ l# s- X5 L0 f; Q
27 G# d2 J5 z& k! y+ s- j4 n
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约) q; x+ V0 q# p
3" J8 O/ }+ u9 X3 ]
Encoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约
, D' ]7 W. t7 K& h6 e, @- `6 s  B
2 _3 {* }) O6 c: w# K与 Solidity 的区别是什么?# P* n' ?  X- O0 D# a
, R' B4 v8 C" v! t9 N3 e
Solidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。9 o0 x( W" p( H) e1 m" O" y
但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。3 X. Y6 r/ u  K

0 \/ d5 j1 i0 W  X$ Y. v0 k我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。7 ?. Q% N  I8 Y) p9 n

0 a, H( z/ c1 @4 D这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。
, }- P* D$ I6 i. ]& R3 c, j& z8 u) j" P% y, t
与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。8 J% H( \0 o: s4 t8 j

6 U4 I" h: k, G: L- i( K这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。
! A. K" O2 T/ j# Z$ v7 V# }3 ]7 y7 H3 D! C( P6 s) n5 v
ABI 规范
! F1 p% p" V1 I6 ~/ y4 a( h+ \0 I
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
; @: ~( q' U, e- G' n/ {. ^类似 ERC20 的接口示例:1 p' k( ]/ x4 y7 \: P
ERC20Interface
; K( y5 a+ ?4 i4 u3 Z# The first non-comment line is the name of the interface and used for all codegen prefixes
! b% i# p# f( g1 F6 y, T- E1 {2 [# this is a comment
. l3 M6 ?# n5 i7 e/ D$ a- rselfBalance -> balance:uint64. A3 {* ]: ^0 }1 G  ~6 J7 x8 S
address:UniversalAddress balance:fn -> balance:uint64, X% ?7 w8 x1 c7 b0 E
addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64
3 X3 v5 i! ^/ I; L- ~# h/ i9 gaddress:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable
  j) \& I; B5 C% g
2 e6 h9 _% s) Y1 K也可以使用数组:
$ D" A+ @! g$ V; ZArrayExample4 f$ l% z+ T  N) I6 C
#declares someFunction takes an array of 20 bytes exactly
5 U" L; L0 H) Q8 u3 v0 E; f# zsomeData:uint8[20]:fixed someFunction:fn -> void
1 {5 h" G3 K* |& i5 W  q3 l#declares someFunctionDynamic that takes an array of no more than 20 bytes, ^" s/ [1 y9 [: b
someData:uint8[20]:max someFunctionDynamic:fn -> void
- T) Q7 q; n% Y4 M/ K% g! S+ w支持的基本类型:
- N4 C& s8 {8 n4 S8 y! @: _9 ?3 z3 k8 X3 P7 L' [8 r
uint8" h/ r9 a5 \$ R0 }4 e7 [  v7 U
uint16
; u: Z' F4 ?3 [- \6 w  G+ Iuint32
; U- B& g! Y& D9 p+ cuint641 j* \/ W5 t& _1 V
int8
# {9 W7 L' ~" F* R0 T4 ^$ eint16
% u9 B) f& r  ]int32, b- q" \1 o# n0 {* a
int64! @% {1 x$ n! z- N" s6 T) U
char4 d9 k5 H  p" y, u4 }
void -- 仅对返回数据有效。对应无返回数据
6 y" V. l/ j+ f: T# _  R4 |! vfn -- 特殊
, R& h( O! ~  ?# L$ @更高级的类型:
8 d/ [7 k3 j+ aUniversalAddress0 R0 E4 Y& {+ m$ S7 ^. j
基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。- e: A8 A  @: V- d& e% k9 ?
数组类型:# ^* |+ ^9 ^2 E- `& I  K3 U! L
fixed(默认) - 数据必须是指定的确切大小, W4 r( @0 E9 C, U/ w7 o
max(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误
: }6 j- h9 D  u% @6 J# Hdynamic(动态) - 任何长度都有效(使用前 uint8[])有效
% r5 }# V4 G" T4 n& r' b1 Bclip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误
  n+ E! j# K: \6 T' C1 ?" c7 r# i* ?9 ~5 a' `5 Y
函数编号
# x5 {/ Z& P+ {  C. I- T$ ]函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。9 f1 z& n# G- o4 t2 v

+ D, L' v6 |  h2 F( G+ Q; M! D4 A3 y内存分配5 @- `" X4 h4 ]7 O! B
大于 256 字节的数组都使用堆分配而不是栈。. k7 d7 r/ e% n/ f" [% ?& m1 t
. f, d" S; \1 t- X7 [
接口
' w% J2 S7 ^6 e" `" i" ^6 {一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。
1 Z% I( Y: _; C' @% m, u! E包括其他接口:5 x8 b* x( v% E6 b2 Z) w( Y
MyContract! w$ {; {4 Y# q6 y
:interfaces ERC20, ERC721, MyParentContract
1 b; W- C: z( M2 b* i3 wabigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
! V  {8 l0 ]  g( _0 \& p9 ?; O; k' d# @. @5 O0 p. t2 x
语言; H/ b) o  c6 K+ F' r. A9 D
现在只支持 C. 之后会支持 Rust。  B& A! |4 J6 @& h8 J
示例(手动生成) C代码:
7 c6 [) v# L& y% i/ j9 hstruct simpletoken_Send_Params{
- W  Z* F& q! W8 c3 m3 e1 g   UniversalAddressABI* address;
2 v) C0 q& c  d! ~4 \3 n   uint64_t value;
# L  R+ Y# l! q+ t9 o};
# c# d; B+ g6 s, Y' @2 L7 W+ e6 }struct simpletoken_Send_Returns{. Y! A* U8 A) k3 o
   uint64_t recvvalue;' S# @# m# n5 ]% Z
   uint64_t sendervalue;
" |" R- A% \, ^; [6 Z: q6 i+ ~+ u};2 W9 H7 ~- n0 K! _: ^1 G9 z
void decodeABI(){
2 v' D; M* J. T  O2 ?   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
# T( v+ z% Q" v% |1 O   //format: address:address BALANCE -> balance:uint6" [$ ~& S8 g* B  K; T
   //format: SELFBALANCE -> balance:uint64
+ J8 s4 F$ u& D. }4 c4 _: D' ?   uint32_t function = 0;
: B7 A( s5 L. b, e* g& |* L   if(qtumStackItemCount() == 0){
! J( S1 T2 \- E& B+ b! p' H& B       //fallback function...
: b& P, _" H8 m   }7 o, _' H& H- @( M9 T, O) B8 `7 O
   QTUM_POP_VAL(function);
/ W0 w, m2 V; [" W- r% X   switch(function){0 Y; [& o5 M' C. v
       case CONTRACT_SELFBALANCE:
. Z: m* c( E9 a       {$ P5 {% w4 {  Q4 k- a  H
           uint64_t resBalance;
- f: n/ W: |+ ?+ `: ~0 X" _' ^           selfBalance(&resBalance);' a; z7 I9 U8 ]. }8 P+ ]3 o
           QTUM_PUSH_VAL(resBalance);: l8 i4 [7 d6 O
           return;
2 g8 u: U  m6 S1 [6 l# T! N       }
! [4 U. d( S% f. c       case CONTRACT_BALANCE:2 L' Z* v' f6 k: _: z9 i
       {
0 ]3 [8 K$ X* h7 s0 {5 v           UniversalAddressABI address;
; r- l. F9 X* X' f& J- C9 Y           QTUM_POP_VAL(address);7 S% o, M/ S# a0 J3 b; G
           uint64_t resBalance;9 b/ g; f6 F& k6 w' m/ R2 D
           balance(&address, &resBalance);$ a& u0 u6 B8 I  V
           QTUM_PUSH_VAL(resBalance);
4 j: F) i# O5 c           return;
( j2 W9 F3 f1 {  x4 h. L       }9 V1 h# _4 \+ \. U" D
       case CONTRACT_SEND:/ ~) g$ r( i) s
       {
. K! b6 B* B! z+ B7 O7 A/ D/ W           struct simpletoken_Send_Params params;
4 m8 q) J0 p& [1 l2 b" r  R+ \           UniversalAddressABI __tmp1;
) _3 a# ^4 |' _           params.address = &__tmp1;) n& ?( u$ o/ j0 t, j: |: T3 H9 Y

% a" F4 V; Q+ s5 i& D8 `: |           QTUM_POP_VAL(params.value);8 y# r1 k0 j& s0 w; [1 M
           QTUM_POP_VAL(__tmp1);
& N$ V# g' E3 B4 G& r# N& \' r9 v" g           struct simpletoken_Send_Returns returns;
: \6 z7 B7 H! B           send(¶ms, &returns);
2 Z0 e1 Z+ c& U! \1 b' u) N           QTUM_PUSH_VAL(returns.sendervalue);5 O  U: Q! K. ^' _
           QTUM_PUSH_VAL(returns.recvvalue);1 p9 ^6 s7 Q3 j# K
           return;
) a* x# u. C" n; {       }
! U6 g! {) K& C7 h0 h       default:
. a" l; p& I* g8 X& N8 f* O           qtumError("Invalid function");
# H# J' n  q' S. W" N2 e2 e7 [* q           return;$ x* q; ?- s7 r1 Z: q6 m5 D
   }& n! R/ C, B2 m3 E+ C* @0 U
}
# y+ M! Q  d2 |1 y//format for this:
: {2 C9 ], X8 z- Z: T& X% Y//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
5 G, p9 g) j9 K5 X& R3 C& ^$ ustruct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,0 m% s3 O2 V" ~/ w
   const struct simpletoken_Send_Params* params,
* f/ `3 U3 ], [   struct simpletoken_Send_Returns* returns
. F6 O+ P' [. M# j% L* f2 G' `   )% a- M& d4 i4 l' s& v, y
{
9 l/ ?  s& |4 h3 _   if(__gasLimit == 0){; Q& b5 `2 X7 D& x+ h! t
       __gasLimit = QTUM_CALL_GASLIMIT;
* y7 U9 j2 S' J   }, f) s4 `' e2 ?# @& A! T1 s# W, i3 h
   qtumStackClear();, w+ l; F8 X8 h1 C. I" a$ s" Q7 W
   QTUM_PUSH_VAL(*params->address);: ~# c4 b+ b( S4 L( h
   QTUM_PUSH_VAL(params->value);
: p7 r, H3 i+ J0 ]$ o   uint32_t f = CONTRACT_SEND;
7 U& ^8 G3 _4 K/ G6 E   QTUM_PUSH_VAL(f);% E7 F1 ^/ a) R* q; N$ G+ T
   struct QtumCallResultABI result;
0 L1 g: Z4 K" J) w   qtumCallContract(__contract, __gasLimit, 0, &result);; Q# A  `3 b( L) e$ V9 b7 s
   if(result.errorCode != 0){. _; z5 ^) N1 H5 i# B0 G9 m
       return result;
7 b4 Y: f: ~) I   }# s- m# O$ J2 ^$ P
   QTUM_POP_VAL(returns->recvvalue);; A+ l$ W/ R* s. {3 Z$ ~
   QTUM_POP_VAL(returns->sendervalue);( K: R" k7 c; j
   return result;
  g& \* A3 k, r0 U9 d}
8 C, j5 z6 c% `5 |/ I9 Z* p, O! c2 J, t1 F  a& S! @
其他
5 [1 V$ B6 X/ M: c* |) [对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13