Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
Qtum abigen! S- @  W1 G( \! }2 b

, V8 T1 ?. }1 n3 m3 m9 Q9 U这是 Qtum x86 合约的一个轻量级的 ABI。这个 ABI 规范称为 Simple ABI。
0 H& |2 Q( r# Z- y8 w) ^* }
$ l( U; @. X: \8 u0 x% X& cSimpleABI 只编码字段值(flat values)和简单数组(simple arrays)。它不是智能合约 ABI 的终极状态,只是实现起来非常简单,最重要的是使用起来非常顺手。
# h/ W" i6 e- ~8 T' H% Q0 N% y& ~# o% V9 H: }6 y  u, F( B9 {
abigen 可以以下 3 种方式运行:
0 z+ c% A3 C0 z- x2 X% Z1
- D6 r1 b/ G! W2 e9 e4 rDispatcher -- 生成代码,用于解码 SCCS 上的 ABI 数据并调用适当的函数; k2 O: e, b& u' t% M6 z" r
26 Y$ J$ d. j# z
Caller -- 为指定的合约生成代码,可使用 SimpleABI 轻松调用外部合约, O( `6 q; Z  x' T+ v
3
3 R" R! C8 q' J' mEncoder -- 用一系列参数生成合约调用的数据。人们可以简单地用 sendtocontract 等即可调用 SimpleABI 合约1 w: v' F" l% T) Q$ _7 I

' L- _, W7 P" _; O5 A4 m2 o7 g与 Solidity 的区别是什么?
1 `. M5 L/ }  E- C, D6 m3 K5 G9 i
Solidity 调用外部合约的 ABI 直接内建在语言中。Solidity 专门用于构建智能合约,因此这么设计是有一定道理的。
) m5 u4 M4 R# k% E但是,x86 VM 支持多种不同的语言,这些语言不是专门为智能合约而设计的。这意味着我们必须在这些现有语言之上构建 ABI。使用复杂的语言分析库等或许可以自动构建适当的 ABI,但很难用,限制大,且不能在语言之间移植。# ^. |8 P: S# }  `: n
: f; Y; E! R6 B+ x+ l% Y
我们正在设计的这个新VM,应该是可以从你的 C 语言合约调用另一个 C 语言合约,也可以从你的 C++ 合约调用一个 Rust 合约等等。
/ X; ~6 \( P& C' X4 n' m1 @' K( P7 Y! h5 `, n
这个 ABI 比 Solidity 的 ABI 简单得多,但与 Solidity 不同,它是显式调用的,即它只能调用在 ABI 文件中直接指定的函数。因此,这个 ABI 往往需要更多的模板代码来处理简单的事情,比如调用函数,甚至只是解码发送的 ABI 数据......所以,一个理想的工具是代码生成。我们可以使用模板代码来生成函数,这样开发人员实际中使用函数只要几行代码。
7 M! h/ V3 y! ~  R1 K* I, h
+ @/ p" Q- ]7 [: K3 O与 EVM 暴露“调用数据”的方式不一样的是,x86 VM具有“智能合约通信堆栈”(SCCS,smart contract communication stack)。我们只需要一个在合约之间传递和返回数据的栈,没必要解析一个大的扁平字节数组。
9 R& X  s8 d9 S0 J% ]& q  n$ L  j
这大大简化了智能合约的实现,这个 ABI 就是为了利用这一点而设计的。SCCS 可以将每个参数视为栈上的一个子项,而不需要解码一大块数据。这也使得调用合约变得更容易,因为不再需要构造一大块数据。大块数据往往需要分配足够内存,将所有元素放入一个连续的内存区域;而 SCCS 可以使用许多较小的内存实现。  E2 k, I9 q* z2 y* {8 U* Z
: N% S2 }: W: J1 E* W
ABI 规范
" o0 _# [6 y, A. O! `0 o/ k5 h6 j6 j2 `: a: O( i( @
ABI 规范很简单,每个函数 1 行。它还充当合约函数前后堆栈的表。即使不使用abigen,这也是一种有用的规范,可以手动实现对合约数据的编码解码的堆栈操作。
5 A, P) z) f. _( B, {类似 ERC20 的接口示例:1 {- N4 X4 }3 A
ERC20Interface1 o0 M, Z, w& j$ d+ O
# The first non-comment line is the name of the interface and used for all codegen prefixes
& h0 p8 x3 \4 B, q0 t# this is a comment% w* |8 G5 m$ T1 t3 ]9 s
selfBalance -> balance:uint647 J5 @: E3 n) P; i( U2 |; k! D, M
address:UniversalAddress balance:fn -> balance:uint64$ G, ~2 ]. _% L5 C
addressTo:UniversalAddress value:uint64 send:fn -> newFromBalance:uint64 newToBalance:uint64
4 r$ ~7 Z  m1 E+ x" T$ L4 eaddress:UniversalAddress buyTokens:fn -> newBalance:uint64 -- payable
% G/ ^+ F1 ~2 U' Z4 R8 S! }/ M
/ p5 J: p, v# }: ]: L' j! E6 b也可以使用数组:
; s* C9 Y: x% }- X) gArrayExample
; F/ @! ^+ Y8 S' l# d. e/ A1 Z#declares someFunction takes an array of 20 bytes exactly1 S, d# p* M  z* @
someData:uint8[20]:fixed someFunction:fn -> void9 v) @! {% b( s. y
#declares someFunctionDynamic that takes an array of no more than 20 bytes
0 I* w+ l, v3 U; ]0 VsomeData:uint8[20]:max someFunctionDynamic:fn -> void& |4 `9 m" J/ d3 W- D4 t
支持的基本类型:5 S' |$ b; [0 P% r# p, H& {0 Y6 t
  @$ g+ t& C# w* w8 ?: q
uint8
6 h! a" m' F- \( z. z" `0 \uint16
; R/ A  ~: {/ C' nuint321 R+ ?) _4 q' R
uint64% b% s+ |: b0 t2 @
int8* ^8 F/ A9 _: Z* a6 Y) H9 Q
int16# M0 m0 U: x' l7 {, k0 z
int32
8 b7 `3 e9 @& m- B3 w8 }& tint64' n) r/ j; f$ u+ C
char+ i# F) x, B1 J. W* c
void -- 仅对返回数据有效。对应无返回数据) ^# s% w' v3 H3 T% Q: F/ E2 T
fn -- 特殊- e1 t$ c6 R4 j' p6 @. i
更高级的类型:1 H3 T: m" B8 o% i  R  q: m# p
UniversalAddress
% z5 d  p! S  `基本类型尽可能传值使用。高级类型传引用。数组传引用,并指向值,值包括高级类型。
8 F& A* k0 q8 P7 Y数组类型:
- J: v5 O( W2 Vfixed(默认) - 数据必须是指定的确切大小$ G: B; r6 g+ C" N
max(指定最大) -数据不能大于指定的大小。如果它较大,则会触发错误7 ?$ R2 c+ x: \5 S% f' M
dynamic(动态) - 任何长度都有效(使用前 uint8[])有效
7 d6 r' U+ J3 d1 C2 g9 eclip(截断) - 如果数据大于指定的大小,那么它会被截断,不会触发任何错误, @8 Z% ~3 W7 Z* N/ i9 i" J
! b& G9 v+ C) s& @# t
函数编号+ I  b" V8 l: d
函数编号的构造方式与 Solidity 类似。 sha256 哈希由函数行和接口名称组成,哈希值截断到后面 4 个字节作为函数号。4 s2 a# t( T/ j# @. ~
6 B' s+ R* Q& w: y( P9 W2 ^- l; r* v& g
内存分配" [0 h0 T& z% o3 c  p
大于 256 字节的数组都使用堆分配而不是栈。
' v6 @1 R$ B7 R$ Z( p$ b; S
! ?: V7 G; I, l) `2 Z接口
4 x% W2 D5 E7 Q* T8 j一个合约可以实现多个接口。每个接口使用该接口名称前缀来生成代码。对于具有相同名称的多个函数,只要它们由不同名称的接口定义,就可以同时存在于一个合约内。2 `1 j) c# B# k" _$ W
包括其他接口:
( t: v, c. }" d0 d5 GMyContract
4 K" m7 v) Q( k4 v9 |+ P:interfaces ERC20, ERC721, MyParentContract
9 ~5 [5 f/ {( d5 B# E% ^5 Z8 _2 Fabigen 自动查找当前目录中的 ABI 文件名,并实现指定全局接口目录的方法。! ]* T! m- J1 {/ C- T& O+ Z! a

1 K; a3 r6 [- d# z语言
9 m) G; ~, C% Z- A; K" e! |现在只支持 C. 之后会支持 Rust。
- P7 c6 O3 j: C2 |0 l示例(手动生成) C代码:
+ b/ }4 h  c5 _% N, C: B, ostruct simpletoken_Send_Params{4 Y/ B8 ^) x- Y4 C
   UniversalAddressABI* address;, L" `, A" F* e- f# t% X% j
   uint64_t value;
- b" \7 ?- _9 {9 R+ [};: W' i3 y# c7 W7 I
struct simpletoken_Send_Returns{
7 |4 _+ u. ]# w   uint64_t recvvalue;
/ \3 M# O' {- E, E- J6 K" n7 ~   uint64_t sendervalue;1 l/ R* j6 P4 Z* J/ `1 F; F
};
: t! W! n* J7 ~8 N5 ~! Z- Z* avoid decodeABI(){
, F/ _& z4 x5 d   //format: address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64
: i& @" v: @; W  P/ y; u7 W   //format: address:address BALANCE -> balance:uint6
2 W8 R- Y0 S' T; u9 `2 M  B( K   //format: SELFBALANCE -> balance:uint64+ ]4 X' n4 s( B, h# K$ m
   uint32_t function = 0;  s( n0 C4 f. h# t
   if(qtumStackItemCount() == 0){$ ^3 a  {# n) S, _8 {
       //fallback function... # t9 i" M( y' w# ^
   }; s( r! B" e- q( C  C! p4 J; g
   QTUM_POP_VAL(function);, Q. |. s) w* x, F
   switch(function){: C  j  Z! Z: y! |9 P
       case CONTRACT_SELFBALANCE:
1 L( k# x( S9 ]# r8 R; E       {
% s% |/ U7 B: E1 ?( Y5 T4 g           uint64_t resBalance;( \" B* C+ C. Y
           selfBalance(&resBalance);
! @; L1 g% {. ~2 e           QTUM_PUSH_VAL(resBalance);
( W5 |, G( P7 H( `, }1 X           return;
) b9 a' m8 N4 \. `5 Z' g/ V       }; X) [9 J. O, u. Z
       case CONTRACT_BALANCE:
) J) y$ Z& h* @5 f6 B       {% i8 I' d# P4 F3 u- n* J# a, A
           UniversalAddressABI address;% O7 O" R, `8 p/ C
           QTUM_POP_VAL(address);$ [! o/ H1 x, h  P+ h
           uint64_t resBalance;+ d; J; Z- ?5 `& s4 l2 b. o
           balance(&address, &resBalance);' V1 C- p+ O+ K( s2 m
           QTUM_PUSH_VAL(resBalance);3 |- r, o' R1 I& e4 m" u2 ?% V+ {
           return;
  K" G) W1 u/ s$ Q       }
/ F  @" q7 s# {( e' Q0 c7 i+ w       case CONTRACT_SEND:. u7 f7 X( k* M( k; _5 E* p# K) E
       {
1 h3 _8 v. p6 x, v. K           struct simpletoken_Send_Params params;* T* X- s* ^- w3 S/ J/ {
           UniversalAddressABI __tmp1;
* [: f! e8 B: o  g$ k' E6 }           params.address = &__tmp1;
$ a+ v" K" X+ O0 y
! S( m- Q- M/ T6 m; ]3 Z: e6 W, R           QTUM_POP_VAL(params.value);
! l3 |  |) K% ?) _0 _# u( w; {           QTUM_POP_VAL(__tmp1);& D  b. p5 E- ?) _% E1 }+ ?6 W( W5 N: M
           struct simpletoken_Send_Returns returns;9 b( b6 j4 E) {) C( R7 K, D6 _
           send(¶ms, &returns);
" E& i" s9 T, e7 V+ c& g           QTUM_PUSH_VAL(returns.sendervalue);
" }* r1 B5 b8 d5 y+ m5 L) \. I           QTUM_PUSH_VAL(returns.recvvalue);
, I3 I, h+ k' a# v           return;1 {$ `- d1 v( F0 q2 [) ^' y5 y5 S
       }: t. N; {% R6 I
       default:1 f3 v% ?& [4 R# q- C. v
           qtumError("Invalid function");
7 {7 W  {# b" Q' W5 r8 l3 }. {# T, \           return;
& a' M( n% Q2 `. b5 M( G   }
& ?9 e6 s) C; L% V# Q( d& Z}. I  }0 |4 s1 c  ]7 \! J0 |1 {. Q- A  _
//format for this:
  c3 a9 ~% _' k( d//address:address value:uint64 SEND -> sendervalue:uint64 recvvalue:uint64; @& a' \' F& }2 v: }2 R' L/ U! q
struct QtumCallResultABI simpletoken_Send(const UniversalAddressABI* __contract, uint64_t __gasLimit,
8 n. R! T& z7 m8 S# A. a   const struct simpletoken_Send_Params* params,7 t+ O4 z# P6 o' G; A2 o9 L
   struct simpletoken_Send_Returns* returns
0 h7 D, P, G- ^7 w- Y   )
8 o. A# T: _7 ?, `0 F{
" |0 j9 |1 X: ?: b  }   if(__gasLimit == 0){
+ I# j. C6 N3 f' O' `8 _' e# ^       __gasLimit = QTUM_CALL_GASLIMIT;% |2 p: E  }$ `- J" f7 n, g' g
   }2 j& L  I8 h$ J- o) _4 w
   qtumStackClear();
4 q8 U0 s( a3 b- S: P9 Z1 }   QTUM_PUSH_VAL(*params->address);
1 B/ M: g& ^' V" W5 [   QTUM_PUSH_VAL(params->value);. ?! S; Y, Q  b' e+ p
   uint32_t f = CONTRACT_SEND;
1 K- c' n: O: P  s! Y9 u   QTUM_PUSH_VAL(f);
- o" Z( A  X) v! ]! y* n! E8 n   struct QtumCallResultABI result;
: z  ~7 `1 c$ Y- a, z   qtumCallContract(__contract, __gasLimit, 0, &result);% P  l  ?# [; [- L) a
   if(result.errorCode != 0){. D) ~- D! d; D$ o4 q1 a' v- f* b& x
       return result;
; O6 h" N; J0 ^" o4 o* D   }. t( E% W4 X0 ^& a( p* q5 B2 B
   QTUM_POP_VAL(returns->recvvalue);' A! U8 L# G# k) r
   QTUM_POP_VAL(returns->sendervalue);1 S$ D8 ~% ^6 I* u  X6 {8 x
   return result;; Q1 Q( j. j; B) \0 ^% r
}6 j6 [* V9 R- `; A* }' r" ^

& y# h& a- |2 ]. }! O其他7 X$ ]* m) ]" M6 A" @5 h( r
对于不支持内置数组大小的语言,不定长数组数组也会有个 "length" 参数暴露给 Caller 和 Dispatcher。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    13