Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen' f9 ~. `4 G+ ^, `: r8 `3 G' V7 d

: {2 V) d# k4 ~3 v- g+ @7 c3 t这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。
. ]; j/ q) r8 E: U  N$ h* Y
2 o/ f3 z  c- p8 dSimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。, N9 z, ]) p# _

5 Z# }' N! w: b- S: T: p- Xabigen 可以以下 3 种方式运行:
1 \' R0 ~$ {) K9 j1; o: {% M; E2 e' r  |
Dispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数
  z0 A0 s2 Z: a6 D" z* k/ k2
2 h# V  [5 v1 WCaller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约
9 M* U# B: e2 p" n3 V) c3
/ l8 D: |- ?3 k) T0 `3 VEncoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约4 V3 E1 M: J0 V- U2 R! v$ B4 Y
& H" E0 s  \* t
与 Solidity 的区别是什么?
5 U& d3 k4 H* X) t# u6 A& {4 s! }* e
Solidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。0 f3 z: D# M  m7 D4 s" A
但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。
6 w$ j8 z" ^  V1 U8 k
. Y4 F* p) R- a) z# u# H* M6 ?, Y我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。
( U: }9 O- A/ V* B0 G* @0 F' ?; ]1 P' o
这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。' Y& \+ k/ h' Z5 ]* ]4 _# H( y; O  B

8 ?6 p4 M: B& ?* B! J: n与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。: o* G& f9 ]! r1 s

5 a' m5 X) e/ T3 c6 l* m& X这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。
0 \$ ?: G# A/ M  l. \( `7 t9 s, z! ~' z" C! M; C) i
ABI 规范
8 D- i3 L6 o) R) r0 N8 j9 f6 M5 K( v+ ]
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
  ]6 N/ s% n; H* I* o: E3 B类似 ERC20 的接口示例:( C/ f# [$ o! e4 ~
ERC20Interface
4 `0 O! n8 n% ]- e# The first non-comment line is the name of the interface and used for all codegen prefixes
2 Q4 s2 v  R- m# this is a comment3 J- H1 s5 f0 d7 B$ S
selfBalance -> balance:uint64
3 z# N7 `8 C; }9 @" W2 }9 ?, maddress:UniversalAddress balance:fn -> balance:uint64/ p/ a: ~% |5 ]3 C& @! e/ y
addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64' C* |) g; z4 p& o& ~7 H* h
address:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable
0 s. c3 _! g6 n& o$ ~- p( T2 n- X9 {2 S/ K- f8 d7 {2 h/ D7 m
也可以使用数组:7 D8 k' d9 g9 V" n
ArrayExample8 D9 T( X$ U: u8 F! n$ X: ^% R) ?
#declares someFunction takes an array of 20 bytes exactly. \9 g# _$ O2 I; _
someData:uint8[20]:fixed someFunction:fn -> void# d( l: h' Y, @6 }/ a0 m
#declares someFunctionDynamic that takes an array of no more than 20 bytes
2 i5 C' i2 N' {' p5 csomeData:uint8[20]:max someFunctionDynamic:fn -> void% @5 j* m6 V2 S( @+ a2 ?
支持的基本类型:
* t! X8 j, S, y5 \3 A: `5 w: Y! c; i( R
uint8/ P1 S5 M+ c" l9 A0 q' _. ]# m" N
uint16
6 \) ^8 ]+ X5 B. H9 Y8 U$ Yuint32
+ B7 X, v% M1 p% D* S) c$ @uint64
* m! K$ I/ X$ Y9 F: r/ {- fint8
7 J: F4 G. G3 b( ?7 ]int161 ]( Y* p, i2 f9 l
int32
* o: X' B" H3 h6 ^+ m. W( Y) Gint64
1 e/ S* p' [( [8 U; t* }char9 P8 N' `# W# N  h/ @4 f7 F
void -- 仅对返回数据有效。对应无返回数据
! K5 c) q0 H7 {7 B' I/ Ffn -- 特殊8 x& H0 `: l) v9 h' U
更高级的类型:
1 g  _" t2 T( gUniversalAddress$ p: {$ k( A8 y
基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。& t6 J# j4 {# |0 H" Y
数组类型:2 a  F1 x; J. O# i; E  F9 z% P
fixed(默认) - 数据必须是指定的确切大小
1 W) }& C+ y- Dmax(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误
' @( N9 {* B3 b. `dynamic(动态) - 任何长度都有效(使用前 uint8[])有效( B+ K& ^, n! n8 V2 {1 d
clip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误
2 g/ ]9 {1 G' A5 @+ q- n9 v$ z, H  Z# E: `6 b' C; y7 V; I
函数编号
( b" f8 J7 R  Q" }函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。
9 E, q; b4 r+ L8 Y( J
9 n& P0 y5 k% ^+ X* u) c8 N# r9 u内存分配
, \6 G( L$ s$ l5 o大于 256 字节的数组都使用堆分配而不是栈。
1 b. T8 p1 j7 s. N8 o+ ~
9 X* J. Y# e( f0 |+ a5 j' S3 J接口9 y% P& j7 t- G
一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。# t( E& ?6 i2 j8 j
包括其他接口:4 u) {& O3 b, S+ Q: Z7 Q' F- X# a! R5 q
MyContract& U7 `  E5 v- h" ?, C2 E* x
:interfaces ERC20, ERC721, MyParentContract
* j# |* N) E8 r" V) gabigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。
2 |0 L& ?; e% p5 |& ]4 L# v' \: b" z9 E- @3 V
语言
% I8 I. k# U2 P5 {6 |! P" {% K现在只支持 C. 之后会支持 Rust。4 x* z2 V+ h2 o5 |9 F5 s0 G
示例(手动生成) C代码:
2 U. p* c% g* \; Y% _) F/ w# Astruct simpletoken_Send_Params{
) j' {7 u+ s1 u3 D   UniversalAddressABI* address;! n6 _# L  d. O
   uint64_t value;7 d; G* Q& H* Z, a4 m
};
" K0 U& j" e2 l/ c3 f  v6 ^struct simpletoken_Send_Returns{
' s  }; Q) i# q4 q+ Y- x9 r   uint64_t recvvalue;
: {: T& l4 F* O% g( e   uint64_t sendervalue;4 P+ K7 R+ t. }" V' C' H% a% U
};
& b, |/ j, H7 k+ y1 @void decodeABI(){- m" T/ `3 u% u* \9 j
   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64& R% s* U, @  H5 p5 y5 D# `
   //format: address:address BALANCE -> balance:uint6
7 l9 T& }- y$ `6 Q   //format: SELFBALANCE -> balance:uint64
6 _! _. N/ q' {) a   uint32_t function = 0;6 F! F) E! x% e) B
   if(qtumStackItemCount() == 0){
; _" G# A2 K3 v, i/ Y       //fallback function...
- m  Y+ ?; K" `  D6 {& P6 o   }
) g, j  l, f0 E' y' F/ V1 @   QTUM_POP_VAL(function);
  h: J6 O/ `/ a2 m& S$ Y" |   switch(function){8 n. a5 B# N  g4 G* r
       case CONTRACT_SELFBALANCE:
  e5 P% p, c5 c) t       {) C( ]" Q2 ~# k
           uint64_t resBalance;1 f4 E7 I4 l" X2 w/ Y  x
           selfBalance(&resBalance);2 a3 J! K( ^% J* m7 Q7 }
           QTUM_PUSH_VAL(resBalance);
. i3 {" [6 W! ~8 M           return;
; G( s" n+ i0 a& x2 l       }9 u# w* z( }" \& x8 _
       case CONTRACT_BALANCE:# ^/ A, i6 z1 c" a, z
       {+ h# |" N6 B8 T$ `: I
           UniversalAddressABI address;
. ?& G4 o1 _7 g% Y           QTUM_POP_VAL(address);! [9 I5 b" M" c' x' p
           uint64_t resBalance;, S9 A; u: ?' A* G8 m9 e
           balance(&address, &resBalance);' }( f: O4 x6 s2 H$ j  C
           QTUM_PUSH_VAL(resBalance);' x# ~2 o. `4 ?/ T$ X
           return;( F3 ^' D& g% r2 x9 h6 Q0 `; O
       }
" {9 u0 d9 [" d4 _* h, V& \       case CONTRACT_SEND:! z- h2 [) V* @/ Q3 ?% z
       {
5 `) N% d- C: b( y7 A           struct simpletoken_Send_Params params;
# `6 y! |8 \5 h* C0 A: C6 J           UniversalAddressABI __tmp1;
2 H8 }! I7 p9 I0 T           params.address = &__tmp1;7 v5 D1 V% q7 |. i0 \/ y9 H0 W0 x

, D8 V, b7 [; \# \& i$ w           QTUM_POP_VAL(params.value);
0 B  x/ i7 R" F  N  u           QTUM_POP_VAL(__tmp1);& K2 ]4 d4 y: ~. T5 [2 w. F
           struct simpletoken_Send_Returns returns;
3 o: M! J8 P+ {, f2 B2 `( z           send(¶ms, &returns);7 O# B/ k1 q3 {; ^, q
           QTUM_PUSH_VAL(returns.sendervalue);
, T4 V7 v  n3 `. }" j           QTUM_PUSH_VAL(returns.recvvalue);
! ~/ X. n  K# [& i1 W  r) i+ c           return;( K4 H, w$ c/ w; z
       }
" U: l9 M) x4 y! Q       default:
" E6 s, a9 U. K' w% j& k* z# A$ G: m           qtumError("Invalid function");
+ K- n  g) a" _2 I3 ~           return;
' \0 ~2 z/ H, B, \$ E9 m   }; p( s7 E5 `* P( W( ~
}
0 V* K# q4 Z; P( w//format for this:
4 s0 I! b- z5 |1 {//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64% N! C9 Y  v" ~: c
struct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
8 c6 B  k, B* t) f   const struct simpletoken_Send_Params* params,# h3 b5 k# ^# J0 l7 t) a
   struct simpletoken_Send_Returns* returns& q" y" j+ i6 p+ o. i' m
   )8 J  v/ i3 u) A1 @& u) @8 j
{2 P2 }. G1 n& A, [
   if(__gasLimit == 0){  M9 [4 U3 H( W3 F: y
       __gasLimit = QTUM_CALL_GASLIMIT;
( q" `5 y7 y. e  Z   }2 a; S! {! v- [% l% P2 a8 v
   qtumStackClear();
# x+ w% H3 q9 V# H! ~. D4 O   QTUM_PUSH_VAL(*params->address);
# f1 D. Y0 o% Z" ?+ }- \# ]   QTUM_PUSH_VAL(params->value);- h" N4 E- Y# P( E! A" _$ {
   uint32_t f = CONTRACT_SEND;+ U/ ?: C4 ^( E- A+ q- G
   QTUM_PUSH_VAL(f);- K* A+ d- w5 U1 A8 B! T0 `& t6 K3 p
   struct QtumCallResultABI result;/ ?/ t% c( \7 u) {. O! |
   qtumCallContract(__contract, __gasLimit, 0, &result);2 ^3 s! J4 x4 R. K7 X- f: T1 `9 }
   if(result.errorCode != 0){# c$ x+ I1 u: i
       return result;
  o- S( x; ^. q$ Z& z. v  i4 q   }# u$ M5 n8 o: H, x- R6 Q+ @+ f
   QTUM_POP_VAL(returns->recvvalue);8 w8 D+ K: R2 K) a2 Z3 E# |
   QTUM_POP_VAL(returns->sendervalue);& ~+ q3 k; c& h3 j' ^' J" y
   return result;$ H+ I1 O* J2 B+ q2 x9 p& Y
}
* u: ]3 z5 [* t2 P$ R/ n0 u6 ^! ~% `0 ^" N
其他- E/ w* _- M7 V% N3 f0 ^% K! P
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13