eth開發入門門檻
⑴ 011:Ethash演算法|《ETH原理與智能合約開發》筆記
待字閨中開發了一門區塊鏈方面的課程:《深入淺出ETH原理與智能合約開發》,馬良老師講授。此文集記錄我的學習筆記。
課程共8節課。其中,前四課講ETH原理,後四課講智能合約。
第四課分為三部分:
這篇文章是第四課第一部分的學習筆記:Ethash演算法。
在介紹Ethash演算法之前,先講一些背景知識。其實區塊鏈技術主要是解決一個共識的問題,而共識是一個層次很豐富的概念,這里把范疇縮小,只討論區塊鏈中的共識。
什麼是共識?
在區塊鏈中,共識是指哪個節點有記賬權。網路中有多個節點,理論上都有記賬權,首先面臨的問題就是,到底誰來記帳。另一個問題,交易一定是有順序的,即誰在前,前在後。這樣可以解決雙花問題。區塊鏈中的共識機制就是解決這兩個問題,誰記帳和交易的順序。
什麼是工作量證明演算法
為了決定眾多節點中誰來記帳,可以有多種方案。其中,工作量證明就讓節點去算一個哈希值,滿足難度目標值的勝出。這個過程只能通過枚舉計算,誰算的快,誰獲勝的概率大。收益跟節點的工作量有關,這就是工作量證明演算法。
為什麼要引入工作量證明演算法?
Hash Cash 由Adam Back 在1997年發表,中本聰首次在比特幣中應用來解決共識問題。
它最初用來解決垃圾郵件問題。
其主要設計思想是通過暴力搜索,找到一種Block頭部組合(通過調整nonce)使得嵌套的SHA256單向散列值輸出小於一個特定的值(Target)。
這個演算法是計算密集型演算法,一開始從CPU挖礦,轉而為GPU,轉而為FPGA,轉而為ASIC,從而使得算力變得非常集中。
算力集中就會帶來一個問題,若有一個礦池的算力達到51%,則它就會有作惡的風險。這是比特幣等使用工作量證明演算法的系統的弊端。而以太坊則吸取了這個教訓,進行了一些改進,誕生了Ethash演算法。
Ethash演算法吸取了比特幣的教訓,專門設計了非常不利用計算的模型,它採用了I/O密集的模型,I/O慢,計算再快也沒用。這樣,對專用集成電路則不是那麼有效。
該演算法對GPU友好。一是考慮如果只支持CPU,擔心易被木馬攻擊;二是現在的顯存都很大。
輕型客戶端的演算法不適於挖礦,易於驗證;快速啟動
演算法中,主要依賴於Keccake256 。
數據源除了傳統的Block頭部,還引入了隨機數陣列DAG(有向非循環圖)(Vitalik提出)
種子值很小。根據種子值生成緩存值,緩存層的初始值為16M,每個世代增加128K。
在緩存層之下是礦工使用的數據值,數據層的初始值是1G,每個世代增加8M。整個數據層的大小是128Bytes的素數倍。
框架主要分為兩個部分,一是DAG的生成,二是用Hashimoto來計算最終的結果。
DAG分為三個層次,種子層,緩存層,數據層。三個層次是逐漸增大的。
種子層很小,依賴上個世代的種子層。
緩存層的第一個數據是根據種子層生成的,後面的根據前面的一個來生成,它是一個串列化的過程。其初始大小是16M,每個世代增加128K。每個元素64位元組。
數據層就是要用到的數據,其初始大小1G,現在約2個G,每個元素128位元組。數據層的元素依賴緩存層的256個元素。
整個流程是內存密集型。
首先是頭部信息和隨機數結合在一起,做一個Keccak運算,獲得初始的單向散列值Mix[0],128位元組。然後,通過另外一個函數,映射到DAG上,獲取一個值,再與Mix[0]混合得到Mix[1],如此循環64次,得到Mix[64],128位元組。
接下來經過後處理過程,得到 mix final 值,32位元組。(這個值在前面兩個小節《 009:GHOST協議 》、《 010:搭建測試網路 》都出現過)
再經過計算,得出結果。把它和目標值相比較,小於則挖礦成功。
難度值大,目標值小,就越難(前面需要的 0 越多)。
這個過程也是挖礦難,驗證容易。
為防止礦機,mix function函數也有更新過。
難度公式見課件截圖。
根據上一個區塊的難度,來推算下一個。
從公式看出,難度由三部分組成,首先是上一區塊的難度,然後是線性部分,最後是非線性部分。
非線性部分也叫難度炸彈,在過了一個特定的時間節點後,難度是指數上升。如此設計,其背後的目的是,在以太坊的項目周期中,在大都會版本後的下一個版本中,要轉換共識,由POW變為POW、POS混合型的協議。基金會的意思可能是使得挖礦變得沒意思。
難度曲線圖顯示,2017年10月,難度有一個大的下降,獎勵也由5個變為3個。
本節主要介紹了Ethash演算法,不足之處,請批評指正。
⑵ ETH是什麼怎樣購買才好
ETH是以太幣的編碼,而以太幣是以太坊區塊鏈上的代幣,以太幣目前有不少人在投資交易。於新手而言,可能對以太幣的操作方式有些迷糊,其實,以太幣交易僅需於領域王國上預測其價格漲跌走勢判斷正確即獲利。雖說單筆交易最低5美元,交易周期短至30秒,但注意不要頻頻交易與重倉交易。
⑶ eth錢包開發(nodejs)(一)
tips: sendEthTransaction方法將eth轉賬和token轉賬合並,轉賬eth時將tokenValue賦值為0,轉賬token時將value賦值為0即可
⑷ 【ETH錢包開發04】web3j轉賬ERC-20 Token
在上一篇文章中講解了ETH轉賬,這一篇講一下ERC-20 Token轉賬。
【ETH錢包開發03】web3j轉賬ETH
1、直接用web3j的API
2、java/Android調用合約的 transfer 方法
不管用哪種方式來轉賬,你都需要先寫一個solidity智能合約文件來創建ERC-20 Token,然後部署合約,最後才是通過客戶端來調用。
注意:erc-20 token轉賬和eth轉賬的區別如下:
1、erc-20 token創建交易對象用的是這個方法 createTransaction
2、erc-20 token需要構建 Function ,它其實對應的就是erc-20 token合約中的那些方法。它的第一個參數就是ERC20中那幾個方法的名稱,第二個參數的話就是對應合約方法中的參數,第三個參數是和第二個參數對應的,按照我那樣就行了。轉賬的話就是 transfer ,我們從合約的 transfer 可以看到第一個參數是收款地址,第二個參數是金額,所以 Function 這里對應起來就好。
這種方法不需要使用web3j封裝的方法,而是直接調用solidity合約的方法。
步驟
1、web3j載入一個已經部署的合約
2、驗證合約是否載入成功 isValid
3、如何載入合約成功,則調用合約的 transfer 方法
注意:
1、這里的 TokenERC20 是根據solidity智能合約生成的對應的Java類,用於java/Android和智能合約交互的,如果你對這里不太清楚,不妨看看我之前的一篇文章。
以太坊Web3j命令行生成Java版本的智能合約
2、如果載入合約失敗,可能的一個原因是合約對應的Java類中的 BINARY 的值不對,這個值是你部署合約成功之後的bytecode,你最好檢查對比一下。
我發送一筆交易,可以通過這個地址查詢
https://rinkeby.etherscan.io/tx/
⑸ 006:MPT與RLP|《ETH原理與智能合約開發》筆記
待字閨中開發了一門區塊鏈方面的課程:《深入淺出ETH原理與智能合約開發》,馬良老師講授。此文集記錄我的學習筆記。
課程共8節課。其中,前四課講ETH原理,後四課講智能合約。
第二課分為三部分:
這篇文章是第二課第二部分的學習筆記:MPT與RLP。
MPT,Merkle Patricia Tree,結合了Merkle Tree(默克爾樹)和 Patricia Tree(帕特里夏樹)的一種數據結構。
RLP,Recursive Length Prefix,一種編碼方法。
這是兩個非常重要的數據結構,在以太坊的區塊和交易中都有用到。
先分別介紹一下Merkle Tree 和 Patricia Tree。
Merkle Tree 和 Patricia Tree Merkle Tree 和 Patricia Tree
默克爾樹的解釋:對每一個交易計算其散列值(Hash),再對兩個散列值求他們的散列值。如果是奇數個,就把最後一個重復一次。最後得到的一個散列值就是默克爾樹根的值。如圖,交易1、1、2、3的散列值分別是HASH0、HASH1、HASH2、HASH3。HASH0和HASH1結合在一起計算散列值得HASH01,HASH2和HASH3結合在一起計算散列值得HASH23,接下來HASH01、HASH23結合在一起,計算散列值得HASH0123。
採用默克爾樹的好處是可以方便的判斷一個交易是否在區塊中。
Patricia Tree,可稱為壓縮前綴樹。如上圖右半部分。相同的前綴在同一分支中,後面一同的部分分叉出來,如test和toast,都有相同的t,est和oast在兩個分支中。
這個結構的好處是節省空間,因為每一級的鍵值可以是多個字元。
了解了Merkle Tree 和 Patricia Tree後,再來看這兩者混合後的產物——MPT。
這里的原理知識單獨來看不易理解,和具體的例子結合起來才更容易理解,此處先放上課件截圖。在後面的例子中再做說明。
Merkle Patricia Tree 規格 Merkle Patricia Tree 規格
在MPT中,還涉及到三個小的編碼標准。主要規則如圖。下面結合兩個例子說明一下。
三個編碼標准 三個編碼標准
HEX編碼的例子:從ASCII碼表中可以查出,b的十六進制編碼為62,o的十六進制編碼為6F,F在十六進制中就是15的意思。因為這是個葉子節點,最後加上0x10表示結束,也就是16。所以最後的編碼為[6 2 6 15 6 2 16]
HEX-Prefix編碼的例子:[6 2 6 15 6 2 16],將其最後的0x10去掉,[6 2 6 15 6 2]。前面補一個四元組,其中(倒數)第0位是區分奇偶信息的,[6 2 6 15 6 2]是偶數位,第0位是0;第1位是區分節點類型的,這是葉子節點,第1位是1。所以這個四元組就是0010是2。「如果輸入key的長度是偶數則再添加一個四元組0x0在flag四元組之後。」,所以,最終的前綴是0x20。本例最終的結果,[32 98 111 98],即[0x20, 0x62, 0x6F, 0x62]
下面是綜合性的例子,通過它可以很方便地理解前面的理論知識。值得多看幾篇,仔細休會。
初始的key-value對為:
其中,<>中的數據為key的16進制編碼。
MPT.jpg MPT.jpg
因為4組數據都有公共的6,所以這個節點的值為6,長度為1,奇數;節點類型:擴展節點;所以前綴就是0001,即1。
這是個擴展節點,它的值是一個Hashvalue,它指向一個分支節點。Hashvalue,具體指的是分支節點RLP編碼的結果的散列值。(RLP見下小節)
分支節點。上面4組數據的第2位是4和8兩種情況。在4的位置上存的是下面的擴展節點的散列值,在8的位置上存的是下面的葉子節點的散列值。
葉子節點。以68開頭的只有一個了。所以這個節點上的四元組就是6f727365了。它是偶數位。前綴是0x20(同前文HEX-Prefix編碼的例子)。這個葉子節點的value值為'stallion'。
擴展節點。在64之後,公共的部分是6f,這個擴展節點的key即為6f,前綴為0000,即00。這個擴展節點的value存放的是一個hashvalue,指向下一個節點,一個分支節點。
分支節點。646f已經表達完,這個節點的value值就是646f對應的值,'verb'。
除此之外,646f之後就是6,所以在這個分支節點的6位置上有一個散列值,指向下一個節點。
擴展節點。在646f6之後,公共的部分是7,其長度為1,奇數。所以前綴為0001。這個節點的value是一個散列值,指向下一個節點。
分支節點。646f67已經表達完,這個節點的value值就是646f67對應的值,'puppy'。
除此之外,646f67之後就是6,所以在這個分支節點的6位置上有一個散列值,指向下一個節點。
葉子節點。key為5,value為'coin'。長度為1,奇數,前綴0011,即3。
整個分析過程結束。可結合上圖和前文的理論多加復習。
這小節也是理論性較強,通過例子可以方便理解。先放上課件,再根據我的理解舉更多的例子。同樣,學習方法也是理論和例子配合學習。其中,list的例子在下篇文章的上機實驗部分再列舉。 RLP的編碼標准 RLP的編碼標准 再舉幾個例子 再舉幾個例子
⑹ ETH開發實踐——批量發送交易
在使用同一個地址連續發送交易時,每筆交易往往不可能立即到賬, 當前交易還未到賬的情況下,下一筆交易無論是通過 eth.getTransactionCount() 獲取nonce值來設置,還是由節點自動從區塊中查詢,都會獲得和前一筆交易同樣的nonce值,這時節點就會報錯 Error: replacement transaction underpriced
在構建一筆新的交易時,在交易數據結構中會產生一個nonce值, nonce是當前區塊鏈下,發送者(from地址)發出的交易(成功記錄進區塊的)總數, 再加上1。例如新構建一筆從A發往B的交易,A地址之前的交易次數為10,那麼這筆交易中的nonce則會設置成11, 節點驗證通過後則會放入交易池(txPool),並向其他節點廣播,該筆交易等待礦工將其打包進新的區塊。
那麼,如果在先構建並發送了一筆從地址A發出的,nonce為11的交易,在該交易未打包進區塊之前, 再次構建一筆從A發出的交易,並將它發送到節點,不管是先通過web3的eth.getTransactionCount(A)獲取到的過往的交易數量,還是由節點自行填寫nonce, 後面的這筆交易的nonce同樣是11, 此時就出現了問題:
實際場景中,會有批量從一個地址發送交易的需求,首先這些操作可能也應該是並行的,我們不會等待一筆交易成功寫入區塊後再發起第二筆交易,那麼此時有什麼好的解決辦法呢?先來看看geth節點中交易池對交易的處理流程
如之前所說,構建一筆交易時如果不手動設置nonce值,geth節點會默認計算發起地址此前最大nonce數(寫入區塊的才算數),然後將其加上1, 然後將這筆交易放入節點交易池中的pending隊列,等到節點將其打包進區塊。
構建交易時,nonce值是可以手動設置的,如果當前的nonce本應該設置成11, 但是我手動設置成了13, 在節點收到這筆交易時, 發現pending隊列中並沒有改地址下nonce為11及12的交易, 就會將這筆nonce為13的交易放入交易池的queued隊列中。只有當前面的nonce補齊(nonce為11及12的交易被發現並放入pending隊列)之後,才會將它放入pending隊列中等待打包。
我們把pending隊列中的交易視為可執行的,因為它們可能被礦工打包進最新的區塊。 而queue隊列因為前面的nonce存在缺失,暫時無法被礦工打包,稱為不可執行交易。
那麼實際開發中,批量從一個地址發送交易時,應該怎麼辦呢?
方案一:那麼在批量從一個地址發送交易時, 可以持久化一個本地的nonce,構建交易時用本地的nonce去累加,逐一填充到後面的交易。(要注意本地的nonce可能會出現偏差,可能需要定期從區塊中重新獲取nonce,更新至本地)。這個方法也有一定的局限性,適合內部地址(即只有這個服務會使用該地址發送交易)。
說到這里還有個坑,許多人認為通過 eth.getTransactionCount(address, "pending") ,第二個參數為 pending , 就能獲得包含本地交易池pending隊列的nonce值,但是實際情況並不是這樣, 這里的 pending 只包含待放入打包區塊的交易, 假設已寫入交易區塊的數量為20, 又發送了nonce為21,22,23的交易, 通過上面方法取得nonce可能是21(前面的21,22,23均未放入待打包區塊), 也可能是22(前面的21放入待打包區塊了,但是22,23還未放入)。
方案二是每次構建交易時,從geth節點的pending隊列取到最後一筆可執行交易的nonce, 在此基礎上加1,再發送給節點。可以通過 txpool.content 或 txpool.inspect 來獲得交易池列表,裡面可以看到pending及queue的交易列表。
啟動節點時,是可以設置交易池中的每個地址的pending隊列的容量上限,queue隊列的上容量上限, 以及整個交易池的pending隊列和queue隊列的容量上限。所以高並發的批量交易中,需要增加節點的交易池容量。
當然,除了擴大交易池,控制發送頻率,更要設置合理的交易手續費,eth上交易寫入區塊的速度取決於手續費及eth網路的擁堵狀況,發送每筆交易時,設置合理的礦工費用,避免大量的交易積壓在交易池。
⑺ 【ETH錢包開發02】導入錢包
本文主要講解通過助記詞、keystore、私鑰 3種方式來導入錢包。導入錢包就是說根據輸入的這3者中的一個去重新生成一個新的錢包。導入錢包的過程和創建的過程其實是差不多的。
根據助記詞導入錢包不需要原始密碼,密碼可以重新設置。根據用戶輸入的助記詞,先驗證助記詞的合規性(格式、個數等),驗證正確後,配合用戶輸入的密碼重新生成一個新的錢包。
驗證助記詞的合規性(格式、個數等)
助記詞導入錢包
通過私鑰導入錢包其實和創建錢包的過程基本一致。因為私鑰在導出的時候轉換成了16進制,所以在導入私鑰的時候,要把16進制轉換為byte數組。
keystore就是錢包文件,實際上就是錢包信息的json字元串。導入keystore是需要輸入密碼的,這個密碼是你最後導出keystore時的密碼。將keystore字元串變成walletFile實例再通過 Wallet.decrypt(password, walletFile); 解密,成功則可以導入,否則不能導入。
這是Web3j的API,程序走到這里經常OOM!
具體原因的話,我就不多說了,細節大家可以看這里
https://www.jianshu.com/p/41d4a38754a3
解決辦法
根據源碼修改 decrypt 方法,這里我用一個已經修改好的第三方庫
修改後的解密方法
導入Kestore
1、導入助記詞和私鑰是不需要以前的密碼的,而是重新輸入新的密碼;導入Keystore則需要以前的密碼,如果密碼不正確,會提示地址和私鑰不匹配。
2、關於備份助記詞
用過imtoken的同學可以看到imtoken是可以導出(備份)助記詞的。這個一開始我也很困惑,後來了解到其實它實在創建錢包的時候,在app本地保存了助記詞,導出只是講數據讀取出來而已。還有一點,imtoken一旦備份了助記詞之後,之後就沒有備份那個功能了,也就是說助記詞在本地存儲中刪除了;而且導入錢包的時候也是沒有備份助記詞這個功能的。
⑻ iOS開發ETH錢包
框架:web3swift => https://github.com/matter-labs/web3swift
1、創建錢包
2、導入錢包
3、獲取余額
4、轉賬
5、調用智能合約
注意:
1、網路的切換
測試網 let web3 = Web3.InfuraRinkebyWeb3()
主網 let web3 = Web3.InfuraMainnetWeb3()
2、轉賬相關的,必須配置
KeystoreManager
TransactionOptions
3、調用智能合約,參數不對,會直接返回nil
⑼ 【ETH錢包開發03】web3j轉賬ETH
在之前的文章中,講解了創建、導出、導入錢包。
【ETH錢包開發01】創建、導出錢包
【ETH錢包開發02】導入錢包
本文主要講解以太坊轉賬相關的一些知識。交易分為ETH轉賬和ERC-20 Token轉賬,本篇先講一下ETH轉賬。
1、解鎖賬戶發起交易。錢包keyStore文件保存在geth節點上,用戶發起交易需要解鎖賬戶,適用於中心化的交易所。
2、錢包文件離線簽名發起交易。錢包keyStore文件保存在本地,用戶使用密碼+keystore的方式做離線交易簽名來發起交易,適用於dapp,比如錢包。
本文主要講一下第二種方式,也就是錢包離線簽名轉賬的方式。
交易流程
1、通過keystore載入轉賬所需的憑證Credentials
2、創建一筆交易RawTransaction
3、使用Credentials對象對交易簽名
4、發起交易
注意以下幾點:
1、Credentials
這里,我是通過獲取私鑰的方式來載入 Credentials
還有另外一種方式,通過密碼+錢包文件keystore方式來載入 Credentials
2、nonce
nonce是指發起交易的賬戶下的交易筆數,每一個賬戶nonce都是從0開始,當nonce為0的交易處理完之後,才會處理nonce為1的交易,並依次加1的交易才會被處理。
可以通過 eth_gettransactioncount 獲取nonce
3、gasPrice和gasLimit
交易手續費由gasPrice 和gasLimit來決定,實際花費的交易手續費是 gasUsed * gasPrice 。所有這兩個值你可以自定義,也可以使用系統參數獲取當前兩個值
關於 gas ,你可以參考我之前的一篇文章。
以太坊(ETH)GAS詳解
gasPrice和gasLimit影響的是轉賬的速度,如果gas過低,礦工會最後才打包你的交易。在app中,通常給定一個默認值,並且允許用戶自己選擇手續費。
如果不需要自定義的話,還有一種方式來獲取。獲取以太坊網路最新一筆交易的 gasPrice ,轉賬的話, gasLimit 一般設置為21000就可以了。
Web3j還提供另外一種簡單的方式來轉賬以太幣,這種方式的好處是不需要管理nonce,不需要設置gasPrice和gasLimit,會自動獲取最新一筆交易的gasPrice,gasLimit 為21000(轉賬一般設置成這個值就夠用了)。
這個問題,我想是很多朋友所關心的吧。但是到目前為止,我還沒有看到有講解這方面的博客。
之前問過一些朋友,他們說可以通過區塊號、區塊哈希來判斷,也可以通過Receipt日誌來判斷。但是經過我的一番嘗試,只有 BlockHash 是可行的,在web3j中根據 blocknumber 和 transactionReceipt 都會報空指針異常。
原因大致是這樣的:在發起一筆交易之後,會返回 txHash ,然後我們可以根據這個 txHash 去查詢這筆交易相關的信息。但是剛發起交易的時候,由於手續費問題或者乙太網絡擁堵問題,會導致你的這筆交易還沒有被礦工打包進區塊,因此一開始是查不到的,通常需要幾十秒甚至更長的時間才能獲取到結果。我目前的解決方案是輪詢的去刷 BlockHash ,一開始的時候 BlockHash 的值為0x00000000000,等到打包成功的時候就不再是0了。
這里我使用的是rxjava的方式去輪詢刷的,5s刷新一次。
正常情況下,幾十秒內就可以獲取到區塊信息了。
區塊確認數=當前區塊高度-交易被打包時的區塊高度。
⑽ ETH開發實踐——合約地址是怎麼得來的
在把智能合約成功部署到ETH網路時,會得到合約地址,那麼,這個合約地址是由什麼決定的呢?合約地址由合約創建者的地址(sender address)和這筆部署交易中的nonce(發送者的累積交易次數)決定,將 sender 和 nonce 經過RLP編碼後,再進行Keccak-256(SHA3)散列, 最後裁掉前面12個位元組即得到合約地址。
example in js: