以前一直在忙於通用跨鏈公鏈PalletOne的研發,沒有怎麼作技術分享的博客,最近PalletOne主網上線也有幾個月的時間了,即將進行PTN(PalletOne上面的主Token)從ERC20到主網的轉網工做。在轉網進行時,正好將這其中的技術原理與你們分享。git
由於ERC20同質化通證標準的流行,大量區塊鏈項目都是經過先在以太坊上以ERC20的形式發行Token,進行募資、糖果發放、Token買賣等,等到本身的主鏈研發完成,就會將ERC20上的Token銷燬或者凍結,而將對應數量的Token在主網上發放到各個持幣用戶,這個過程叫作Token轉網。github
Token轉網通常有兩種方式,經過交易所轉網或者經過項目方轉網。經過交易所轉網對用戶來講最簡單,用戶只須要將ERC20充幣到對應的交易所,而後再提幣時,提的就是主網的Token。而經過項目方轉網的實現方式就比較多了,有經過以太坊合約進行地址映射,經過專門的轉網網站進行轉網操做,經過以太坊快照確認每一個地址的Token餘額,經過創世區塊進行Token分配等多種方式,看項目方根據本身鏈的特色來決定。安全
交易所要支持一個新的公鏈,那麼必然會在交易所創建該公鏈的全帳本節點,而交易所原本就支持ERC20代幣,因此也有以太坊的全帳本節點。交易所轉網分爲一次性轉網和持續轉網兩種操做方式。app
一次性轉網就是交易所規定一個時間,在該時間後,再也不支持該ERC20的充幣提幣,交易所得到一個肯定的ERC20餘額,而後將這些ERC20按項目方的要求進行銷燬或者轉移到某個鎖定地址。項目方將對應數量的主網Token轉移到交易所的新公鏈錢包地址。這些操做完成後,交易所從新打開該Token的充幣提幣通道,只不過如今充幣只能接受主網的Token,充幣地址也是該主網的新地址,而提幣也只能提取主網的Token。函數
持續轉網是指交易所不規定中止ERC20充幣的時間,用戶隨時均可以將ERC20充幣到交易所,也就是說充幣支持主網Token和ERC20兩種方式,而提幣只支持主網Token。交易所先按一次性轉網的流程,將本身持有的ERC20兌換成主網Token,之後當用戶充值的是ERC20時,交易所會定時將全部充值的ERC20進行銷燬或者轉移到項目方規定的鎖定地址,而後向項目方發出ERC20兌換的請求,這個請求通常會發送到項目方的一個RPC API,項目方的該API確認ERC20鎖定後,會將本身持有的主網Token以對應數量發送給交易所指定的地址。工具
PalletOne調色板由於自己就是一個支持比特幣、以太坊等公鏈的通用跨鏈公鏈,因此其上的Token PTN轉網就基於其跨鏈的特色,再配合上陪審團和以太坊適配器執行跨鏈合約,實現主網智能合約的Token轉網。下面詳細介紹一下其中的技術原理。區塊鏈
要進行異構鏈的Token轉網,通常來講須要3步操做:網站
其中步驟1和2均可以在以太坊上經過智能合約來實現。若是以太坊上面ERC20 Token轉帳時可以附上一句話,那麼就太簡單了,只須要在將ERC20轉移到鎖定地址的這個交易中,以字符串形式附上本次鎖定的Token在主網中對應的映射地址便可。可是咱們看看ERC20的標準:https://eips.ethereum.org/EIPS/eip-20ui
function transfer(address _to, uint256 _value) public returns (bool success) function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
不管是transfer仍是transferFrom,都只有金額,沒有備註字段,因此咱們想要在轉帳時附加上主網映射地址是不現實的。因此咱們須要專門發佈一個地址映射的合約方法,持幣用戶調用該方法時,合約將持幣用戶地址與傳入的主網地址進行關聯,再使用一個查詢方法,便可查詢以太坊地址對應的主網地址。另外還有一個方案是發佈一個地址映射的網站,持幣用戶到該網站註冊以太坊地址和主網地址的映射,而後網站給出一個字符串,用戶用以太坊的私鑰對該字符串進行簽名,並提交簽名給網站,這樣網站就能夠驗證此次映射肯定是該以太坊用戶本身發出,而不是別人冒充的。加密
以上提出的2個方案都有個驗證的問題,那就是對持幣用戶要求很高。一個普通的持幣用戶,沒有太多的計算機知識,沒有普遍被使用的合約調用或者簽名的錢包工具,那麼是很難操做「調用地址映射方法」和「對消息進行簽名」的。普通的支持ERC20的錢包,主要就是對ERC20標準的支持,也就是對transfer函數的支持,因此PalletOne地址映射方法被包裝成了transfer方法,用戶只須要用普通的以太坊錢包便可實現地址映射。
其中的具體原理是,以太坊的address _to地址是20字節,而PalletOne的地址雖然形如:P1CumdbKemvLLFXQxH7ufHgjRSzcednFvgd 這樣的形式,可是其本質上也是20字節,因此咱們能夠將PalletOne地址轉換爲以太坊地址:0x82a445064ac1de016719c653fcd2d13e5b62575c,因此咱們定義一個新的ERC20 Token,名字叫PTNMap,持幣用戶在錢包中添加這種Token,而後就能夠看到餘額爲1(表示沒有進行映射),發起轉帳,將接收方設置爲PalletOne地址轉換後的以太坊地址便可。轉帳成功後,能夠看到餘額爲0,則說明地址映射成功了。
該合約不只僅是一個包裝成了ERC20的地址映射合約,也是一個Token鎖定合約。持幣用戶在進行了PTNMap的轉帳(地址映射)後,便可將ERC20轉帳到該合約地址。因爲該合約沒有提出ERC20的合約方法,因此這是一個鎖定(銷燬)合約。
PalletOne基於對大量主流區塊鏈的抽象,完成了區塊鏈操做的適配器抽象接口定義,在適配器的接口定義中,定義了區塊鏈通用操做、加密貨幣操做、智能合約操做3大類。Eth-Adaptor以太坊適配器是一種針對以太坊ETH和ERC20的實現。https://github.com/palletone/eth-adaptor
針對PTN轉網來講,以太坊適配器主要使用了
GetTransferTx(input *GetTransferTxInput) (*GetTransferTxOutput, error)
GetPalletOneMappingAddress(addr *GetPalletOneMappingAddressInput) (*GetPalletOneMappingAddressOutput, error)
這兩個方法,一個用於轉網合約查詢某筆ERC20轉帳交易是否成功,源地址、目標地址、金額等,一個用戶計算在主網的地址,而後就能夠根據金額和主網地址進行主網Token的發放。
PalletOne支持圖靈完備的智能合約,而且從設計上可以支持多語言(Golang、Java、NodeJS等),支持多鏈的操做(比特幣、以太坊等)。
PalletOne的智能合約與其餘公鏈不一樣,智能合約並不在記帳節點運行,而是在選出的陪審團內運行。一個陪審團由至少4個陪審員節點組成(固然也能夠採用更多陪審員節點以進一步增強安全性),每一個陪審員分別獨立的運行合約,獲得合約執行結果,並進行簽名,若是3/4的節點都對同一個結果達成共識並簽名,那麼這個結果就被認爲是可信的,記帳節點會將這個結果進行打包。
本次PTN轉網合約由Golang寫成,PTN轉網合約的核心方法是:
func (p *PTNMain) PayoutPTNByTxID(ethTxID string, stub shim.ChaincodeStubInterface) pb.Response
其主要邏輯就是經過傳入的鎖定ERC20的以太坊交易Hash,調用適配器查詢交易是否真實存在,並得到交易細節,根據交易金額和映射地址,將合約上的PTN轉移給對應的用戶地址。固然還有不少關於錯誤判斷、重放攻擊檢查之類的,就不一一詳述了。
本來是計劃讓用戶本身來調用PalletOne合約,將ERC20鎖定轉帳的交易Hash做爲參數傳入的,可是發現一個矛盾的地方,就是用戶尚未進行轉網的話,就沒有PTN,沒有PTN就沒辦法發起合約調用,因此就沒辦法得到轉網的PTN。因此就由咱們發佈一個定時任務來作。該程序不斷的循環掃描以太坊上的ERC20 PTN的事件日誌,若是發現有PTN的轉帳,則看轉帳的接收方是否是鎖定合約地址,若是是,則說明有人要進行轉網。接下來就是判斷該交易是否被足夠的塊確認,一旦確認的塊數達到必定數量(好比15個確認),那麼就觸發PalletOne轉網合約的調用。
最後,PalletOne的轉網合約操做步驟嵌入到了PalletOne錢包中,用戶能夠下載錢包,自行轉網:https://pallet.one/wallet/