日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

plsql存储过程修改后怎么保存_Solidity变量存储位置与gas成本详解

發(fā)布時間:2023/12/19 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 plsql存储过程修改后怎么保存_Solidity变量存储位置与gas成本详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

如果你要優(yōu)化Solidity合約的gas成本,變量的數(shù)據(jù)存儲位置是第一個 要考慮的因素。在這個教程中,我們將深入學(xué)習(xí)Solidity中的數(shù)據(jù)存儲機制, 包含以太坊虛擬機EVM的介紹、Solidity的三種數(shù)據(jù)存儲位置的 區(qū)別以及不同情況下跨區(qū)域數(shù)據(jù)賦值的gas成本分析與利用等內(nèi)容。

用自己熟悉的語言學(xué)習(xí) 以太坊DApp開發(fā) : Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

1、以太坊虛擬機

在開始探討Solidity的數(shù)據(jù)存儲之前,我想先介紹下以太坊虛擬機 的一些相關(guān)內(nèi)容,以便更容易理解后續(xù)的部分。

EVM的內(nèi)部結(jié)構(gòu)大致如下圖所示:

當(dāng)我們安裝以太坊客戶端時,它其中就包含了EVM這個專門用于運行 智能合約的輕量級操作系統(tǒng)。EVM的架構(gòu)基于棧機器模型,這意味著 其指令集是基于棧而非寄存器來運作的。EVM操作碼清單在黃皮書中 有描述,具體可查閱以太坊虛擬機操作碼和指令參考手冊。

在EVM中指令的執(zhí)行流程如下:當(dāng)一個交易觸發(fā)智能合約代碼的執(zhí)行時, 就會實例化一個EVM,EVM的ROM載入了要調(diào)用的合約代碼。程序計數(shù)器 被清零,存儲從合約賬號對應(yīng)的部分載入,內(nèi)存清零,設(shè)置區(qū)塊和環(huán)境 變量,然后代碼開始執(zhí)行。

2、Solidity變量的數(shù)據(jù)存儲位置

現(xiàn)在讓我們回到memory關(guān)鍵字。從0.5.0版本開始,所有的復(fù)雜類型必須 顯式指定其存儲的數(shù)據(jù)位置,有三種可選的數(shù)據(jù)位置:memory、storage 和calldata。

注意:唯一可以省略數(shù)據(jù)位置聲明的是狀態(tài)變量,因為狀態(tài)變量始終保存 在賬號的存儲中。

storage/存儲

  • 存儲中的數(shù)據(jù)是永久存在的。存儲是一個key/value庫
  • 存儲中的數(shù)據(jù)寫入?yún)^(qū)塊鏈,因此會修改狀態(tài),這也是存儲使用成本高的原因。
  • 占用一個256位的槽需要消耗20000 gas
  • 修改一個已經(jīng)使用的存儲槽的值,需要消耗5000 gas
  • 當(dāng)清零一個存儲槽時,會返還一定數(shù)量的gas
  • 存儲按256位的槽位分配,即使沒有完全使用一個槽位,也需要支付其開銷

memory/內(nèi)存

  • 內(nèi)存是一個字節(jié)數(shù)組,槽大小為256位(32字節(jié))
  • 數(shù)據(jù)僅在函數(shù)執(zhí)行期間存在,執(zhí)行完畢后就被銷毀
  • 讀或?qū)懸粋€內(nèi)存槽都會消耗3gas
  • 為了避免礦工的工作量過大,22個操作之后的單操作成本會上漲

calldata/調(diào)用數(shù)據(jù)

  • 調(diào)用數(shù)據(jù)是不可修改、非持久化的區(qū)域,用來保存函數(shù)參數(shù),其行為類似于內(nèi)存
  • 外部函數(shù)的參數(shù)必須使用calldata,但是也可用于其他變量
  • 調(diào)用數(shù)據(jù)避免了數(shù)據(jù)拷貝,并確保數(shù)據(jù)不被修改
  • 函數(shù)也可以返回使用calldata聲明的數(shù)組和結(jié)果,但是不可能分配這些類型

3、Solidity數(shù)據(jù)位置與賦值成本的研究

如果你不期望合約代碼出現(xiàn)不可預(yù)計的行為,重要的一點是理解數(shù)據(jù)位置的 賦值是如何運作的。

下面列出了不同位置的變量間賦值的一些規(guī)則:

  • 在存儲和內(nèi)存(或調(diào)用數(shù)據(jù))間的賦值將創(chuàng)建一個新的獨立拷貝
  • 內(nèi)存之間的賦值僅創(chuàng)建引用,這意味著對一個內(nèi)存變量的修改會 同時反應(yīng)在其他引用相同數(shù)據(jù)的內(nèi)存變量上
  • 從存儲到局部存儲變量的賦值,實際上只會給一個引用
  • 所有其他賦值通常導(dǎo)致產(chǎn)生新的數(shù)據(jù)拷貝。例如賦值給狀態(tài)變量 或位于存儲的結(jié)構(gòu)類型的局部變量成員時,即使局部變量只是一個 引用,也會產(chǎn)生新的數(shù)據(jù)拷貝

下面讓我們用remix debugger 深入研究一下:

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.7.0;contract DataLocationTest { uint[] stateVar = [1,4,5]; function foo() public{ // case 1 : from storage to memory uint[] memory y = stateVar; // copy the content of stateVar to y // case 2 : from memory to storage y[0] = 12; y[1] = 20; y[2] = 24; stateVar = y; // copy the content of y to stateVar // case 3 : from storage to storage uint[] storage z = stateVar; // z is a pointer to stateVar z[0] = 38; z[1] = 89; z[2] = 72; } }

用上面的代碼創(chuàng)建一個新文件,然后部署合約。現(xiàn)在試著調(diào)用函數(shù), 你將會在控制臺看到交易的詳細(xì)信息以及旁邊的debug按鈕。點擊這個 按鈕:

這時應(yīng)當(dāng)可以看到調(diào)試器區(qū)域大致如下:

點擊上圖中紅色標(biāo)識的箭頭,單步執(zhí)行代碼。

你應(yīng)當(dāng)注意到的第一件事,是存儲載入了stateVar的內(nèi)容,這正如我們 之前在EVM部分提到的,當(dāng)然,這里沒有局部變量。

當(dāng)你繼續(xù)單步執(zhí)行時,你應(yīng)當(dāng)會看到變量y出現(xiàn)在局部變量區(qū)域(Solidity Locals)。 繼續(xù)單步執(zhí)行,你還會看到需要執(zhí)行很多字節(jié)碼來創(chuàng)建必要的內(nèi)存空間、 從存儲中載入所有數(shù)據(jù)并將其拷貝到內(nèi)存。這意味著需要支付更多的gas, 因此從存儲區(qū)域到內(nèi)存區(qū)域的賦值非常昂貴。

現(xiàn)在讓我們研究下第二種情況:從內(nèi)存區(qū)域賦值給存儲區(qū)域。 例如當(dāng)你修改完內(nèi)存變量后,可能需要將修改存回存儲區(qū)域。 這時也會消耗許多gas。如果我們計算debugger中單步執(zhí)行前后的 剩余gas差,可以看到消耗了17083 gas。該操作用了4個SSTORE 指令:第一個用于保存數(shù)組大小,消耗800gas,其他三個用于 更新數(shù)組的值,每個消耗5000gas。

接下來讓我們看看第三種情況:從存儲區(qū)域賦值給存儲區(qū)域。 這一次會創(chuàng)建一個新的局部變量來保存stateVar的值。如果我們 查看代碼的執(zhí)行過程,就會注意到Solidity做的就是將第一個存儲 槽位的地址推入棧,該槽位保存有數(shù)組長度。根據(jù)文檔說明,對 動態(tài)數(shù)組而言,槽的位置包含了數(shù)組的長度。

如果我們比較不同情況下將數(shù)據(jù)拷貝進內(nèi)存的成本,那么 根據(jù)上述情況(更新并拷貝回存儲:21629 gas,創(chuàng)建引用并 直接更新狀態(tài):5085gas),非常清楚的是第二種方案的成本 要低得多。

但是如果我們要直接更新狀態(tài)變量,例如:

stateVar[0] = 12;

這也是可行的,不過如果你要處理映射和嵌套的數(shù)據(jù)類型,使用 存儲指針會讓代碼可讀性更強。


原文鏈接:http://blog.hubwiz.com/2020/11/11/solidity-data-storage/

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的plsql存储过程修改后怎么保存_Solidity变量存储位置与gas成本详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。