以太坊的組成部分
- P2P網絡:以太坊在以太坊網絡上運行,該網絡可在TCP端口30303上尋址,并運行一個協議。
- 交易:以太坊交易時網絡消息,其中包括發送者,接受者,值和數據的有效載荷
- 以太坊虛擬機:這是一個執行字節碼的基于堆棧的虛擬機
- 數據庫:以太坊的區塊鏈被稱為數據庫,本地存儲在每個節點上,包含序列化后的交易和系統交易
- 客戶端:以太坊有幾種可互操作的客戶端軟件實現
以太坊的組成部分
- 賬戶
- 普通賬戶,存儲和代碼均為空
- 合約賬戶,包含存儲和代碼
- 地址
- 交易
- 可以發送以太幣和信息
- 向合約發送的交易可以調用合約代碼,并以信息數據為函數參數
- 向空用戶發送信息,可以自動生成以信息為代碼塊的合約賬戶
- gas:以太坊用于執行智能合約的虛擬燃料,也就是以太幣交易的手續費
以太坊的貨幣
- 以太坊的貨幣單位成為以太(ether),又可以稱為ETH
代幣
- 代幣(token)被稱為通證,本意為令牌,代表有所有權的資產、貨幣、權限等在區塊鏈上的抽象
- 可代替通證
- 非同質通證
MetaMask數字錢包
私鑰?:965ed69e03a652eeb7d43ac461f8dd3306a6f3b27f64971b929a401ed966f370
INFURA水龍頭網站密碼:enfadfhaweiwer32#Dfsdh
使用Solidity編寫智能合約
在以太坊上使用 Solidity 編寫的智能合約執行每一步操作都需要燃燒一定數量的 Gas
- Remix寫一個水龍頭合約
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;contract Faucet {// 以太幣的默認發送數量uint public constant faucetAmount = 0.001 ether;// 向調用者發送以太幣function withdraw() public {require(address(this).balance >= faucetAmount, "Not enough funds in the faucet");payable(msg.sender).transfer(faucetAmount);}// 獲取當前合約的余額function getBalance() public view returns (uint) {return address(this).balance;}
}
使用Solidity編寫水龍頭合約測試
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;contract Faucet {// 以太幣的默認發送數量uint public constant faucetAmount = 0.0001 ether;// receive 函數會在合約接收以太幣時自動觸發receive() external payable {// 可以在這里添加一些處理邏輯,如果需要的話}// 向調用者發送以太幣function withdraw() public {require(address(this).balance >= faucetAmount, "Not enough funds in the faucet");payable(msg.sender).transfer(faucetAmount);}// 獲取當前合約的余額function getBalance() public view returns (uint) {return address(this).balance;}
}
使用有以太幣的賬號支付gas費用將該智能合約打包到區塊鏈中,讓所有節點都可以使用這個智能合約
這個是智能合約的地址,現在沒有以太幣儲備,所以沒有辦法調用withdraw()方法,也就是水龍頭方法
現在需要使用自己的賬戶為這個智能合約轉賬
此時合約里就有0.1個以太幣了
此時我的賬戶還剩0.3963個以太幣
調用withdraw提款代碼
由于withdraw提款代碼寫錯了,轉進智能合約里的錢取不走.........
并非提款代碼出錯了,是因為這是合約的內部交易,并不是某一個賬戶發到另外一個賬戶的操作,而是內部函數的行為,被稱為
合約內部交易
注意:調用者是水龍頭的調用者,所以每一次調用需要支付一定的gas費用
智能合約地址:0xde220a5e622347cF85519AA6C96B6E56D3086931
以太坊客戶端
- 基于以太坊規范的網絡:以太坊、以太坊經典、Ella、Expanse、Ubiq、Musicoin等等
- 以太坊客戶端軟件的維護人員,需要進行微小修改,以支持每個網絡的功能或屬性
- 以太坊的多種客戶端
- go-ethereum(Go):官方推薦,開發使用最多
- prity(Rust):最輕便的客戶端,在歷次以太坊網絡攻擊中表現卓越
- cpp-ehereum(C++)
- pyethapp(python)
- ethereumjs-lib(javascript)
- EthereumJ/Harmony(Java)
- 以太坊全節點
1.以太坊全節點,全節點是主鏈的一個副本,存儲并維護鏈上的所有數據,并隨時驗證新區塊的合法性
2.運行全節點將耗費巨大的成本,包括硬件資源和寬帶
3.以太坊開發不需要在實時網絡(主網)上運行全節點,我們可以用測試網絡來代替,也可以使用本地私鏈,或者使用服務商提供的基于云的以太坊客戶端,這些幾乎都可以執行所有操作
- 遠程客戶端和輕節點
- 遠程客戶端:不存儲區塊鏈的本地副本或驗證塊和交易。這些客戶端一般只提供錢包功能,可以創建和廣播交易。遠程客戶端可用于連接到現有網絡,MetaMask就是一個這樣的客戶端。
- 輕節點:不保存鏈上的區塊歷史數據,只保存區塊鏈當前的狀態。輕節點可以對塊和交易進行驗證。
以太坊客戶端Geth客戶端安裝
1.geth 是以太坊(Ethereum)網絡中最常用的 Go 語言實現的客戶端。它是一個用于連接到以太坊網絡、參與共識算法、同步區塊鏈數據等操作的命令行工具。
2.源碼安裝
yum install git
// 從GitHub上克隆文件到Linux當前的工作目錄下
git clone https://github.com/ethereum/go-ethereum.git
// 更改go語言的代理服務器網站,國內的下載速度更快
go env -w GOPROXY=https://goproxy.cn
// 下載nvm,配置環境變量
// 使用nvm快捷下載node.js和npm
make geth
根本安裝不了,老古董教程。
// 更新以下基礎工具和程序
yum update -y && yum install git bzip2 gcc-c++ ntp epel-release nodejs -y
// 下載cmake,智能合約的編寫需要c++
make geth
JSON-RPC
1.訪問以太坊節點:JSON-RPC允許開發者通過網絡與運行在本地或遠程服務器上的以太坊節點進行通信。這樣,開發者可以在應用程序中通過RPC調用訪問以太坊節點的功能。
2.查詢區塊鏈信息:使用JSON-RPC,開發者可以查詢有關區塊鏈的信息,例如獲取最新區塊號、查看賬戶余額、獲取交易歷史等。這使得開發者能夠在應用程序中實時監視區塊鏈狀態。
3.創建和發送交易:JSON-RPC允許開發者創建和發送交易到以太坊網絡。這包括發送以太幣、調用智能合約等操作。通過JSON-RPC,開發者可以構建應用程序來實現去中心化的交易和智能合約調用。
4.管理以太坊賬戶:開發者可以使用JSON-RPC創建新賬戶、解鎖/鎖定賬戶、更改密碼等。這些功能對于管理用戶賬戶、實現身份驗證和保護私鑰等方面都很重要。
5.訂閱事件:JSON-RPC支持訂閱機制,開發者可以通過訂閱關鍵事件(如新區塊、交易確認等)來獲得實時的區塊鏈更新。這對于構建實時應用程序和監控工具非常有用。
6.合約交互:通過JSON-RPC,開發者可以與以太坊上的智能合約進行交互。這包括調用合約的函數、查詢合約狀態等。
以太坊賬戶類型
- 外部賬戶
- 有對應的以太幣余額
- 可發送交易(轉幣或觸發合約代碼)
- 由用戶私鑰控制
- 沒有關聯代碼
- 合約賬戶
- 有對應的以太幣余額
- 有關聯的代碼
- 由代碼控制
- 可通過交易或來自其它合約的調用消息來觸發代碼執行
- 執行代碼時可以操作自己的存儲空間,也可以調用其它合約
以太坊交易(Transaction)
- 消息的接受方地址
- 發送方簽名
- 金額(VALUE)
- 數據(DATA,可選)
- START GAS
- GAS PRICE
消息(Message)
- 合約可以向其它合約發送“消息”
- 消息是不會被序列化的虛擬對象,只存在于以太坊執行環境中
- 可以看作函數調用
- 消息發送方
- 消息接收方
- 金額(VALUE)
- 數據(DATA,可選)
- START GAS
合約
- 可以讀寫自己的內部存儲(32字節key-value的數據庫)
- 可向其它合約發送消息,依次觸發執行
- 一旦合約運行結束,并且由它發送的消息觸發的所有子執行都結束,EVM就會中止運行,直到下次交易被喚醒
注意:以太坊其實就是一個大的全局單例狀態機,它的狀態的改變就是靠交易來觸發,而且交易時唯一可以觸發狀態的改變的事務。
合約也不是自己運行的,以太坊也不會“在后臺”運行。以太坊上的一切變化都始于交易
交易數據結構(交易是包含以下數據的序列化二進制消息)
- nonce:由發起人EOA發出的序列號,用于防止交易消息重播
- gas price:交易發起人愿意支付的gas單價(wei)
- start gas:交易發起人愿意支付的最大gas量
- to:目的以太坊地址
- value:要發送到目的地的以太數量
- data:可變長度二進制數據負載(payload)
- v,r,s:發起人EOA的ECDSA簽名的三個組成部分
- 交易消息的結構使用遞歸長度前綴(RLP)編碼方案進行序列化,該方案專為在以太坊中準確和字節完美的數據序列化而創建
交易的value和data
- 僅有value的交易就是一筆以太的付款
- 僅有data的交易一般是合約調用
- 進行合約調用的同時,我們除了傳輸data,還可以發送以太,從而交易中同時包含data和value
- 沒有value和data的交易,只是在浪費gas,但是是有效的
以太坊虛擬機(EVM)
- 以太坊虛擬機EVM是智能合約的運行環境
- 作為區塊驗證協議的一部分,參與網絡的每個節點都會運行EVM。他們會檢查正在驗證的塊中列出的交易,并運行由EVM中的交易觸發代碼
- EVM不僅是沙盒封裝的,而且是完全隔離的,也就是說EVM中運行的代碼是無法訪問網絡、文件系統和其它進程的,甚至智能合約之間的訪問也是受限的。
- 合約以字節的格式存在于區塊鏈上。
- 合約通常以高級語言編寫,通過EVM編譯器編譯為字節碼,最終通過客戶端上載部署到區塊鏈網絡中。
交易的接受者(to)
- 交易接收者在to字段中指定,是一個20字節的以太坊地址。地址可以是EOA或合約地址。
- 如果交易發送到無效地址,將銷毀發送的以太,使其永遠無法訪問。
- 驗證接收人地址是否有效的工作,應該在用戶界面一層完成。
EVM指令集
- 所有的指令都是針對“256位的字”這個基本的數據類型來進行操作
- 具備常用的算數、位、邏輯和比較操作,也可以做到有條件和無條件跳轉
- 合約可以訪問當前區塊的相關屬性,比如它的塊高度和時間戳
消息調用
- 合約可以通過消息調用的方式來調用其它合約或者發送以太幣到非合約賬戶
- 合約可以決定在其內部的消息調用中,對于剩余的gas,應發送和保留多少
- 如果在內部消息調用時發送了out-of-gas異常(或其它任何異常),這將由一個被壓入棧頂的錯誤值所指明;此時只有與該內部消息調用一起發送的gas會被消耗
委托調用
- 一種特殊類型的消息調用
- 目標地址的代碼將在發起調用的合約的上下文中執行,并且msg.sender和msg.value不變
- 可以由此實現“庫”:可重復的代碼庫可以放在一個合約的存儲上,通過委托調用引入相應的代碼
合約的創建和自毀
- 通過一個特殊的消息調用create calls,合約可以創建其它合約(不是簡單的調用零地址)
- 合約代碼從區塊鏈上移除的唯一方式是合約在合約的地址上的執行自毀操作selfstruct;合約賬戶上剩余的以太幣會發送給指定的目標,然后其存儲和代碼從狀態中被移除