首先建立一個為我們初始化web3客戶端的模組:
請注意,本文中的每個程式碼段都是一個單獨的js檔案,我們將其與index.js結合在一起
該模組接收Web3包並返回一個初始化的客戶端。 我在rinkeby測試網上使用了一個Infura Ethereum節點,並且如果您決定也這樣做(我建議這樣做),請確保使用正確的金鑰替換YOUR_INFURA_API_KEY。
接下來,我們將建立實際的交易檢查器:
我們的第二個模組使用該web3客戶端來查詢實際網路。我們有一個私有account變數,您應將其替換為您感興趣的地址,然後返回checkLastBlock函式。首先我們檢索最新的區塊,並將數字記錄到控制檯。這樣的程式碼塊看起來就是這樣(我排除了一些對我們沒有用的欄位):
您可以看到諸如number、nonce和hash之類的欄位,但我們現在真正感興趣的是transactions欄位。這是一個陣列,包含該塊中包含的所有事務雜湊。
在transactionChecker.js的第9行,我們檢查block和block.transactions陣列是否不為空,在第10行,我們遍歷該陣列。對於陣列中的每個交易雜湊,我們請求實際交易。事務如下所示:
如果我們現在發現to欄位(事務接收端的地址)等於我們的地址(不要忘記toLowerCase()函式),那麼我們已經找到了要查詢的內容,並且可以將一些資料記錄到控制檯。(如果事務不包含“收件人”欄位,則為合約建立)
底部的間隔功能每7秒檢查一次當前區塊。我選擇此數字是因為以太坊的平均出塊時間為15秒,我們不想錯過任何區塊。該程式的問題在於它不依賴統計異常值。例如如果一個區塊在7秒內被挖掘,則可能會完全丟失該區塊。而且如果我們嘗試透過減少輪詢間隔來緩解這種情況,則會發現我們需要一個非常快速的Internet連線來處理所有非同步網路I/O。
有利的一面是,我們可以擴充套件此指令碼,例如檢查一系列區塊之間的所有到該帳戶的交易,如下所示:
也不要忘記返回這個函式。
如果您對我的模組編寫方式完全感到困惑:我匯出所謂的工廠函式,這是JavaScript的絕佳設計模式。
第二個程式利用以太坊的pub/sub。pub/sub是一個系統,釋出者透過該系統不斷向網路廣播與特定主題相關的事件,客戶端(訂閱者)可以訂閱這些事件。這比像我們在第一個程式中那樣不停地對網路進行投票要好得多,也快得多。但是您必須考慮以下幾個方面:
- 通知是實時傳送的,用於當前事件,而不是過去事件。可以調整前一個程式以搜尋一系列塊之間的事務,但這對該程式不起作用。
- 訂閱需要全雙工連線。幸運的是,Infura和Geth都以websocket的形式提供了這種連線。
由於我們是實時監控帳戶,因此這些要點不會打擾我們,讓我們繼續。我現在在一個新的npm目錄中工作,如果您正在編碼,請記住這一點。
首先我們必須建立我們的客戶。對於此程式,我們需要一個普通的http提供程式以及一個websocket提供程式。在我們的程式碼中,我們將兩者都返回到一個物件中-web3http將是http客戶端,web3是websocket客戶端:
現在對於第二個版本的事務檢查器:
讓我們把這個分解。有幾個主題可以訂閱,如newBlockHeaders或logs。日誌是理想的,但是這個訂閱主題還不起作用。所以我們將使用pendingTransactions訂閱。這發生在第5行。我們的訂閱是事件發射器,當有人傳送新交易(因此尚未確認)的那一刻,它就向我們傳送該交易的交易雜湊。這發生在函式watchTransactions中,我們在第11行公開了該函式。
由於這些事務還沒有被確認,我們將使用setTimeout函式來阻止每一個事件的進一步程式碼執行,直到一分鐘後,希望到那時,該事務將被挖掘出來。因為在那之後,我們實際上只做了與第一個程式相同的事情:檢索事務,並檢查我們的地址是否是接收端的地址。
最後是我們的索引檔案:
該程式更加優雅,並且不會佔用大量資源。但是請注意,這兩個程式都存在一些可靠性問題。我們討論的第一個區塊:如果區塊時間比平均區塊時間低很多,則可能會錯過該區塊。對於第二筆,如果有人支付了很少的費用,那麼肯定不會在一分鐘後被挖掘。在我的專案中,我將setTimeout增加到5分鐘,因為出於我的考慮,這仍然在範圍之內。但是如果要實際使用此功能,請小心。理想情況下,我們將訂閱日誌,但這仍然是真正的錯誤,因此是一個非常糟糕的主意。