溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Solidity的Yul是什么

發(fā)布時(shí)間:2021-12-07 15:32:55 來(lái)源:億速云 閱讀:195 作者:iii 欄目:互聯(lián)網(wǎng)科技

這篇文章主要講解了“Solidity的Yul是什么”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Solidity的Yul是什么”吧!

Yul (先前被也被稱為 JULIA 或 IULIA)是一種可以編譯到各種不同后端的中間語(yǔ)言( 以太坊虛擬機(jī)Ethereum Virtual Machine(EVM) 1.0,以太坊虛擬機(jī)Ethereum Virtual Machine(EVM) 1.5,而 eWASM 也在計(jì)劃中)。 正因?yàn)槿绱?,它被設(shè)計(jì)成為這三種平臺(tái)的可用的共同標(biāo)準(zhǔn)。 它已經(jīng)可以用于 Solidity 內(nèi)部的“內(nèi)聯(lián)匯編”,并且未來(lái)版本的 Solidity 編譯器甚至?xí)?Yul 用作中間語(yǔ)言。 為 Yul 構(gòu)建高級(jí)的優(yōu)化器階段也將會(huì)很容易。

Solidity的Yul是什么

Yul 的核心組件是函數(shù),代碼塊,變量,字面量,for 循環(huán),if 條件語(yǔ)句,switch 條件語(yǔ)句,表達(dá)式和變量賦值。

Yul 是強(qiáng)類型的,變量和字面量都需要通過(guò)前綴符號(hào)來(lái)指明類型。支持的類型有:bool, u8, s8, u32, s32, u64, s64, u128, s128, u256 和 s256。

Yul 本身甚至不提供操作符。如果目標(biāo)平臺(tái)是 以太坊虛擬機(jī)Ethereum Virtual Machine(EVM),則操作碼將作為內(nèi)置函數(shù)提供,但如果后端平臺(tái)發(fā)生了變化,則可以重新實(shí)現(xiàn)它們。 有關(guān)強(qiáng)制性的內(nèi)置函數(shù)的列表,請(qǐng)參閱下面的章節(jié)。

以下示例程序假定 以太坊虛擬機(jī)Ethereum Virtual Machine(EVM) 操作碼 mul,div 和 mo 是原生支持或可以作為函數(shù)用以計(jì)算指數(shù)的。

{
   function power(base:u256, exponent:u256) -> result:u256
   {
       switch exponent
       case 0:u256 { result := 1:u256 }
       case 1:u256 { result := base }
       default:
       {
           result := power(mul(base, base), div(exponent, 2:u256))
           switch mod(exponent, 2:u256)
               case 1:u256 { result := mul(base, result) }
       }
   }

}

也可用 for 循環(huán)代替遞歸來(lái)實(shí)現(xiàn)相同的功能。這里,我們需要 以太坊虛擬機(jī)Ethereum Virtual Machine(EVM) 操作碼 lt(小于)和 add 可用。

{
   function power(base:u256, exponent:u256) -> result:u256
   {
       result := 1:u256
       for { let i := 0:u256 } lt(i, exponent) { i := add(i, 1:u256) }
       {
           result := mul(result, base)
       }
   }

}

1

Yul語(yǔ)言說(shuō)明

本章介紹 Yul 代碼。Yul 代碼通常放置在一個(gè) Yul 對(duì)象中,它將在下一節(jié)中介紹。

語(yǔ)法:

代碼塊 = '{' 語(yǔ)句* '}'

語(yǔ)句 =
   代碼塊 |
   函數(shù)定義 |
   變量聲明 |
   賦值 |
   表達(dá)式 |
   Switch |
   For 循環(huán) |
   循環(huán)中斷

函數(shù)定義 =
   'function' 標(biāo)識(shí)符 '(' 帶類型的標(biāo)識(shí)符列表? ')'
   ( '->' 帶類型的標(biāo)識(shí)符列表 )? 代碼塊

變量聲明 =
   'let' 帶類型的標(biāo)識(shí)符列表 ( ':=' 表達(dá)式 )?

賦值 =
   標(biāo)識(shí)符列表 ':=' 表達(dá)式

表達(dá)式 =
   函數(shù)調(diào)用 | 標(biāo)識(shí)符 | 字面量

If 條件語(yǔ)句 =
   'if' 表達(dá)式 代碼塊

Switch 條件語(yǔ)句 =
   'switch' 表達(dá)式 Case* ( 'default' 代碼塊 )?

Case =
   'case' 字面量 代碼塊

For 循環(huán) =
   'for' 代碼塊 表達(dá)式 代碼塊 代碼塊

循環(huán)中斷 =
   'break' | 'continue'

函數(shù)調(diào)用 =
   標(biāo)識(shí)符 '(' ( 表達(dá)式 ( ',' 表達(dá)式 )* )? ')'

標(biāo)識(shí)符 = [a-zA-Z_$] [a-zA-Z_0-9]*

標(biāo)識(shí)符列表 = 標(biāo)識(shí)符 ( ',' 標(biāo)識(shí)符)*

類型名 = 標(biāo)識(shí)符 | 內(nèi)置的類型名

內(nèi)置的類型名 = 'bool' | [us] ( '8' | '32' | '64' | '128' | '256' )

帶類型的標(biāo)識(shí)符列表 = 標(biāo)識(shí)符 ':' 類型名 ( ',' 標(biāo)識(shí)符 ':' 類型名 )*

字面量 =
   (數(shù)字字面量 | 字符串字面量 | 十六進(jìn)制字面量 | True字面量 | False字面量) ':' 類型名

數(shù)字字面量 = 十六進(jìn)制數(shù)字 | 十進(jìn)制數(shù)字

十六進(jìn)制字面量 = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')字符串字面量 = '"' ([^"\r\n\\] | '\\' .)* '"'

True字面量 = 'true'

False字面量 = 'false'

十六進(jìn)制數(shù)字 = '0x' [0-9a-fA-F]+

十進(jìn)制數(shù)字 = [0-9]+

語(yǔ)法層面的限制

Switches 必須至少有一個(gè) case(包括 default )。 如果表達(dá)式的所有可能值都被覆蓋了,那么不應(yīng)該允許使用 default (即帶 bool 表達(dá)式的 switch 語(yǔ)句同時(shí)具有 true case 和 false case 的情況下不應(yīng)再有 default 語(yǔ)句)。

每個(gè)表達(dá)式都求值為零個(gè)或多個(gè)值。 標(biāo)識(shí)符和字面量求值為一個(gè)值,函數(shù)調(diào)用求值為所調(diào)用函數(shù)的返回值。

在變量聲明和賦值中,右側(cè)表達(dá)式(如果存在)求值后,必須得出與左側(cè)變量數(shù)量相等的值。 這是唯一允許求值出多個(gè)值的表達(dá)式。

那種同時(shí)又是語(yǔ)句的表達(dá)式(即在代碼塊的層次)求值結(jié)果必須只有零個(gè)值。

在其他所有情況中,表達(dá)式求值后必須僅有一個(gè)值。

continue 和 break 語(yǔ)句只能用在循環(huán)體中,并且必須與循環(huán)處于同一個(gè)函數(shù)中(或者兩者都必須在頂層)。

for 循環(huán)的條件部分的求值結(jié)果只能為一個(gè)值。

字面量不可以大于它們本身的類型。已定義的最大類型寬度為 256 比特。

作用域規(guī)則

Yul 中的作用域是與塊(除了函數(shù)和 for 循環(huán),如下所述)和所有引入新的標(biāo)識(shí)符到作用域中的聲明 ( FunctionDefinition ,VariableDeclaration )緊密綁定的。

標(biāo)識(shí)符在將其定義的塊中可見(jiàn)(包括所有子節(jié)點(diǎn)和子塊)。 作為例外,for 循環(huán)的 “init” 部分中(第一個(gè)塊)定義的標(biāo)識(shí)符在 for 循環(huán)的所有其他部分(但不在循環(huán)之外)中都是可見(jiàn)的。 在 for 循環(huán)的其他部分聲明的標(biāo)識(shí)符遵守常規(guī)的作用域語(yǔ)法規(guī)則。 函數(shù)的參數(shù)和返回參數(shù)在函數(shù)體中可見(jiàn),并且它們的名稱不能相同。

變量只能在聲明后引用。 尤其是,變量不能在它們自己的變量聲明的右邊被引用。 函數(shù)可以在聲明之前被引用(如果它們是可見(jiàn)的)。

Shadowing 是不被允許的,即是說(shuō),你不能在同名標(biāo)識(shí)符已經(jīng)可見(jiàn)的情況下又定義該標(biāo)識(shí)符,即使它是不可訪問(wèn)的。

在函數(shù)內(nèi),不可能訪問(wèn)聲明在函數(shù)外的變量。

形式規(guī)范

我們通過(guò)在 AST 的各個(gè)節(jié)點(diǎn)上提供重載的求值函數(shù) E 來(lái)正式指定 Yul。 任何函數(shù)都可能有副作用,所以 E 接受兩個(gè)狀態(tài)對(duì)象和 AST 節(jié)點(diǎn)作為它的參數(shù),并返回兩個(gè)新的狀態(tài)對(duì)象和數(shù)量可變的其他值。

這兩個(gè)狀態(tài)對(duì)象是全局狀態(tài)對(duì)象(在 以太坊虛擬機(jī)Ethereum Virtual Machine(EVM) 的上下文中是 內(nèi)存memory,存儲(chǔ)storage 和區(qū)塊鏈的狀態(tài))和本地狀態(tài)對(duì)象(局部變量的狀態(tài),即 以太坊虛擬機(jī)Ethereum Virtual Machine(EVM) 中堆棧的某個(gè)段)。 如果 AST 節(jié)點(diǎn)是一個(gè)語(yǔ)句,E 將返回兩個(gè)狀態(tài)對(duì)象和一個(gè)用于 break 和 continue 語(yǔ)句的 “mode”。 如果 AST 節(jié)點(diǎn)是表達(dá)式,則 E 返回兩個(gè)狀態(tài)對(duì)象,并返回與表達(dá)式求值結(jié)果相同數(shù)量的值。

在這份高層次的描述中,并沒(méi)有對(duì)全局狀態(tài)的確切本質(zhì)進(jìn)行說(shuō)明。 本地狀態(tài) L 是標(biāo)識(shí)符 i 到值 v 的映射,表示為 L[i] = v。 對(duì)于標(biāo)識(shí)符 v, 我們用 $v 作為標(biāo)識(shí)符的名字。

我們將為 AST 節(jié)點(diǎn)使用解構(gòu)符號(hào)。

E(G, L, <{St1, ..., Stn}>: Block) =
   let G1, L1, mode = E(G, L, St1, ..., Stn)
   let L2 be a restriction of L1 to the identifiers of L
   G1, L2, modeE(G, L, St1, ..., Stn: Statement) =
   if n is zero:
       G, L, regular
   else:
       let G1, L1, mode = E(G, L, St1)
       if mode is regular then
           E(G1, L1, St2, ..., Stn)
       otherwise
           G1, L1, modeE(G, L, FunctionDefinition) =
   G, L, regularE(G, L, <let var1, ..., varn := rhs>: VariableDeclaration) =
   E(G, L, <var1, ..., varn := rhs>: Assignment)E(G, L, <let var1, ..., varn>: VariableDeclaration) =
   let L1 be a copy of L where L1[$vari] = 0 for i = 1, ..., n
   G, L1, regularE(G, L, <var1, ..., varn := rhs>: Assignment) =
   let G1, L1, v1, ..., vn = E(G, L, rhs)
   let L2 be a copy of L1 where L2[$vari] = vi for i = 1, ..., n
   G, L2, regularE(G, L, <for { i1, ..., in } condition post body>: ForLoop) =
   if n >= 1:
       let G1, L1, mode = E(G, L, i1, ..., in)
       // 由于語(yǔ)法限制,mode 必須是規(guī)則的
       let G2, L2, mode = E(G1, L1, for {} condition post body)
       // 由于語(yǔ)法限制,mode 必須是規(guī)則的
       let L3 be the restriction of L2 to only variables of L
       G2, L3, regular
   else:
       let G1, L1, v = E(G, L, condition)
       if v is false:
           G1, L1, regular
       else:
           let G2, L2, mode = E(G1, L, body)
           if mode is break:
               G2, L2, regular
           else:
               G3, L3, mode = E(G2, L2, post)
               E(G3, L3, for {} condition post body)E(G, L, break: BreakContinue) =
   G, L, breakE(G, L, continue: BreakContinue) =
   G, L, continueE(G, L, <if condition body>: If) =
   let G0, L0, v = E(G, L, condition)
   if v is true:
       E(G0, L0, body)
   else:
       G0, L0, regularE(G, L, <switch condition case l1:t1 st1 ... case ln:tn stn>: Switch) =
   E(G, L, switch condition case l1:t1 st1 ... case ln:tn stn default {})E(G, L, <switch condition case l1:t1 st1 ... case ln:tn stn default st'>: Switch) =    let G0, L0, v = E(G, L, condition)    // i = 1 .. n    // 對(duì)字面量求值,上下文無(wú)關(guān)    let _, _, v1 = E(G0, L0, l1)    ...    let _, _, vn = E(G0, L0, ln)    if there exists smallest i such that vi = v:        E(G0, L0, sti)    else:        E(G0, L0, st')E(G, L, <name>: Identifier) =
   G, L, L[$name]E(G, L, <fname(arg1, ..., argn)>: FunctionCall) =
   G1, L1, vn = E(G, L, argn)
   ...
   G(n-1), L(n-1), v2 = E(G(n-2), L(n-2), arg2)
   Gn, Ln, v1 = E(G(n-1), L(n-1), arg1)
   Let <function fname (param1, ..., paramn) -> ret1, ..., retm block>
   be the function of name $fname visible at the point of the call.
   Let L' be a new local state such that    L'[$parami] = vi and L'[$reti] = 0 for all i.    Let G'', L'', mode = E(Gn, L', block)
   G'', Ln, L''[$ret1], ..., L''[$retm]E(G, L, l: HexLiteral) = G, L, hexString(l),
   where hexString decodes l from hex and left-aligns it into 32 bytesE(G, L, l: StringLiteral) = G, L, utf8EncodeLeftAligned(l),
   where utf8EncodeLeftAligned performs a utf8 encoding of l
   and aligns it left into 32 bytesE(G, L, n: HexNumber) = G, L, hex(n)
   where hex is the hexadecimal decoding functionE(G, L, n: DecimalNumber) = G, L, dec(n),
   where dec is the decimal decoding function

類型轉(zhuǎn)換函數(shù)

Yul 不支持隱式類型轉(zhuǎn)換,因此存在提供顯式轉(zhuǎn)換的函數(shù)。 在將較大類型轉(zhuǎn)換為較短類型時(shí),如果發(fā)生溢出,則可能會(huì)發(fā)生運(yùn)行時(shí)異常。

下列類型的“截取式”轉(zhuǎn)換是允許的:

  • bool

  • u32

  • u64

  • u256

  • s256

Solidity的Yul是什么

低級(jí)函數(shù)

以下函數(shù)必須可用:

Solidity的Yul是什么

后端

后端或目標(biāo)負(fù)責(zé)將 Yul 翻譯到特定字節(jié)碼。 每個(gè)后端都可以暴露以后端名稱為前綴的函數(shù)。 我們?yōu)閮蓚€(gè)建議的后端保留 evm_ 和 ewasm_ 前綴。

后端: EVM

目標(biāo) 以太坊虛擬機(jī)Ethereum Virtual Machine(EVM) 將具有所有用 evm_ 前綴暴露的 以太坊虛擬機(jī)Ethereum Virtual Machine(EVM) 底層操作碼。

后端: "EVM 1.5"

TBD

后端: eWASM

TBD

2

Yul對(duì)象說(shuō)明

語(yǔ)法:

頂層對(duì)象 = 'object' '{' 代碼? ( 對(duì)象 | 數(shù)據(jù) )* '}'

對(duì)象 = 'object' 字符串字面量 '{' 代碼? ( 對(duì)象 | 數(shù)據(jù) )* '}'

代碼 = 'code' 代碼塊

數(shù)據(jù) = 'data' 字符串字面量 十六進(jìn)制字面量

十六進(jìn)制字面量 = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')

字符串字面量 = '"' ([^"\r\n\\] | '\\' .)* '"'

在上面,代碼塊 指的是前一章中解釋的 Yul 代碼語(yǔ)法中的 代碼塊。

Yul 對(duì)象示例如下:

..code:

// 代碼由單個(gè)對(duì)象組成。 單個(gè) “code” 節(jié)點(diǎn)是對(duì)象的代碼。// 每個(gè)(其他)命名的對(duì)象或數(shù)據(jù)部分都被序列化// 并可供特殊內(nèi)置函數(shù):datacopy / dataoffset / datasize 用于訪問(wèn)object {
   code {
       let size = datasize("runtime")
       let offset = allocate(size)
       // 這里,對(duì)于 eWASM 變?yōu)橐粋€(gè)內(nèi)存到內(nèi)存的拷貝,對(duì)于 EVM 則相當(dāng)于 codecopy
       datacopy(dataoffset("runtime"), offset, size)
       // 這是一個(gè)構(gòu)造函數(shù),并且運(yùn)行時(shí)代碼會(huì)被返回
       return(offset, size)
   }

   data "Table2" hex"4123"

   object "runtime" {
       code {
           // 運(yùn)行時(shí)代碼

           let size = datasize("Contract2")
           let offset = allocate(size)
           // 這里,對(duì)于 eWASM 變?yōu)橐粋€(gè)內(nèi)存到內(nèi)存的拷貝,對(duì)于 EVM 則相當(dāng)于 codecopy
           datacopy(dataoffset("Contract2"), offset, size)
           // 構(gòu)造函數(shù)參數(shù)是一個(gè)數(shù)字 0x1234
           mstore(add(offset, size), 0x1234)
           create(offset, add(size, 32))
       }

       // 內(nèi)嵌對(duì)象。使用場(chǎng)景是,外層是一個(gè)工廠合約,而 Contract2 將是由工廠生成的代碼
       object "Contract2" {
           code {
               // 代碼在這 ...
           }

           object "runtime" {
               code {
                   // 代碼在這 ...
               }
            }

            data "Table1" hex"4123"
       }
   }

}

感謝各位的閱讀,以上就是“Solidity的Yul是什么”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Solidity的Yul是什么這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI