背景
在以太坊原生語言solidity中調用API可以將鏈下數據傳輸至鏈上智能合約應用。世界各地的開發者可以利用Chainlink的去中心化區塊鏈預言機將鏈下真實世界的數據和事件接入區塊鏈環境。Chainlink內置的核心適配器可以輕鬆配置並驗證來自任何開放API的數據。
然而,Chainlink核心適配器往往在靈活性和功能性上無法滿足開發者所有的需求,比如:
- API接口認證(保護API祕鑰隱私)
- 保障隱私,降低延遲,並實現高吞吐量的鏈下計算,以降低gas費用
- 將數據傳輸至其他區塊鏈(互操作性)
- 其他核心適配器無法滿足的功能
外部適配器可以訪問優質數據並使智能合約能夠非常靈活地連接至付費web API。目前眾多安全可靠的預言機網絡都已接入外部適配器,其中包括超過35個價格參考數據,總共保障了30多億美元的DeFi資產。本文將探討以下問題:
- 什麼是外部適配器?
- 如何開發外部適配器?
- 如何運行外部適配器?
- 如何使用外部適配器?
什麼是外部適配器?
適配器通常分成兩類:
- 核心適配器
- 外部適配器
核心適配器是Chainlink核心節點客戶端內置的功能。Httpget、Copy和Jsonparse都屬於核心適配器。而外部適配器則是指開發者根據具體要求基於Chainlink預言機網絡定製化的功能。本文不會深入探討接入其他區塊鏈的技術細節,但是Chainlink外部適配器和外部啟動器實現定製化,將使Chainlink能夠與任何區塊鏈兼容,因此能極大豐富其功能,這是Chainlink兩大關鍵價值的其中一個。
這裡順便提一句,如果想要智能合約在端到端保持去中心化,就必須允許其他預言機節點也運行外部適配器。可以把外部適配器想象成Chainlink節點的開源軟件包。也就是說,你可以選擇不親自運行節點,但同時也能夠在智能合約中使用節點的定製化功能。你可以讓其他節點幫你運行外部適配器,現在有許多項目集成了Chainlink但不親自運行節點。這樣,智能合約開發者就可以專注於去中心化應用的商業邏輯,並將節點運行工作交給專業的節點運營商處理。你可以在market.link等第三方節點分類信息平臺上掛出你的外部適配器,也可以#ask-a-node-operator (委託節點運營商)運行你的外部適配器,你只需要負責測試和開發工作。
當然,如果你想要自己運行節點,也完全可以這麼做!
如何開發外部適配器
快速啟動
開發外部適配器最簡單的方式就是把它做成一個API接口。這樣一來,就可以靈活定製鏈下計算方式,使用任何編程語言,並且調用API傳輸並接收數據。關於如何開發API接口有許多教學資料,接下來我們將在nodejs中看一個簡單的Chainlink適配器模板。另外還有python版本的示例 ,如果你感興趣也可以查看。我們會基於下面這個代碼庫進行開發,這是一個功能完整的外部適配器,你可以輕鬆定製所需的數據。你也可以從零開始開發,不過用這個代碼庫開發會簡單很多。
接下來,你需要使用yarn和nodejs。首先,將代碼庫克隆到本地,使用cd命令進入到項目中。
git clone https://github.com/thodges-gh/CL-EA-NodeJS-Template.git ExternalAdapterTemplate
cd ExternalAdapterTemplate
然後,安裝依賴並啟動API服務器。
yarn
yarn start
API/外部適配器的服務器會被啟動,並等待被調用。
patrick@iMac: [~/code/ExternalAdapterTemplate - (master)] $ yarn start
yarn run v1.22.4
$ node app.js
Listening on port 8080!
要注意,Chainlink節點會掃描所有適配器,一旦發現了在它適配器/任務清單中的外部適配器,就會進行調用。我們可以自己調用一次,模擬Chainlink節點請求的過程。
這是一個curl命令,向我們剛開始運行的API服務器發送HTTP post請求。你可以在本地終端窗口嘗試一下。
curl -X POST -H "content-type:application/json" "http://localhost:8080/" --data '{ "id": 0, "data": { "from": "ETH", "to": "USD" } }'
jsonhttp://localhost:8080/
是API服務器等待響應的地址,--data
後面的參數是我們為了讓Chainlink節點看懂數據請求而發送的參數。Chainlink節點發送的請求包括:
- 一個
id
- 一個
data
object
格式如下: {"id":"0", "data":{}}
在data
object中,可以清楚地看到from
和to
參數。這些是我們設置的定製化參數,讓外部適配器能夠獲得各種不同的價格數據。可以看到,當運行curl腳本時,會返回以下結果:
{"jobRunID":0,"data":{"USD":441.49,"result":441.49},"result":441.49,"statusCode":200}
注:由於以太幣價格一直在變動,因此這裡的數字可能會發生變化!
json所有外部適配器都會返回一個對象,其中至少包含:
jobRunID
-
data
object
最好還能包含status
和result
字段,這樣可以輕鬆處理並改正錯誤。在這個示例中,返回的結果是441.49
,即當前以太幣價格。我們之所以會獲得這個數據,是因為我們的外部適配器也調用了一個API,那就是:
https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD
這個外部適配器實際上裡面包裹著一個API接口,這也是外部適配器的常見框架。
以上就是外部適配器的功能,那麼我們接下來看一下它的運行原理。
獲取天氣數據
在PatrickAlphaC模板代碼庫中的weather-api分支中可以查看。
OpenWeatherMap我們先來修改一下代碼,以便從一個新的API接口()獲取天氣數據。為了方便教學,我們先在這裡免費註冊,獲得一個免費的API祕鑰。賬號通過驗證後,我們就可以在這裡看到API祕鑰,以及城市當前天氣數據API文檔。注:你註冊後大概需要等待十分鐘祕鑰才會完全生效。
我們現在要把這個外部適配器稍作修改,本來它獲取的是以太幣價格,現在要改為獲取城市天氣數據。
我們要修改index.js
文件(如果要上線則需修改test/index_test.js測試文件
)。app.js
定義了外部適配器/API服務器響應請求的方式,我們現在先不用管。在之前示例裡的data
object中,我們使用了兩個參數,即from
和to
參數。我們可以通過更新customParams
來定製化參數:
更新前的customParams:
const customParams = {
base: ['base', 'from', 'coin'],
quote: ['quote', 'to', 'market'],
endpoint: false
}
更新後的customParams:
const customParams = {
city:['q', 'city', 'town'],
endpoint: false
}
這樣,我們無論輸入city
、town
還是q
,都表示city
。
createReqeust
常量是最關鍵的一個環節,因為這裡需要連接到URL。如果查看天氣數據文檔,可以看到這樣的一個示例地址:`https://api.openweathermap.org/data/2.5/weather?q=&appid=
可以輸入API祕鑰和城市名boston
,對API進行測試,然後將URL複製到瀏覽器(如果返回錯誤說API祕鑰無效,可以等幾分鐘再試一次)
用這個URL就可以知道需要做哪些更新:
更改前:
const endpoint = validator.validated.data.endpoint || 'price'
更改後:
const endpoint = validator.validated.data.endpoint || 'weather'
更改前:
const url = 'https://min-api.cryptocompare.com/data/${endpoint}'
更改後:
const url = 'https://api.openweathermap.org/data/2.5/${endpoint}'
現在我們要添加參數。我們的兩個參數是城市(文檔裡的城市是q
)和API祕鑰( appid
)
城市可以在原來的代碼上進行修改:
const fsym = validator.validated.data.base.toUpperCase()
改成:
const q = validator.validated.data.city.toUpperCase()
然而,我們不能將API祕鑰寫死在代碼中。
API認證
我們應該編輯這行代碼:
const tsyms = validator.validated.data.quote.toUpperCase()
將它改成:
const appid = process.env.API_KEY;
要將API祕鑰放到.envrc
文件中,而不是放到源代碼中,因此要新建這樣一個.envrc
文件:
export API_KEY=<YOUR_KEY_HERE>
別忘了要添加到.gitignore
中!如果你在運行curl命令測試時遇到任何問題,也可以在終端運行 export API_KEY=<API_KEY>
。
注:點擊這裡瞭解關更多環境變量
然後需要將參數從:
const params = {
fsym,
tsyms
}
改成:
const params = {
q,
appid
}
將結果從:
response.data.result = Requester.validateResultNumber(response.data, [tsyms])
改成:
response.data.result = Requester.validateResultNumber(response.data, ['main','temp'])
然後就搞定了!現在,main
object的temp
值就等於天氣API輸出的氣溫了,因此我們的response.data.result
參數如上所示。
現在你已經成功開發出了API祕鑰認證的外部適配器!
我們來調用一下API。
curl -X POST -H "content-type:application/json" "http://localhost:8080/" --data '{ "id": 0, "data": { "city":"Boston"} }
示例返回值:
{"jobRunID":0,"data":{"coord":{"lon":-71.06,"lat":42.36},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"base":"stations","main":{"temp":296.81,"feels_like":298.49,"temp_min":295.15,"temp_max":297.59,"pressure":1008,"humidity":78},"visibility":10000,"wind":{"speed":2.6,"deg":360},"clouds":{"all":90},"dt":1599162213,"sys":{"type":1,"id":3486,"country":"US","sunrise":1599127933,"sunset":1599174905},"timezone":-14400,"id":4930956,"name":"Boston","cod":200,"result":296.81},"result":296.81,"statusCode":200}
很好!現在就能完美運行了!我們創建了關鍵內容,讓Chainlink節點能夠理解數據請求。你可以清楚地看到在鏈下展開運算的好處,智能合約可以將大量計算工作放到鏈下運行,然後再將計算結果返回至鏈上。
現在已經做出了外部適配器,接下來的問題就是如何讓Chainlink節點運行外部適配器?如何調用外部適配器?我們這裡先暫時跳過親自運行外部適配器的部分,因為實際上我們不需要親自運行。在index.js
的底部有一些wrapper,可以讓節點運營商採用無服務器的方式部署代碼。所以我們可以這麼做:
- 將適配器添加至第三方節點分類信息平臺,比如market.link
- 讓節點運營商運行我們的適配器(#ask-a-node-operator discord)
- 親自運行節點(不必要)
你可以發現,你甚至都不用親自運行節點就可以使用自己的外部適配器。這是最理想的情況,因為我們希望自己的適配器可以被其他預言機節點使用,這樣就可以有許多節點訪問數據,並使Chainlink網絡保持極高的去中心化水平。
我們將在之後的視頻或博客文章中詳細探討如何運行外部適配器。如果你已經開發出了新的適配器,可以先暫時讓節點幫你運行,並加入我們的社區!
使用外部適配器
假設現在有一個節點幫你運行外部適配器,那麼你就可以通過這個節點將數據傳輸至你的智能合約。在這個示例中,我們開發出了一個叫做Alpha Vantage的外部適配器。Alpha Vantage是一個股票和加密貨幣價格數據API,需要API祕鑰才能訪問。我們來看看如何通過Linkpool kovan節點運行的外部適配器獲取特斯拉股票價格數據。首先要找到這個外部適配器,我們需要在外部適配器的網頁中尋找。將頁面一直往下拉,直到找到我們想要的Alpha Vantage外部適配器。
Alpha Vantage外部適配器
圖中描述了外部適配器的所有功能。我們可以點擊“supported nodes”按鈕,查看可以運行這個適配器的節點。我們發現有一個節點可以支持它,然後可以在任務頁面查看這個節點的具體信息。你可以看到Alpha Vantage適配器在這個節點的適配器清單中。
接下來就是如何使用適配器。我們先像往常一樣將job ID和預言機ID添加至代碼中。然後添加Alpha Vantage文檔中的所有參數。
bytes32 jobId = “802ec94e00184b789a016b8e71ae9fb4”;
address oracle = 0x56dd6586DB0D08c6Ce7B2f2805af28616E082455;
function requestTSLAPrice() public {
Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfillEthereumPrice.selector);
req.add("function", "GLOBAL_QUOTE");
req.add("symbol", "TSLA");
string[] memory copyPath = new string[](2);
copyPath[0] = "Global Quote";
copyPath[1] = "05. price";
req.addStringArray("copyPath", copyPath);
req.addInt("times", 100000000);
sendChainlinkRequestTo(oracle, req, fee);
}
以上是完整版代碼,你可以嘗試使用。你也可以使用任何API的文檔進行嘗試,因為現在你應該已經發現其實套路都是一樣的!
總結
正如你所看到的,外部適配器是非常強大的工具,開發者可以用來豐富智能合約的功能並提升其連通性。另外,還可以使用API認證和鏈下計算等layer2解決方案來提升外部適配器的靈活性。如果這篇文章對你有任何啟發,歡迎參加Chainlink黑客鬆,嘗試應用你新學到的技能!這次黑客鬆的獎金超過4萬美元,希望大家能踴躍參加!
如果當你讀到這篇文章時黑客鬆已經結束了,那麼也歡迎加入我們在Twitter, Discord, 或 Reddit上的社區,轉發並加上#chainlink和#ChainlinkEA標籤,瞭解Chainlink最新活動消息,並嘗試應用你的技能!
如果Chainlink預言機可以為你目前開發的產品提供任何附加價值;抑或你希望參與Chainlink網絡的開源開發工作,請查看開發者文檔或加入我們在Discord頻道上的技術討論群。
加入中文開發者社區:neils_(開發者社區管理員團長)