Security

eip-1967 地址計算

  • November 29, 2021

我已經閱讀了 EIP-1967 並且研究了代理契約的工作原理。

在 EIP-1967 中有一些我不明白的地方。

這是我的理解:

  • 邏輯合約的儲存變數儲存在代理合約的記憶體中。
  • 代理合約包含他自己的儲存變數
  • 如果邏輯合約變數的地址與代理合約變數的地址相同,我們可能會遇到一個大問題。
  • 因此,代理合約變數儲存在 3 個特定地址(我們在代理合約中只有 3 個儲存變數)
  • 這個 EIP 的目標是指定 3 個地址,並告訴所有編譯器和 EVM,他們不應該在這個地址儲存變數。

在我看來,寫這個 EIP 的人可以選擇任何地址。重要的是每個人都同意這個地址選擇(編譯器,evm,…)。他們選擇這個地址:

0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc(作為 bytes32(uint256(keccak256(’eip1967.proxy.implementation’)) - 1) 獲得

0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50(作為 bytes32(uint256(keccak256(’eip1967.proxy.beacon’)) - 1) 獲得

0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 (作為 bytes32(uint256(keccak256(’eip1967.proxy.admin’)) - 1) 獲得

很好,但我想知道一些事情:他們為什麼在地址計算中加上 -1 ?

EIP 說:

此外,添加了 -1 偏移量,因此無法知道雜湊的原像,進一步降低了可能的攻擊機會

我不明白這個 -1 偏移量如何減少任何可能的攻擊機會……每個人都知道雜湊。誰能解釋這種 -1 保護哪種攻擊?

我查看了一個 openzepplin 實現(TransparentUpgradeableProxy.sol),這就是我所看到的:

bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

constructor(...)
{
    assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
    ...
}

我的問題是:這個斷言怎麼可能是假的?建構子中這個斷言的目標是什麼?

非常感謝

我不明白這個 -1 偏移量如何減少任何可能的攻擊機會……每個人都知道雜湊。誰能解釋這種 -1 保護哪種攻擊?

這是一個有趣的問題,它與“碰撞攻擊”和“原像攻擊”之間的區別有關,當涉及到嘗試惡意創建存在插槽碰撞的場景的風險時。

您可以在此處查看導致 -1 的邏輯的討論:

https://github.com/ethereum/EIPs/pull/1967#issuecomment-489276813

-1來自wjmelements的建議,當他在這裡評論時:

我質疑 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3 是最佳儲存位置的想法。它有一個已知的 keccak 原像,與附近的 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c2 不同。在沒有已知原像的情況下很難設計攻擊。

(請注意,這兩個地址之間的唯一區別是尾隨3vs 2。)

回應是

好點子。我們選擇了具有這樣一個原像的雜湊,以便我們知道它不會與 Solidity 或 Vyper 編譯器分配的任何內容髮生衝突(它們都將映射值儲存在以聲明映射的插槽號開頭的原像中),但是選擇一個完全隨機的值也可能是一個好主意。很想知道其他人對此有何看法!

至於你的結束問題,

這個斷言怎麼可能是假的?建構子中這個斷言的目標是什麼?

使用assert()(而不是require())表示這永遠不會失敗。例如,我只能想像這是必要的,以確保您不會意外地對繼承做一些不正確的事情。這個想法是,“在繼續部署到主網之前驗證這個非常重要的細節——如果這個關鍵的事情是錯誤的,就中止。”

引用自:https://ethereum.stackexchange.com/questions/93409