EOS REX 安全系列之從源碼開始玩轉 REX(一)

EOS REX 安全系列之从源码开始玩转 REX(一)

by SlowMist team

前言

伴隨著 REX 提案終於被 BP 們投票通過,炒了半年概念的 REX 終於上線了,這個號稱穩賺不虧的投資項目吸引了眾多人的目光,同時也霸佔了各大區塊鏈媒體的頭條,其火熱程度不亞於平臺幣,一上線便湧入了大量的資金。但是 REX 究竟是什麼呢?REX 又有什麼用?本系列基於 rex1.6.0-rc2 源碼進行分析,給出相關的細節及答案。

什麼是 REX

REX,全稱 Resource Exchange,即資源交易所,是為了提供一個更好的資源租賃平臺,緩解 EOS 高昂的資源使用成本,以更少的 EOS 換取更多的資源。同時也可以增加用戶投票,促進 EOS 系統的良性運轉。現在市面上有許多資源租賃 DApp,目的也是為了用於緩解 CPU 緊缺的問題。REX 與這些平臺一樣,都是充當租賃平臺的角色,不同的是資源出租方不再是 DApp,而是每一個 EOS 持有者都能成為資源出租方,並享受收益。這裡需要重點聲明的是,REX 不是一種代幣,而是一個資源租賃平臺!用戶購買的 REX 只是流轉於 REX 租賃平臺內的一種通證,用於證明用戶出租了資源,這種通證本身不可流轉,無法交易。類似於國債,REX 就是手中的債券。為了區分這兩個概念,下文統一將 REX 資源租賃平臺稱為 REX。而用戶購買得到的通證稱為 rex。

更詳細的資料可以參看 BM 自己的文章:

https://medium.com/@bytemaster/proposal-for-eos-resource-renting-rent-distribution-9afe8fb3883a

REX 攻略

對於一般用戶而言,買賣 rex 只需要接觸到以下幾個接口,分別是:

  1. depodit:用於充值,將 EOS 變成 SEOS,也叫預備金。

  2. withdraw:用與提現,將 SEOS 換回 EOS。

  3. buyrex:用於從用戶的預備金中扣除相應的份額,並用於 rex 的購買。

  4. sellrex:用於賣出已經結束鎖定的 REX,並將本金連帶收益一起放進用戶的預備金賬戶中。

  5. unstaketorex:將用於抵押中的資源用於 rex 的購買 。

下面,我們一起來看下這幾個函數的實現,瞭解資金的流向。

deposit 函數

deposit 函數是用戶參與 REX 的第一個接口,顧名思義,用戶充值以備後來購買 rex。就像去遊戲廳充值遊戲幣一樣,先把人民幣換成遊戲廳的點數衝進卡里,然後用這張卡進行後續的遊戲,後續的所有花費都是基於這張卡的。REX 也是相同的道理,後續所有的買賣操作都基於這個儲備金賬戶。deposit 函數的具體實現如下:

EOS REX 安全系列之从源码开始玩转 REX(一)

我們不需要了解每一行的具體實現,但是大概的道理是需要明白的。deposit 函數做了以下事情:

1、首先在第三行校驗了用戶權限,總不能平白無故的讓別人給自己買了 rex,繞過自己的意志。

2、在第五行和第六行對購買金額和代幣的信息進行校驗,不能拿假的 EOS 來買,也不能買個負數的,保證 REX 的安全性。

3、把用戶的 EOS 打進 eosio.rex 賬戶,你的錢就從你的口袋,轉到了 eosio.rex 系統賬戶上了。

4、調用 transfer_to_fund 接口,把用戶的充值金額用小本本記起來,這相當我們的儲備金錢包,在數據體現上是一個表,後續將根據這個表進行 rex 的購買。

5、調用 update_rex_account 接口,這個接口在輸入不同的參數的時候有不同的功能,這裡是用於處理用戶的賣單,把用戶賣 rex 得到的收益一併整理進儲備金賬戶中。

withdraw 函數

withdraw 函數是 deposit 函數的反向接口,用於將儲備金賬戶中的餘額轉移到用戶的 EOS 賬戶中,就像你在遊戲廳玩夠了,卡里還有點數,或玩遊戲贏到點數放進卡里,就可以用卡里的點數換回人民幣,下次再來,withdraw 函數的道理也是一樣的。withdraw 函數的具體實現如下:

EOS REX 安全系列之从源码开始玩转 REX(一)

與 deposit 函數大致一樣,withdraw 函數同樣對 EOS 代幣的信息進行了相關的校驗,與 deposit 函數不一樣的是,withdraw 函數調用 update_rex_account 接口和 transfer_from_fund 接口的順序與 deposit 函數不一樣。但目的都是為了處理用戶的 rex 賣單,將收益歸結進儲備金賬戶中。分別用於提現或購買 rex。這裡詳細的細節分析將放到後續文章之中。

buyrex 函數

折騰了那麼久,怎麼充值看完了,怎麼提現也看完了,下面就到了我們最關心的問題,就是該怎麼買的問題了。買 rex 調用的接口為 buyrex 函數,函數的具體實現如下:

EOS REX 安全系列之从源码开始玩转 REX(一)

和前面兩個函數一樣,buyrex 函數同樣也校驗了代幣的相關信息,然後使用 transfer_from_fund 函數從用戶的儲備金中扣除相應的金額。除此之外,我們還應該關注另外三個函數,分別是 check_voting_requirement,add_to_rex_pool 和 add_to_rex_balance。這三個函數分別用於檢查用戶是否投票、計算能購買到的 rex 的數量並把相應增加的 rex 數量加到 rexpool 中、記錄用戶購買的 rex 信息並計算用戶購買的 rex 的解鎖時間。那麼,我們能獲取到的 rex 的數量是怎麼計算出來的呢?從源碼上我們可以看到,計算 rex 的數量調用了 add_to_rex_pool 函數。所以,下面將著重分析 add_to_rex_pool 函數。

add_to_rex_pool 函數

add_to_rex_pool 函數用於將用戶購買的 rex 放進 rex_pool 中,並根據 rex_pool 中的相關信息計算出用戶能夠購買的 rex 的數量。首先我們先看下 rex_pool 表的定義

EOS REX 安全系列之从源码开始玩转 REX(一)

以上是 rex_pool 表的定義,其中定義了 8 個字段,除去 version 參數,我們分別一個一個解釋每個參數的意思

1、total_lent:用於記錄總共被借出了多少的 cpu 資源和 net 資源,這個資源是以 EOS 為單位的。

2、total_unlent:記錄 rex_pool 中未用於出借的 EOS 資源。包括用戶因為購買 rex 所產生的可用於出租的金額,租用資源的用戶的租金。 這其中有一部會因為出租資源而鎖定的金額(30 天后自動解鎖),是一個 connector,用於 bancor 操作,計算一定數量的 EOS 可租借的資源。

3、total_rent:用於記錄用戶在租用資源的時候支付的租金,是一個 connector,其反應了租借資源的用戶的多少。用於 bancor 操作,計算一定數量的 EOS 可租借的資源。

4、total_lenable:可以說是整個 rex_pool 的所有資金,計算公式為 total_unlent + total_lent。這裡的資金來源還包括 name bid 的競拍費用以及 ram fee。這個參數同時和用戶的收益息息相關。

5、total_rex:rex_pool 中 rex 的總量,其來源於用戶購買 rex。

6、namebid_proceeds:記錄競拍賬戶產生的費用。

7、loan_num:記錄出租資源的總次數。

明白了以上字段的定義,我們現在正式看看 add_to_rex_pool 函數,以下是函數的具體實現。

EOS REX 安全系列之从源码开始玩转 REX(一)
EOS REX 安全系列之从源码开始玩转 REX(一)EOS REX 安全系列之从源码开始玩转 REX(一)

首先我們看下我們能購買到的 rex 是怎麼計算的。當 rex_pool 迎來第一個購買 rex 的用戶的時候,獲得 rex 的獲取比例是1:10000,即 1 個 EOS 換 10000 個 rex,往後購買 rex 的用於按照公式((uint128_t(S1) * R0) / S0) - R0 計算能獲取的 rex。

看起來很複雜對不對?我們對公式進行分解下,首先進行以下轉換,公式變為(S1 / S0 * R0) - R0,再代入 S1,得到((S0 + payment) / S0 * R0) - R0,最後我們進行分解再去括號,得到 R0 + (payment / S0) * R0 - R0。最後這個公式就變成了(payment / S0) * R0。再變一下,變成 payment * (R0 / S0),即用戶用於購買 rex 的資金乘以當前 rex_pool 中的 EOS 總資產與 rex_pool 中的 rex 的總量之間的比例。

這個比例在沒有第三方資金如賬戶競拍費用,ram fee 等的干擾下是固定不變的,為 1:10000。但是當有第三方資金入場的時候,作為分母的 S0 就會不斷變大,那麼這個比例就不斷變小,同樣的金額能買到的 rex 就會越來越少。通過上面的分析,我們知道,在有第三方資金的參與下,rex 買得越早,能買到的數量就越多。rex 的價格與購買的人數無關,而與租借資源的數量,系統競拍資源產生的收益,以及 ram fee 有關。

sellrex 函數

那麼,現在流程走到這裡,剩下的就是計算收益的問題了。用於處理用戶出租 EOS 資源產生收益的計算細節的實現全部在 sellrex 函數中。以下是 sellrex 函數的具體實現。

EOS REX 安全系列之从源码开始玩转 REX(一)EOS REX 安全系列之从源码开始玩转 REX(一)

這個 sellrex 函數有很多學問,完整說下來可能不是這篇短短的分析能寫完的,但是可以分析我們最關心的問題,就是獲得的收益是怎麼計算出來的。首先我們不管其他細節,先看看在真正計算收益之前做了什麼。主要分為以下幾步:

1、檢查用戶購買了 rex 沒有,總不能沒買就能賣對吧。

2、通過 process_rex_maturities 函數計算結束鎖定的 rex,用戶從購買的 rex 到賣 rex 需要 4 天的釋放期。

3、檢測需要賣出的 rex 的數量是否小於結束鎖定的 REX 的數量。

通過以上幾步檢查之後,就真正進入了結算函數。rex 的收益結算是通過 fill_rex_order 接口實現的。看下具體實現。

fill_rex_order

EOS REX 安全系列之从源码开始玩转 REX(一)
EOS REX 安全系列之从源码开始玩转 REX(一)EOS REX 安全系列之从源码开始玩转 REX(一)

同樣的,類似 add_to_rex_pool,我們也可以拋開其他細節,直擊最核心的收益計算公式,即第 6 行的計算公式。(uint128_t(rex.amount) * S0) / R0,這個函數雖然看起來同樣的複雜,但是我們可以用相同的方法進行簡化。首先我們對公式進行一些轉換,變成 rex.amount / R0 * S0,加個括號,變成 rex.amount * (R0 / S0),即你能收益的 rex 是你要賣的 rex 乘以 rex_pool 中 rex 總量和 rex_pool 中得總 EOS 總資產之間的比例,這個比例在沒有第三方資金如 name bid 和 ram fee 加入的情況下也是維持穩定不變的 10000:1。

我們知道了什麼?

一口氣說了一大堆,看到這裡的你可能還有點茫然,可能只是記住了兩個公式的轉化,不打緊。我來總結下這次看完文章的的收穫。通過以上的分析,我們知道買 rex 和賣 rex 都是根據 rex 總量和 rex_pool 中的 EOS 的總資金之間的比例進行計算的,也就是說在沒有第三方資金參與,用戶的 EOS 總是按 1:10000 的比例變成 rex,再按 10000:1 的比例再變成 EOS。這說明,在沒有第三方資源的情況下,rex 和 EOS 總是按照一定的比例進行互換,這也是為什麼 REX 號稱穩賺不虧的原因。同時,在有第三方資金入場的時候,R0 / S0 的比例就會變小,也意味著 S0 / R0 的比例變大,雖然同樣資金買到的 rex 變少了,但是,賣出去的比例就變大了,獲得的收益就變得更多了。

整個參與的流程大致如下:

EOS REX 安全系列之从源码开始玩转 REX(一)

REX 安全性分析

REX 作為 EOS 本身的系統合約,其安全防護必須要做到面面俱到,一旦出現問題,將造成災難性的影響。REX 合約已經由 EOS Authority 團隊進行義務安全審計,但作為一名安全人員,筆者同時也對 REX 的整個架構進行了深入的思考,文章將會陸續對每個文章提及到的接口進行分析,闡述其安全性或安全性增強建議。

本文粗略介紹了四個接口,分別是 deposit,withdraw,buyrex,sellrex。

從函數實現上來看:

1、每個函數都有對 asset 參數的信息進行校驗,包括數量,代幣的符號信息是否與系統代幣信息一致。防止可能的假充值問題和溢出問題。

2、用戶的關鍵操作都有權限校驗,防止越權操作。

同時,文章內介紹的四個接口不存在 EOS 上常見的攻擊手法如回滾攻擊,排擠攻擊,假通知攻擊。

但值得注意的是,在這幾個函數中,sellrex 函數曾存在一個嚴重漏洞(現已修復),導致用於可以從 REX 中盜取資產。

詳細信息如下:

https://eosauthority.com/blog/REX_progress_with_testing_and_implementation_details

漏洞的成因在於進行 sellrex 操作的時候 REX 系統可能會不夠錢支付用戶的收益,在這種情況下,用戶的賣單就會掛起,如果沒有校驗訂單,惡意用戶就能在系統資金不足的情況下一直進行 sellrex 操作,一直增加掛起訂單的金額,直到有系統有足夠的資源支付用戶的收益。

結語

REX 是一個龐大的系統,不存在三言兩語將全部細節分析到位情況,文章沒有分析太多的技術細節,只是大概分析了每個函數的大概作用,介紹了關於 REX 收益最核心的地方。想要了解具體細節的朋友可以持續關注我們的系列文章~下一篇文章將會繼續說明這些函數之間更加好玩的細節!文章可能有說得不對的地方,歡迎大家指點交流。

本文僅用作技術參考,不構成任何投資建議。投資者應在充分了解相關風險的基礎上進行理性投資。


分享到:


相關文章: