獲取鏈上數據與糟糕的雜貨店購物

將日常常識應用於以太坊等上的批量數據獲取。

source : https://coinsbench.com/fetching-on-chain-data-vs-terrible-grocery-shopping-85a4cd8f9c6d by gaspacho.eth

This is what peak performance looks like.

有沒有想過一個人們真的不擅長做雜貨的世界?

想像一下,他們製作了一份詳細的雜貨清單,並且:
1.去商店
2. 拿起清單上的一個項目
3. 結帳並回家將物品放入冰箱
4. 回到商店購買下一件商品並重複步驟 2–3,直到他們的清單結束

現在,這種方法對您來說可能聽起來很荒謬。
在一次旅行中獲得全部物品清單並且只回家一次肯定更有效,對吧?
正如你可能從我在同義詞庫中沒有找到的“荒謬”這個詞的用法中推斷出的,我很聰明。而且我很高興確認您是正確的,最少的旅行更有效
可能的!

但是,有時無法使用給定的工具應用更好的邏輯。

當你想通過僅從用戶的瀏覽器調用他們的視圖函數來獲取 ERC721Enum(對於 ERC721 更糟)合約中用戶擁有的令牌 ID 列表時,這種情況實際上會發生。

ERC721Enum 合約帶有兩個基本的視圖函數來獲取用戶擁有的令牌 ID:
- “balanceOf”為您提供用戶擁有的代幣數量
- “tokenOfOwnerByIndex”,您必須為每個令牌調用一次(它為您提供每個擁有令牌的 ID)

這意味著如果用戶在該 ERC721Enum 合約中擁有 100 個代幣,您將需要進行 101 個視圖函數調用:
- 1x balanceOf 這會讓你知道用戶擁有 100 個代幣
- 100x tokenOfOwnerByIndex 填充用戶擁有的 100 個 ID 列表

如果您每秒可以進行 10 次調用,那麼對於您的用戶來說,這仍然是 10 秒的加載時間。

One request per ID is slow and sucks balls.

這並不理想,規模很差,而且我們開始看起來像那些不擅長做雜貨的人……還有什麼替代方案?

  1. 查看所有合約的事件並過濾所有進出用戶的傳輸(它有效,但可能很麻煩,尤其是對於具有數以百萬計的事件的流行集合。每個請求的最大事件也取決於用戶的節點提供商和連接的鏈。)
  2. 通過監控合約並定期更新來填充您自己的數據庫(在我看來,如果您只想製作一個簡單的 dApp,那就太矯枉過正了)
  3. 使用像 Moralis、Alchemy 等預製的 api 服務……(在這種情況下,您將取決於他們的服務、費用和有限的網絡選擇)
  4. 操他媽的,我要回到 web2 了(這個方法最簡單,但你無法獲取用戶擁有的令牌 ID)
  5. 下面的方法

在視圖函數中進行迭代

為了提高速度,我們需要在視圖函數內部進行這數百次迭代,而不是在用戶的瀏覽器上!需要時間的是視圖函數對節點的請求(很像去雜貨店和回家的旅程)。到目前為止,這種創建一個遍歷所有擁有的令牌的簡單視圖函數的方法並不是什麼新鮮事,但它也帶來了一些問題。

事實上,它提出了兩個主要挑戰:

  1. 視圖函數將有不可預測的最大迭代次數,並且可能會超時(如果用戶是一個大鯨魚並且有 2000 個令牌的餘額,那麼這個請求很可能會超時。
    是的,調用視圖函數可能會“耗盡燃料”並超時)
  2. “Gaspacho,我無法修改現有的 ERC721Enum 合約來添加我自己的小功能。你個傻鵝!” (確實如此!)

進入 TokenFetcher,一個只能查看的合約!

Exclusive footage of a smart contract right after deployment — circa 2022

TokenFetcher 合約通過以下方式解決了這兩個挑戰:

  1. 它的 ERC721EnumGetBatchTokensForUser 函數採用“索引開始”來了解何時開始,以及您想要返回的數組的“最大長度”。 這使您可以限制要獲取的批次的最大大小,從而限制函數內的最大迭代次數。 沒有更多的超時風險和更大的靈活性! (我們可以將用戶的 2000 個令牌分成 4 個請求,每個請求 500 個 ID,或者 10 個請求,每個請求 200 個 ID,……)。
  2. 它還需要一個 tokenAddress 並調用該合約地址的視圖函數。 這意味著這個“僅查看”合約與迄今為止和將來發布的每個 ERC721Enum 兼容,無需對這些現有合約進行任何修改!
Two requests to get 215 token IDs is fast and does not suck balls.

正如您可以想像的那樣,這大大減少了呼叫量。
在為最大的鯨魚賬戶(215 多個擁有的代幣)測試 Cyber​​Kongz VX Guardian 應用程序時,TokenFetcher 將加載時間從 20–30 秒減少到幾乎即時加載。只需要 2 個請求而不是 +216。

為什麼要打兩個電話?因為我選擇了相當保守的批量大小限制 (_maxLen) 為 200。所以我的第一次調用給了我前 200 個 ID,第二次調用給了剩下的 15 個 ID。如果我們到達末尾,視圖函數足夠聰明,可以調整批次的大小(如果我要求從索引 200 開始的接下來的 200 個 ID,它將停止在最大擁有的索引處並返回最後 15 個 ID 的數組)。

以同樣的邏輯,任何餘額低於 200 的人只需調用一次。由於請求將返回一批大小小於 200 的 ID,我們已經知道我們擁有所有 ID,根本不需要請求餘額。

以下是獲取所有用戶令牌 ID 的基本偽代碼示例:

Bluueuuargh! Pseudo-code! My eyes! Noooo!

TokenFetcher 的未來

目前 TokenFetcher 還有另外兩個有用的功能。一個允許您在一次調用中為單個或多個用戶獲取一批 ERC20 餘額,另一個允許您獲取任何 ERC721 的一批 ID(比 ERC721Enum 慢)。
該計劃是隨著時間的推移繼續改進合約並添加更多有用的視圖功能。

天哪,你成功了!

你已經讀完了我的第一篇博文,或者你一直向下滾動,這也很酷。

非常感謝您的閱讀,我希望這篇文章對您有任何價值。
我總是非常樂意談論反饋、代碼創意等……
所以不要猶豫在推特上與我聯繫!

有用的鏈接:

  • 您現在可以在 PolygonScan 上閱讀和使用 TokenFetcher 合約
  • 如果您想仔細查看或貢獻,這裡是 GitHub Repo
  • 如果您擁有任何 Cyber​​Kongz VX,您應該查看使用令牌獲取器的 Guardian 應用程序以加快加載速度。 Guardian App 是我為 @OwlOfMoistness 的 Guardian Contract 製作的 UI(在這裡查看他非常有趣的文章)!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store