時(shí)間:2022-02-10|瀏覽:579
在某些情況下,在被納入?yún)^(qū)塊之前,一個(gè)看似有效的交易可能會(huì)被丟棄。當(dāng)網(wǎng)絡(luò)擁堵時(shí),這種情況最常見(jiàn)RPC節(jié)點(diǎn)未能將交易重播(重播)給領(lǐng)導(dǎo)(leader,當(dāng)決定當(dāng)前塊的驗(yàn)證器時(shí)。對(duì)于終端用戶來(lái)說(shuō),他們的交易似乎完全消失了。RPC節(jié)點(diǎn)配備了通用的重播算法,但應(yīng)用程序開(kāi)發(fā)人員也能夠開(kāi)發(fā)自己的自定義重播邏輯。
交易的歷程
客戶如何提交交易
在Solana不存在區(qū)塊鏈mempool概念。所有的交易,無(wú)論是通過(guò)編程還是由終端用戶發(fā)起,都被有效地路過(guò)給領(lǐng)導(dǎo)者,以便被處理成一個(gè)塊。向領(lǐng)導(dǎo)者發(fā)送交易有兩種主要方式:
通過(guò)RPC服務(wù)器和sendTransaction JSON-RPC代理方法
通過(guò)TPU客戶直接傳遞給領(lǐng)導(dǎo)者
絕大多數(shù)終端用戶將通過(guò)RPC服務(wù)器提交交易。當(dāng)客戶提交交易時(shí),接收RPC節(jié)點(diǎn)將試圖將交易廣播給當(dāng)前和下一個(gè)領(lǐng)導(dǎo)者。在交易被領(lǐng)導(dǎo)處理之前,除了客戶和轉(zhuǎn)發(fā)RPC除了節(jié)點(diǎn)知道交易,沒(méi)有交易記錄。TPU在客戶端發(fā)送交易時(shí),重播和領(lǐng)導(dǎo)者轉(zhuǎn)發(fā)完全由客戶端軟件處理。
RPC如何廣播節(jié)點(diǎn)交易
在RPC節(jié)點(diǎn)通過(guò)sendTransaction收到交易后,它將交易轉(zhuǎn)換為UDP數(shù)據(jù)包,然后轉(zhuǎn)發(fā)給相關(guān)領(lǐng)導(dǎo)。UDP允許驗(yàn)證器快速通信,但不保證交易交付。
由于Solana領(lǐng)導(dǎo)時(shí)間表(決定驗(yàn)證器作為下一個(gè)領(lǐng)導(dǎo)時(shí)間表)在每個(gè)時(shí)間(約2天)之前就已經(jīng)知道了,RPC該節(jié)點(diǎn)將直接向當(dāng)前和下一個(gè)領(lǐng)導(dǎo)者廣播交易。與其他協(xié)議(如以太坊)相反,后者在整個(gè)網(wǎng)絡(luò)中隨機(jī)而廣泛地傳播交易。默認(rèn)情況下,RPC該節(jié)點(diǎn)將嘗試每?jī)擅雽⒔灰邹D(zhuǎn)發(fā)給領(lǐng)導(dǎo)者,直到交易最終完成或交易區(qū)塊鏈過(guò)期(150個(gè)區(qū)塊或1分19秒)。如果未完成的重播隊(duì)列超過(guò)1萬(wàn)筆交易,新提交的交易將被丟棄。RPC操作員可以調(diào)整一些命令行參數(shù),從而改變重試邏輯的默認(rèn)行為。
當(dāng)一個(gè)RPC當(dāng)節(jié)點(diǎn)廣播交易時(shí),它將試圖將交易轉(zhuǎn)發(fā)給領(lǐng)導(dǎo)者的交易處理單元(TPU)。TPU處理五個(gè)不同階段的交易。
獲取階段
簽名驗(yàn)證(SigVerify)階段
銀行業(yè)務(wù)(Banking)階段
歷史服務(wù)證明(Proof of History Service)
廣播階段
在這五個(gè)階段,獲取階段負(fù)責(zé)接收交易。在獲取階段,驗(yàn)證器將根據(jù)三個(gè)端口對(duì)匯入的交易進(jìn)行分類。
tpu處理代幣轉(zhuǎn)移等常規(guī)交易,NFT鑄造和程序指令。
tpu_vote只關(guān)注投票交易
若當(dāng)前領(lǐng)導(dǎo)不能處理所有交易,tpu_forwards將未處理的數(shù)據(jù)包轉(zhuǎn)發(fā)給下一位領(lǐng)導(dǎo)。
關(guān)于TPU請(qǐng)參考更多信息Jito Labs這篇文章。
如何丟棄交易?
在整個(gè)交易過(guò)程中,在幾種情況下,交易可能會(huì)無(wú)意中從網(wǎng)絡(luò)中刪除。
在處理交易之前
如果網(wǎng)絡(luò)丟棄了交易,很可能在交易被領(lǐng)導(dǎo)處理之前就丟棄了。UDP數(shù)據(jù)包丟失是造成這種情況的最簡(jiǎn)單原因。當(dāng)網(wǎng)絡(luò)負(fù)載高時(shí),驗(yàn)證器也可能被需要處理的交易量淹沒(méi)。雖然驗(yàn)證器有能力通過(guò)tpu_forwards轉(zhuǎn)發(fā)多余的交易,但可轉(zhuǎn)發(fā)的數(shù)據(jù)量有限。此外,每個(gè)轉(zhuǎn)發(fā)僅限于兩個(gè)單獨(dú)的驗(yàn)證器。也就是說(shuō),在tpu_forwards端口收到的交易不會(huì)轉(zhuǎn)發(fā)給其他驗(yàn)證器。
還有兩個(gè)不為人知的原因,即交易可能在處理前被丟棄。第一種情況涉及通過(guò)RPC池提交的交易。在一些非常罕見(jiàn)的情況下,RPC池的一部分可以完全領(lǐng)先于池的其他部分。當(dāng)需要池中的節(jié)點(diǎn)一起工作時(shí),這可能會(huì)導(dǎo)致問(wèn)題。在這個(gè)例子中,最近的交易區(qū)塊哈希(Blockhash)是由池的高級(jí)部分(Backend A)查詢。當(dāng)交易提交到池的滯后部分時(shí)。(BackendB)節(jié)點(diǎn)將無(wú)法識(shí)別領(lǐng)先的區(qū)塊哈希,從而放棄交易。如果開(kāi)發(fā)者在sendTransaction在提交交易時(shí),可以通過(guò)啟用預(yù)檢來(lái)檢測(cè)這一點(diǎn)。
暫時(shí)的網(wǎng)絡(luò)分叉也會(huì)導(dǎo)致交易丟棄。如果驗(yàn)證器在銀行階段慢慢重放區(qū)塊,它最終可能會(huì)創(chuàng)建一個(gè)少數(shù)分叉。當(dāng)客戶建立交易時(shí),交易可能會(huì)引用最近只存在于少數(shù)分叉上的區(qū)塊哈希。交易提交后,交易集群可以在交易處理前從其少數(shù)分叉中切換。在這種情況下,交易會(huì)因?yàn)檎也坏絽^(qū)塊哈希而被丟棄。
交易處理后,在交易最終確定前丟棄
如果一筆交易引用了最近幾個(gè)分叉的區(qū)塊哈希,它仍然可能被處理。然而,在這種情況下,它將由少數(shù)分叉的領(lǐng)導(dǎo)者處理。當(dāng)領(lǐng)導(dǎo)者試圖與互聯(lián)網(wǎng)上的其他成員分享交易時(shí),它將無(wú)法與大多數(shù)不承認(rèn)少數(shù)分叉的驗(yàn)證器達(dá)成共識(shí)。此時(shí),交易將在最終完成前被丟棄。
處理丟棄的交易
雖然RPC該節(jié)點(diǎn)試圖重新進(jìn)行廣播交易,但它們使用的算法是通用的,通常不適合特定應(yīng)用程序的需要。為了應(yīng)對(duì)網(wǎng)絡(luò)擁堵,應(yīng)用程序開(kāi)發(fā)人員應(yīng)該定制自己的重播邏輯。
深入了解sendTransaction
開(kāi)發(fā)人員在提交交易時(shí)使用的主要工具是sendTransaction RPC方法。sendTransaction只負(fù)責(zé)從客戶端轉(zhuǎn)發(fā)交易R(shí)PC節(jié)點(diǎn)。假如節(jié)點(diǎn)收到交易,sendTransaction將返回交易ID,可用于跟蹤交易。成功的反應(yīng)并不意味著交易是集群處理還是最終完成。
請(qǐng)求參數(shù)
transaction: string(字符串)-完全簽名的交易,作為編碼字符串
(可選) configuration object: object(對(duì)象)
skipPreflight:bolean(布爾值)-如果是真的,跳過(guò)預(yù)檢交易檢查(默認(rèn)為假)。
(可選) preflightCommitment: string(字符串)- 對(duì)bank slot進(jìn)行Preflight模擬中使用的承諾級(jí)別(默認(rèn)為:完成)。
(可選) encoding: string (字符串)-用于交易數(shù)據(jù)的編碼。"base58"(慢速),或 "base64"。(默認(rèn):"base58")。
(可選) maxRetries: usize——RPC節(jié)點(diǎn)重試最大次數(shù)將交易發(fā)送給領(lǐng)導(dǎo)。如果不提供此參數(shù),RPC節(jié)點(diǎn)將重終完成或區(qū)塊哈希過(guò)期之前,節(jié)點(diǎn)將重試交易。
響應(yīng)
transaction id: string (字符串)-——嵌入在交易中的第一個(gè)交易簽名base-58編碼字符串。這筆交易ID可以與getSignatureStatuses一起使用,輪詢(poll)狀態(tài)更新。
自定義重播邏輯
為了開(kāi)發(fā)自己的重播邏輯,開(kāi)發(fā)者應(yīng)該使用它sendTransaction的maxRetries若開(kāi)發(fā)人員提供相關(guān)參數(shù),maxRetries將覆蓋RPC默認(rèn)節(jié)點(diǎn)重播邏輯允許開(kāi)發(fā)者在合理范圍內(nèi)手動(dòng)控制重播過(guò)程。
一種常見(jiàn)的手動(dòng)重試交易模式來(lái)自getLatestBlockhash臨時(shí)存儲(chǔ)的lastValidBlockHeight。一旦存儲(chǔ)了應(yīng)用程序,可以輪詢交易集群的塊高,并在適當(dāng)?shù)臅r(shí)間間隔內(nèi)手動(dòng)重試交易。當(dāng)網(wǎng)絡(luò)擁堵時(shí),maxRetries設(shè)置為0并通過(guò)自定義算法手動(dòng)重播是很有利的。雖然一些應(yīng)用程序可能采用指數(shù)退避算法(exponential backoff algorithm),但其他應(yīng)用程序,如Mango,在發(fā)生某種超時(shí)之前,選擇在恒定的時(shí)間間隔內(nèi)連續(xù)重新交易。
當(dāng)通過(guò)getLatestBlockhash輪詢時(shí),應(yīng)用程序應(yīng)指定其預(yù)期承諾水平。通過(guò)將其承諾設(shè)置為確認(rèn)(投票)或最終確認(rèn)(確認(rèn)后約30個(gè)區(qū)塊),應(yīng)用程序可以避免從少數(shù)分叉輪詢區(qū)塊鏈。
如果一個(gè)應(yīng)用程序可以訪問(wèn)負(fù)載平衡器后面RPC也可以選擇在特定的節(jié)點(diǎn)中劃分節(jié)點(diǎn)的工作負(fù)載。服務(wù)于數(shù)據(jù)密集型請(qǐng)求RPC節(jié)點(diǎn),如getProgramAccounts,它可能很容易落后,也不適合轉(zhuǎn)發(fā)交易。對(duì)于處理時(shí)間敏感交易的應(yīng)用程序,謹(jǐn)慎的做法是只處理特殊節(jié)點(diǎn)sendTransaction。
跳過(guò)Preflight的代價(jià)
默認(rèn)情況下,sendTransaction提交交易前將進(jìn)行三次預(yù)檢。具體來(lái)說(shuō),sendTransaction將:
驗(yàn)證所有簽名是否有效
檢查引用的區(qū)塊鏈?zhǔn)欠裨谧詈?50個(gè)區(qū)塊內(nèi)
針對(duì)preflightCommitment指定的bank slot模擬交易
若三次預(yù)檢中的任何一次失敗,sendTransaction在提交交易之前會(huì)出錯(cuò)。預(yù)檢通常是失去交易和允許客戶優(yōu)雅地處理錯(cuò)誤之間的區(qū)別。為了確??紤]到這些常見(jiàn)的錯(cuò)誤,建議開(kāi)發(fā)人員不要skipPreflight設(shè)置為false。
何時(shí)重新簽名交易?
雖然所有的嘗試都是為了重新廣播,但有時(shí)客戶可能需要重新簽署交易。確保初始交易的區(qū)塊哈希在重新簽署任何交易之前過(guò)期是非常重要的。如果最初的區(qū)塊鏈仍然有效,那么這兩筆交易可能會(huì)被互聯(lián)網(wǎng)接受。對(duì)于終端用戶來(lái)說(shuō),這就像他們無(wú)意中發(fā)送了兩筆相同的交易。
在Solana哈希比遺棄交易所引用的區(qū)塊哈希比getRecentBlockhash收到的lastValidBlock長(zhǎng)期以來(lái),交易可以安全丟棄。開(kāi)發(fā)者可以通過(guò)isBlockhashValid便于檢查給定的區(qū)塊鏈。一旦區(qū)塊鏈?zhǔn)В蛻艨梢杂眯虏樵兊膮^(qū)塊鏈重新簽名。