這種設計使合約的儲存管理和操作變得簡單,因為它不需要記錄傳輸隨機數或返回值。 侷限性在於,隨著使用者數量和固定代幣數量的增長,Merkle證明的大小會增加(合約狀態樹會更深),從而使轉移變得更加昂貴。
使用Merkle Bridge將ERC20代幣從以太坊轉移到Aergo
優點:
· 驗證者實現起來很簡單,因為它們只需要簽署它們認為有效的最終狀態根(透過在橋的兩邊執行完整的節點)。驗證者不需要監視和驗證使用者的轉移。
· 使用者錢包直接透過網橋合同進行轉賬,不需要驗證者批准。
· 錨定週期是靈活的,狀態根可以由許多驗證器(20 +)簽名。
· 如果沒有超過2/3驗證者共同認可並廣播無效的側鏈狀態根,則不能任意審查代幣傳輸。
· 可以進行小額轉賬,並且可以隨時鑄造/解鎖總存款餘額。
· 鏈上的Merkle證明驗證比簽名驗證便宜。
· 任何新資產都可以透過網橋進行轉移,而無需獲得驗證者的批准(由於在鑄造時會部署新的固定合約,因此第一次轉移的成本會更高)。
· 可以透過一次交易完成對另一個鏈上同一帳戶的多次轉賬,提取傳送到該帳戶的總鎖定餘額。
侷限性:
· 一旦啟動,傳輸就應該在網橋的另一端完成(沒有超時限制),但這意味著無法取消傳輸。
· 如果超過1/3的驗證者停止合作,網橋將無限期暫停(不可能有新的取款)。
部署
在此儲存庫中可以找到2個Aergo區塊鏈之間的Merkle橋的POC實現:https://merkle-bridge.readthedocs.io
以太坊和Aergo區塊鏈之間的Merkle橋的POC實現可以在以下儲存庫中找到:https://eth-merkle-bridge.readthedocs.io
在此儲存庫中可以找到用於在以太坊和Aergo之間轉移資產的Javascript SDK:https://github.com/aergoio/eth-merkle-bridge-js?source=post_page-----32bd0f06c308----------------------
橋的操作員
他們要為橋接的每個區塊鏈執行一個完整節點。 每隔固定的時間間隔(每10分鐘?),他們將獲得最新的最終狀態根,並將其註冊在橋合約的Root和Height狀態變數中的相反區塊鏈上。
橋操作員有2種型別:廣播set_root()事務的建議者和為建議者請求的兩個橋接鏈狀態根簽名的驗證器任何人都可以是提議者:橋合約只允許在錨定期之後發生且具有有效簽名的狀態根更新。驗證者的數量可以根據所需的multisig安全性而變化,如果請求的狀態根有效,驗證者會對其進行簽名。
function newAnchor(
bytes32 root,
uint height,
uint[] memory signers,
uint8[] memory vs,
bytes32[] memory rs,
bytes32[] memory ss
) public {
require(height > _anchorHeight + _tAnchor, "Next anchor height not reached");
bytes32 message = keccak256(abi.encodePacked(root, height, _nonce, _contractId, "R"));
validateSignatures(message, signers, vs, rs, ss);
_anchorRoot = root;
_anchorHeight = height;
_nonce += 1;
emit anchorEvent(root, height);
}
操作員呼叫newAnchor(…)來錨定新的狀態根
橋驗證者集更新:
如果2/3的當前驗證者同意新的驗證者集,則可以定義新的驗證者集。
function validatorsUpdate(
address[] memory newValidators,
uint[] memory signers,
uint8[] memory vs,
bytes32[] memory rs,
bytes32[] memory ss
) public {
// validators should not sign a set that is equal to the current one to prevent spamming
bytes32 message = keccak256(abi.encodePacked(newValidators, _nonce, _contractId, "V"));
validateSignatures(message, signers, vs, rs, ss);
_validators = newValidators;
_nonce += 1;
emit newValidatorsEvent(newValidators);
}
橋驗證者集更新
版本2
在Merkle橋的版本2中,簽名驗證將在單獨的Oracle合約中重構,該合約將對橋合約具有完全控制權。這樣可以升級oracle合同的共識機制,併為使用者轉移保留相同的橋接合約。 橋的安全屬性保持不變。
使用者資產轉移:
要傳輸代幣,使用者會將其鎖定在橋接合約中,並等待目標區塊鏈上的下一個錨。
function lock(
string memory receiver,
uint amount,
IERC20 token
) public returns (bool) {
// Add locked amount to total
bytes memory accountRef = abi.encodePacked(receiver, token);
_locks[accountRef] += amount;
// Pull token from owner to bridge contract (owner must set approval before calling lock)
// using msg.sender, the owner must call lock, but we can make delegated transfers with sender
// address as parameter.
require(token.transferFrom(msg.sender, address(this), amount), "Failed to burn");
emit lockEvent(token, receiver, amount);
return true;
}
lock(…)記錄使用者存入的總餘額。
使用者錢包將讀取目標區塊鏈上的新錨定狀態根(Root,Height),並向該節點請求Merkle證明,包括該狀態根的鎖定餘額。使用者的鎖定平衡被記錄在鎖狀態對映,其中鍵是用於一個令牌帳戶參考。 帳戶參考是使用者地址和令牌地址的串聯。 然後可以使用鎖定令牌的Merkle證明在目標區塊鏈上進行薄荷交易。 使用者的造幣金額不能超過合同所存入和記錄的總金額。
function mint(
address receiver,
uint balance,
string memory tokenOrigin,
bytes32[] memory mp, // bytes[] is not yet supported so we use a bitmap of proof elements
bytes32 bitmap,
uint8 leafHeight
) public returns(bool) {
require(balance>0, "Balance must be positive");
bytes memory accountRef = abi.encodePacked(receiver, tokenOrigin);
require(verifyMp("_sv__locks-", accountRef, balance, mp, bitmap, leafHeight), "Failed to verify lock proof");
uint mintedSoFar = _mints[accountRef];
uint amountToTransfer = balance - mintedSoFar;
require(amountToTransfer>0, "Lock tokens before minting");
MintedERC20 mintAddress = _bridgeTokens[tokenOrigin];
if (mintAddress == MintedERC20(0)) {
// first time bridging this token
mintAddress = new MintedERC20();
_bridgeTokens[tokenOrigin] = mintAddress;
_mintedTokens[address(mintAddress)] = tokenOrigin;
emit newMintedERC20(tokenOrigin, mintAddress);
}
_mints[accountRef] = balance;
require(mintAddress.mint(receiver, amountToTransfer), "Failed to mint");
emit mintEvent(mintAddress, receiver, amountToTransfer);
return true;
}
mint(…)驗證存款的Merkle證明並鑄造正確數量的代幣。 如果從未鑄造過令牌,則部署新的固定代幣合約。
如果橋的操作員在使用者產生餘額之前錨定了新的狀態根,則使用者的錢包可以為新錨定的狀態根簡單地建立新的Merkle證明。
使用者的錢包在原始區塊鏈上解鎖代幣之前,會重複類似的燒燬代幣的過程。
有關Merkle橋合約中的Merkle證明驗證的詳細資訊,請參閱:
[http://bitoken.world/?p=297](以太坊Patricia樹的Merkle證明驗證 "http://bitoken.world/?p=297")
相關作品
Merkle Bridge採取的方法是儘可能使用最簡單,最可靠的設計,以使驗證者無需就使用者轉移達成共識,而是將所有資源集中在他們錨定的區塊鏈狀態根的有效性上。此外,使用者沒有完成轉賬的時間限制,並且可以透過一次交易完成對同一帳戶的多次轉賬。這是與以下協議的主要區別:
ICS(鏈間標準)
其他專案,如cosmos ibc,則採用不同的方法,將所有單個跨鏈資產傳輸抽象為資料包(也可以支援契約呼叫),並且peg區域驗證器在這些資料包上達成共識。這是一種非常有趣的方法,可以減少對跨鏈資產的信任,但當peg驗證器鎖定的資金的價值超過所涉原子的價值時,這種設計也最終依賴於驗證器的聲譽時,就會產生問題。
需要注意的是,為了連線比特幣和EOS這樣的區塊鏈,將存款事件轉發到傳輸代幣上是必要的,而EOS並不是Merkelize狀態。
Plasma
Merkle橋的設計靈感來自對Plasma的研究,並解決了在Plasma上執行合約的問題。Merkel橋並不是Plasma的,因為它不具有相同的安全性:沒有退出提示可以挑戰來自側鏈的退出,並且提款必須在側鏈上進行。 Merkle橋的安全性取決於錨定驗證者的分散性。由於可以為單個狀態根進行無限數量的傳輸,因此該狀態根所需的簽名數量可能很高。使用者無需關注區塊鏈上的無效提款和大規模退出情況,而應該信任去中心化的驗證者。同樣在POA企業側鏈的情況下,我們通常會假設共識安全性,因此可以在側鏈上初始化提款是可以接受的,並且側鏈運營商不需要監視父級掛鏈的退出。
結論
Merkle橋由一個簡單的DAO(multisig oracle)組成,用於驗證錨,更新驗證者集和橋設定。使用者錢包可以獨立建立其鎖定/燒燬餘額的Merkle證明,以進行跨鏈轉移,而無需驗證者觀看轉移事件。
EthAergo網橋將用於在Aergo和以太坊主網之間傳送AergoERC20和任何其他代幣。
AERGO-AERGO橋接器將被企業側鏈的使用者用於以一種成本高效和安全的方式在AERGO主網之間轉移他們的資產。
這使MakerDAO的DAI穩定幣和其他任何ERC20等令人興奮的應用程式都可以供Aergo主網使用者使用,並由Merkle橋錨定保護。