跳到主要內容

發表文章

目前顯示的是有「智能合約」標籤的文章

【開發智能合約 - Solidity系列】實作篇Ep.16 - 匯入模組拚積木(Import)

  一套大型的智能合約通常都會拆分成許多小合約,並且透過匯入的方式拼裝而成,而這樣的匯入在Solidity世界中就是「Import」,就讓我們來看看「Import」到底怎麼運用吧! 基本的相對路徑匯入方式 假設目錄結構如下 example.sol other.sol 我們引入的方式就會是: import './other.sol' 也可以遠端匯入 import 'https://example.com/xxx.sol' 彈性的自訂名稱功能 當衝突發生時 當我們使用import時,預設會採用外部模組定義好的方法名稱,但這樣很容易發生衝突,假設外部有一個方法定義為「add()」,但內部也定義成相同名稱的方法時,會發生「DeclarationError」的錯誤,示範如下: external.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.7.0; function add(uint x, uint y) pure returns (uint) { return x + y; } example.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.7.0; import {add} from "./external.sol"; contract Example { function add(uint x, uint y) public pure returns (uint) { return x + y; } } 發生的錯誤如下: 如何補救呢? solidity也跟javascript一樣提供別名的方式,為外部的衝突方法特定一個內部名稱,避免與內部相互衝突,import的方式如下: import {add as extAdd } from "./external.sol"; 結語 這次介紹的import對於模組化非常的有幫助,尤其是分工協作的開發模式下,將需要的模組、功能規劃完畢之後就能夠各自進行開發,並且最終統一彙整,以拼裝積木的方式將各個功能模組兜在一起就能完成一份更加完整的智能合約,也讓合約的內容更加清晰,不會過於複...

【開發智能合約 - Solidity系列】實作篇Ep.15 - 映射的奧秘(Mapping)

  Mapping(映射)就像是字典表一樣,鍵入「什麼樣的標題」對應到「什麼樣的內容」,而標題就是從內容提煉出來的一種簡短快速識別的標的,透過這種方式,我們未來找尋內文時,只要先透過標題來查找,絕對會比直接找內文快上好幾倍,因此Mapping常常應用在查找事物上,它有點像一般程式語言的HashTable,主要目的在於透過對應表快速定位到詳細的資訊。 語法結構 /// 錢包餘額對應表 /// 錢包地址 <-剩餘-> 金額 mapping(address => uint) public _balances; 如何設定對應表? function updateBalance(uint newBalance) public { _balances[msg.sender] = newBalance; } 取得特定值 取得的方式非常簡單,我們宣告一個正確型別的變數進行承接之後,就能夠使用到儲存的值,進行加工後,再次設定。 uint _balance = _balances[msg.sender]; 刪除某一組 藉由delete關鍵字重新設定某一組key值。 delete _balances[msg.sender]; 相關的限制 - 鍵值(Key)僅能是Solidity的基本型態(strings、uint…),複雜型態(array、struct…)是不被允許的。 - 預設不支援iterable,因此無法自然的逐一處理,但提供自行實作的擴充能力, 請參考這裡 。 結語 Mapping是一種非常好用的資料結構,我們日常生活中諸如電話黃頁、書籤、五金行分類…等,舉凡與搜尋有關的整理,皆是在將龐雜的資訊濃縮成摘要,並且進行恰當的分類之後,讓我們更容易找尋這堆龐雜的資料,在區塊鏈的世界上亦是如此,錢包地址的背後可能夾藏的非常複雜的資訊,透過Mapping快速定位到關鍵位置,進行進一步的處理。 今天的範例都在這裡「 📦 solidity-remix-toturial/Ep15 」歡迎自行取用。 📚 更多關於Solidity的文章請看這裡… ---------------------------------------------------------------------------------- 喜歡撰寫文章的你,不妨來了解一下: W...

【開發智能合約 - 密碼學系列】編碼(Encode)、雜湊(Hash)、加密(Encrypt)傻傻分不清楚?

  密碼學能夠帶來什麼好處? 雲時代的來臨, 我們過往使用的桌面版應用程式逐漸搬上雲端, 但也帶來了極大的挑戰, 因為一但上雲就代表著需要面臨著四面八方的使用者, 我們並不知道這些使用者是否都是君子, 一個不小心如果出現漏洞就可能被攻擊, 導致系統損壞, 進而影響商譽、營收, 對企業來說是極大的傷害, 為了避免這樣的狀況發生, 資安防禦體系下的「密碼學」就扮演著極其重要的角色, 讓伺服器與客戶之間的溝通具有一層嚴格的防護網, 減少過程中被竊取、破壞的風險,伺服器的資料也能藉由「密碼學」獲得重要的保護效果,, 而「密碼學」也是一門博大精深的技術, 接下來的系列將以最簡單的方式講述密碼學的原理, 讓我們在資安意識抬頭的時代能夠增加一門功夫, 以因應時代需求的發展。 密碼學的「雜湊」與「加密」是區塊鏈發展的重要基石 區塊鏈可以拆解為「區塊」跟「鏈」,「區塊」就是一份份的資料帳本,而「鏈」就是由密碼學的Hash原理串起來的,每一個「區塊」中皆存放目前的Hash值與上一個區塊的Hash值,以此環環相扣連結成鏈。 因此我們才要好好的認識編碼、加密與雜湊的差異,避免名詞造成混淆,而後續的篇章也會深入來潭討雜湊函數的奧秘,讓我們對於區塊鏈的運作原理能夠有更進一步的認識。 編碼(Encode)、雜湊(Hash)、加密(Encrypt)究竟有什麼不同? 「編碼(Encode)」其實離我們很近…,原來電影情節常常出現的「摩斯密碼」成為了最貼切的例子。 相信我們常常看到電影情節中不時就出現「摩斯密碼」的名詞, 而密碼學之中的「編碼」也是類似這樣的概念, 簡單來說就是「資料內容替換成不易閱讀的符號、文字」以獲得保護, 過程中一但資料被擷取也不易閱讀, 是保護門檻中最基本的一項, 但也是最弱的, 因為一但編碼還原表被竊取, 或是使用大家都知道的編碼表, 就很容易進行還原破解。 常見的編碼格式 - URL編碼。 - UTF-8。 - ASCII。 - Unicode。 - Base64。 「雜湊(Hash)」就是碎片化與拼湊的過程 雜湊!雜湊!雜湊!其實並不難理解,簡單來說就是將「大量的資料碎片化之後再拼湊」,因此雜湊出來的結果並不能「逆推」回原文,那這樣帶來什麼好處呢? 試想,我們碎片化之後再拼湊出來的資訊一定是簡化過的,因此對於容量的佔用,資訊的精準度都具有一定的影響力,不論在搜尋或...

【開發智能合約 - Solidity系列】實作篇Ep.14 - 動動手來打造函式庫吧(Library)

  何謂函式庫? 簡單的來說就是把同類型常用的功能打包在一起,讓其他開發者能夠重複使用,達到資源有效利用的效果,以軟體開發來說就是減少多餘的程式碼,而Solidity語言中,Library可以視為物件導向中的靜態類別,不需要產生實體就能使用,因此能有效的減少Gas。 當我們剛完成一份合約時難免因為設計尚未考慮周全而導致複雜與重複的邏輯,但當我們回頭看看之後,就會發現有一些冗餘的程式碼可以進行整理,甚至分類到不同的地方,如同撰寫文章的草稿一樣,撰寫完畢後進行檢查,會發現有些區段可以挪移到外部的文章進行嵌入…等,讓一篇文章不至於過多的雜訊,而智能合約之中亦是如此,我們可以將共同複雜的邏輯整理到Library並歸類,之後倘若設計多份合約發現共同邏輯時就能夠引入並使用,非常靈活彈性。 建立一個函式庫來玩玩唄 - 情境: 自己打造一個數學函式,並檢核數值是否為「奇數」。 - 以「library」取代「contract」。 - 不需要有static。 - 不需要進行初始化建構(constructor)。 library Math { function checkOdd(uint value) public pure returns(bool) { uint remainder = value % 2; if(remainder!=0) return true; else return false; } } 如何使用? 引用別人撰寫好的Library會使用「import」來進行引用,而引用的對象也是一支Solidity撰寫的模組,使用起來也非常的直觀,直接以Library的名稱進行function的調用即可。 // SPDX-License-Identifier: MIT pragma solidity ^0.8.7.0; import "./math.sol"; contract Example { function checkOdd(uint value) public pure returns(bool) { return Math.checkOdd(value); } } 結語 此篇章適合對於Solid...

【開發智能合約 - Solidity系列】實作篇Ep.13 - 抽象化的合約(Abstract Contracts)

  圖片來源 我們在前幾篇有介紹到介面的用途,都知道介面可以制定規格,建議可以先複習一下這一篇「 【開發智能合約 - Solidity系列】實作篇Ep.10 - 標準化的介面(Interfaces) 」,而這次來介紹一個非常抽象的概念,名為「抽象化合約」,果然如其名! 不太容易理解,這種合約跟介面非常相似,都可以用來制定規格,而不同之處在於「抽象合約」可以被繼承,且「抽象合約」可以實作一些共同方法,但介面是不能實作的,也就是說介面有點設計的意味在,以「車」為例,介面僅設計出草圖,後續交由各種汽車、卡車…,進行不同的實作,只要遵照著規格走就好,怎麼實作就由各家決定,但「抽象合約」還可以先設計出「驅動」的方法,並藉由繼承的方式讓不同的車種皆擁有一樣的「驅動」方式,具有減少共同實作邏輯的特性。 以介面來實現,功能雖廣泛,但… 圖片來源 舉例來說,我們可能會設計一個「車」的介面,這個介面規格規定必須有「驅動」的功能,以燃油車來說會去實作「車」的介面,除了具備「驅動」以外,我們在燃油車的類別還可以實作「添加燃油」的功能,以符合燃油車的特性,那麼假設要製造其他燃油車型時,我們只要繼承「燃油車」這個類別就能基於燃油車進行擴充,以solidity語法設計如下: // 車的介面 interface ICar { // 驅動 function drive() external; } // 燃油車 contract FuelCar is ICar { // 實作燃油車的驅動方式 function drive() public override { ... } // 添加燃油 function fill() public { ... } } // 一般燃油轎車 contract GeneralCar is FuelCar { ...更多燃油車的方法 } 但…,有沒有發現,這樣的方式雖然非常直觀,但也帶來了層層實作繼承的複雜度與設計規劃的高水準。 我們用抽象合約來實現看看? 圖片來源 我們可以發現到,捨去介面後會由三層降為兩層,主要是因為抽象合約除了可以制定規格以外,也能實現共同方法,讓繼承的類別除了自行實作之外,亦可承襲共同方法。 abstract contract Fue...

【開發智能合約 - Solidity系列】實作篇Ep.11 - 繼承同源但不同意圖的函數覆寫(Function Overriding)

  圖片來源 我們在「 【開發智能合約 - Solidity系列】實作篇Ep.9 - 何謂繼承(Inheritance) 」有提到繼承的一些基本概念,然而在繼承的過程中我們可能會用到上游的方法,甚至加工,而方法名稱重複了,是否能被允許呢? 答案是「允許」的,就好比我們雖然繼承了父親的「處事技巧」,但在求新求變的時代中,或許傳統的老舊方法已經不適用於現代,因此就需要覆寫掉「處事技巧」這個方法,甚至基於傳統的方法之後進行擴增,而Solidity提供了繼承當然也支援了覆寫的方式,讓整個合約更加彈性。 但有幾個值得注意的是,當我們的合約欲設計為可覆寫的方法時,需要加入兩個重要的關鍵字,分別為: - virtual: 被繼承的合約方法需要標示此關鍵字之後,該方法才能被覆寫。 - override: 標示該方法以覆寫後的形式呈現。 contract Parent { /// @notice 工作 /// @dev 欲被繼承的方法應使用virtual關鍵字宣告 function doJob() public pure virtual { ... } } contract Child is Parent { /// @notice 工作 /// @dev 繼承並覆寫應使用override關鍵字宣告 function doJob() public pure override { ... } } 另外我們也可以用「擴充」的觀點來進行覆寫的功能加強。 contract Parent { event Log(string msg); /// @notice 工作 /// @dev 欲被繼承的方法應使用virtual關鍵字宣告 function doJob() public virtual { emit Log("i am parent"); } } contract Child is Parent { /// @notice 工作 /// @dev 繼承並覆寫應使用override關鍵字宣告 function doJob() public override { /// @de...