1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      Solidity運行原理是什么

      本篇內(nèi)容介紹了“Solidity運行原理是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

      夷陵網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站設(shè)計等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)建站自2013年創(chuàng)立以來到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)建站

      引  言

      作為一門面向智能合約的語言,Solidity與其他經(jīng)典語言既有差異也有相似之處。

      一方面,服務(wù)于區(qū)塊鏈的屬性使其與其他語言存在差異。例如,合約的部署與調(diào)用均要經(jīng)過區(qū)塊鏈網(wǎng)絡(luò)確認;執(zhí)行成本需要被嚴格控制,以防止惡意代碼消耗節(jié)點資源。

      另一方面,身為編程語言,Solidity的實現(xiàn)并未脫離經(jīng)典語言,比如Solidity中包含類似棧、堆的設(shè)計,采用棧式虛擬機來進行字節(jié)碼處理。

      Solidity的生命周期

      與其他語言一樣,Solidity的代碼生命周期離不開編譯、部署、執(zhí)行、銷毀這四個階段。下圖整理展現(xiàn)了Solidity程序的完整生命周期: Solidity運行原理是什么

      經(jīng)編譯后,Solidity文件會生成字節(jié)碼。這是一種類似jvm字節(jié)碼的代碼。部署時,字節(jié)碼與構(gòu)造參數(shù)會被構(gòu)建成交易,這筆交易會被打包到區(qū)塊中,經(jīng)由網(wǎng)絡(luò)共識過程,最后在各區(qū)塊鏈節(jié)點上構(gòu)建合約,并將合約地址返還用戶。

      當(dāng)用戶準備調(diào)用該合約上的函數(shù)時,調(diào)用請求同樣也會經(jīng)歷交易、區(qū)塊、共識的過程,最終在各節(jié)點上由EVM虛擬機來執(zhí)行。

      下面是一個示例程序,我們通過remix探索它的生命周期。

      pragma solidity ^0.4.25;
      
      contract Demo{
          uint private _state;
          constructor(uint state){
              _state = state;
          }
          function set(uint state) public {
              _state = state;
          }
      }
      編譯

      源代碼編譯完后,可以通過ByteCode按鈕得到它的二進制:

      608060405234801561001057600080fd5b506040516020806100ed83398101806040528101908080519060200190929190

      還可以得到對應(yīng)的字節(jié)碼(OpCode):

      PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH2 0xED DUP4 CODECOPY DUP2 ADD DUP1 PUSH1 0x40 MSTORE DUP2 ADD SWAP1 DUP1 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP PUSH1 0xA4 DUP1 PUSH2 0x49 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x3F JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x44 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x4F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x6C PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0x6E JUMP JUMPDEST STOP JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x4e 0xd9 MOD DIFFICULTY 0x4c 0xc4 0xc9 0xaa 0xbd XOR EXTCODECOPY MSTORE 0xb2 0xd4 DUP7 0xdf 0xc5 0xde 0xa9 DUP1 SLT PUSH1 0xC3 CALLDATACOPY XOR 0x5d 0xad KECCAK256 0xe1 0x1f DUP2 SHL STOP 0x29

      其中下述指令集為set函數(shù)對應(yīng)的代碼,后面會解釋set函數(shù)如何運行。

      JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP STOP
      部署

      編譯完后,即可在remix上對代碼進行部署,構(gòu)造參數(shù)傳入0x123: Solidity運行原理是什么

      部署成功后,可得到一條交易回執(zhí): Solidity運行原理是什么

      點開input,可以看到具體的交易輸入數(shù)據(jù): Solidity運行原理是什么

      上面這段數(shù)據(jù)中,標(biāo)黃的部分正好是前文中的合約二進制;而標(biāo)紫的部分,則對應(yīng)了傳入的構(gòu)造參數(shù)0x123。

      這些都表明,合約部署以交易作為介質(zhì)。結(jié)合區(qū)塊鏈交易知識,我們可以還原出整個部署過程:

      • 客戶端將部署請求(合約二進制,構(gòu)造參數(shù))作為交易的輸入數(shù)據(jù),以此構(gòu)造出一筆交易

      • 交易經(jīng)過rlp編碼,然后由發(fā)送者進行私鑰簽名

      • 已簽名的交易被推送到區(qū)塊鏈上的節(jié)點

      • 區(qū)塊鏈節(jié)點驗證交易后,存入交易池

      • 輪到該節(jié)點出塊時,打包交易構(gòu)建區(qū)塊,廣播給其他節(jié)點

      • 其他節(jié)點驗證區(qū)塊并取得共識。不同區(qū)塊鏈可能采用不同共識算法,F(xiàn)ISCO BCOS中采用PBFT取得共識,這要求經(jīng)歷三階段提交(pre-prepare,prepare, commit)

      • 節(jié)點執(zhí)行交易,結(jié)果就是智能合約Demo被創(chuàng)建,狀態(tài)字段_state的存儲空間被分配,并被初始化為0x123

      執(zhí)行

      根據(jù)是否帶有修飾符view,我們可將函數(shù)分為兩類:調(diào)用與交易。由于在編譯期就確定了調(diào)用不會引起合約狀態(tài)的變更,故對于這類函數(shù)調(diào)用,節(jié)點直接提供查詢即可,無需與其他區(qū)塊鏈節(jié)點確認。而由于交易可能引起狀態(tài)變更,故會在網(wǎng)絡(luò)間確認。

      下面將以用戶調(diào)用了set(0x10)為假設(shè),看看具體的運行過程。

      首先,函數(shù)set沒有配置view/pure修飾符,這意味著其可能更改合約狀態(tài)。所以這個調(diào)用信息會被放入一筆交易,經(jīng)由交易編碼、交易簽名、交易推送、交易池緩存、打包出塊、網(wǎng)絡(luò)共識等過程,最終被交由各節(jié)點的EVM執(zhí)行。

      在EVM中,由SSTORE字節(jié)碼將參數(shù)0xa存儲到合約字段_state中。該字節(jié)碼先從棧上拿到狀態(tài)字段_state的地址與新值0xa,隨后完成實際存儲。

      下圖展示了運行過程: Solidity運行原理是什么

      這里僅粗略介紹了set(0xa)是如何運行,下節(jié)將進一步展開介紹EVM的工作機制以及數(shù)據(jù)存儲機制。

      銷毀

      由于合約上鏈后就無法篡改,所以合約生命可持續(xù)到底層區(qū)塊鏈被徹底關(guān)停。若要手動銷毀合約,可通過字節(jié)碼selfdestruct。銷毀合約也需要進行交易確認,在此不多作贅述。

      EVM原理

      在前文中,我們介紹了Solidity程序的運行原理。經(jīng)過交易確認后,最終由EVM執(zhí)行字節(jié)碼。對EVM,上文只是一筆帶過,這一節(jié)將具體介紹其工作機制。

      運行原理

      EVM是棧式虛擬機,其核心特征就是所有操作數(shù)都會被存儲在棧上。下面我們將通過一段簡單的Solidity語句代碼看看其運行原理:

      uint a = 1;
      uint b = 2;
      uint c = a + b;

      這段代碼經(jīng)過編譯后,得到的字節(jié)碼如下:

      PUSH1 0x1
      PUSH1 0x2
      ADD

      為了讀者更好了解其概念,這里精簡為上述3條語句,但實際的字節(jié)碼可能更復(fù)雜,且會摻雜SWAP和DUP之類的語句。

      我們可以看到,在上述代碼中,包含兩個指令:PUSH1和ADD,它們的含義如下:

      • PUSH1:將數(shù)據(jù)壓入棧頂。

      • ADD:POP兩個棧頂元素,將它們相加,并壓回棧頂。

      這里用半動畫的方式解釋其執(zhí)行過程。下圖中,sp表示棧頂指針,pc表示程序計數(shù)器。當(dāng)執(zhí)行完push2 0x1后,pc和sp均往下移: Solidity運行原理是什么

      類似地,執(zhí)行push2 0x2后,pc和sp狀態(tài)如下: Solidity運行原理是什么

      最后,當(dāng)add執(zhí)行完后,棧頂?shù)膬蓚€操作數(shù)都被彈出作為add指令的輸入,兩者的和則會被壓入棧: Solidity運行原理是什么

      存儲探究

      在開發(fā)過程中,我們常會遇到令人迷惑的memory修飾符;閱讀開源代碼時,也會看到各種直接針對內(nèi)存進行的assembly操作。不了解存儲機制的開發(fā)者遇到這些情況就會一頭霧水,所以,這節(jié)將探究EVM的存儲原理。

      在前文《智能合約編寫之Solidity的基礎(chǔ)特性》中我們介紹過,一段Solidity代碼,通常會涉及到局部變量、合約狀態(tài)變量。

      而這些變量的存儲方式存在差別,下面代碼表明了變量與存儲方式之間的關(guān)系。

      contract Demo{
          //狀態(tài)存儲
          uint private _state;
      
          function set(uint state) public {
              //棧存儲
              uint i = 0;
              //內(nèi)存存儲
              string memory str = "aaa";
          }
      }

      棧用于存儲字節(jié)碼指令的操作數(shù)。在Solidity中,局部變量若是整型、定長字節(jié)數(shù)組等類型,就會隨著指令的運行入棧、出棧。

      例如,在下面這條簡單的語句中,變量值1會被讀出,通過PUSH操作壓入棧頂:

      uint i = 1;

      對于這類變量,無法強行改變它們的存儲方式,如果在它們之前放置memory修飾符,編譯會報錯。

      內(nèi)存

      內(nèi)存類似java中的堆,它用于儲存"對象"。在Solidity編程中,如果一個局部變量屬于變長字節(jié)數(shù)組、字符串、結(jié)構(gòu)體等類型,其通常會被memory修飾符修飾,以表明存儲在內(nèi)存中。

      本節(jié)中,我們將以字符串為例,分析內(nèi)存如何存儲這些對象。

      1. 對象存儲結(jié)構(gòu)

      下面將用assembly語句對復(fù)雜對象的存儲方式進行分析。

      assembly語句用于調(diào)用字節(jié)碼操作。mload指令將被用于對這些字節(jié)碼進行調(diào)用。mload(p)表示從地址p讀取32字節(jié)的數(shù)據(jù)。開發(fā)者可將對象變量看作指針直接傳入mload。

      在下面代碼中,經(jīng)過mload調(diào)用,data變量保存了字符串str在內(nèi)存中的前32字節(jié)。

      string memory str = "aaa";
      bytes32 data;
      assembly{
          data := mload(str)
      }

      掌握mload,即可用此分析string變量是如何存儲的。下面的代碼將揭示字符串?dāng)?shù)據(jù)的存儲方式:

      function strStorage() public view returns(bytes32, bytes32){
          string memory str = "你好";
          bytes32 data;
          bytes32 data2;
          assembly{
              data := mload(str)
              data2 := mload(add(str, 0x20))
          }   
          return (data, data2);
      }

      data變量表示str的0~31字節(jié),data2表示str的32~63字節(jié)。運行strStorage函數(shù)的結(jié)果如下:

      0: bytes32: 0x0000000000000000000000000000000000000000000000000000000000000006
      1: bytes32: 0xe4bda0e5a5bd0000000000000000000000000000000000000000000000000000

      可以看到,第一個數(shù)據(jù)字得到的值為6,正好是字符串"你好"經(jīng)UTF-8編碼后的字節(jié)數(shù)。第二個數(shù)據(jù)字則保存的是"你好"本身的UTF-8編碼。

      熟練掌握了字符串的存儲格式之后,我們就可以運用assembly修改、拷貝、拼接字符串。讀者可搜索Solidity的字符串庫,了解如何實現(xiàn)string的concat。

      2. 內(nèi)存分配方式

      既然內(nèi)存用于存儲對象,就必然涉及到內(nèi)存分配方式。

      memory的分配方式非常簡單,就是順序分配。下面我們將分配兩個對象,并查看它們的地址:

      function memAlloc() public view returns(bytes32, bytes32){
          string memory str = "aaa";
          string memory str2 = "bbb";
          bytes32 p1;
          bytes32 p2;
          assembly{
              p1 := str
              p2 := str2
          }   
          return (p1, p2);
      }

      運行此函數(shù)后,返回結(jié)果將包含兩個數(shù)據(jù)字:

      0: bytes32: 0x0000000000000000000000000000000000000000000000000000000000000080
      1: bytes32: 0x00000000000000000000000000000000000000000000000000000000000000c0

      這說明,第一個字符串str1的起始地址是0x80,第二個字符串str2的起始地址是0xc0,之間64字節(jié),正好是str1本身占據(jù)的空間。此時的內(nèi)存布局如下,其中一格表示32字節(jié)(一個數(shù)據(jù)字,EVM采用32字節(jié)作為一個數(shù)據(jù)字,而非4字節(jié)): Solidity運行原理是什么

      • 0x40~0x60:空閑指針,保存可用地址,本例中是0x100,說明新的對象將從0x100處分配。可以用mload(0x40)獲取到新對象的分配地址。

      • 0x80~0xc0:對象分配的起始地址。這里分配了字符串a(chǎn)aa

      • 0xc0~0x100:分配了字符串bbb

      • 0x100~...:因為是順序分配,新的對象將會分配到這里。

      狀態(tài)存儲

      顧名思義,狀態(tài)存儲用于存儲合約的狀態(tài)字段。

      從模型而言,存儲由多個32字節(jié)的存儲槽構(gòu)成。在前文中,我們介紹了Demo合約的set函數(shù),里面0x0表示的是狀態(tài)變量_state的存儲槽。所有固定長度變量會依序放到這組存儲槽中。

      對于mapping和數(shù)組,存儲會更復(fù)雜,其自身會占據(jù)1槽,所包含數(shù)據(jù)則會按相應(yīng)規(guī)則占據(jù)其他槽,比如mapping中,數(shù)據(jù)項的存儲槽位由鍵值k、mapping自身槽位p經(jīng)keccak計算得來。

      從實現(xiàn)而言,不同的鏈可能采用不同實現(xiàn),比較經(jīng)典的是以太坊所采用的MPT樹。由于MPT樹性能、擴展性等問題,F(xiàn)ISCO BCOS放棄了這一結(jié)構(gòu),而采用了分布式存儲,通過rocksdb或MySQL來存儲狀態(tài)數(shù)據(jù),使存儲的性能、可擴展性得到提高。

      “Solidity運行原理是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!


      當(dāng)前標(biāo)題:Solidity運行原理是什么
      標(biāo)題鏈接:http://www.ef60e0e.cn/article/pphios.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        宜君县| 屏山县| 肥城市| 汝州市| 新巴尔虎左旗| 胶州市| 甘德县| 邹城市| 鄂尔多斯市| 麻栗坡县| 天水市| 通河县| 兴业县| 闽清县| 通化市| 鞍山市| 宝坻区| 长顺县| 潜山县| 阜康市| 铁岭县| 红桥区| 方山县| 伊春市| 当涂县| 宣城市| 大丰市| 衢州市| 始兴县| 郸城县| 蚌埠市| 寻乌县| 河西区| 大冶市| 隆德县| 南部县| 松江区| 仙居县| 台南市| 周至县| 南京市|