eip-1967 地址計算
我已經閱讀了 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 不同。在沒有已知原像的情況下很難設計攻擊。
(請注意,這兩個地址之間的唯一區別是尾隨
3
vs2
。)回應是
好點子。我們選擇了具有這樣一個原像的雜湊,以便我們知道它不會與 Solidity 或 Vyper 編譯器分配的任何內容髮生衝突(它們都將映射值儲存在以聲明映射的插槽號開頭的原像中),但是選擇一個完全隨機的值也可能是一個好主意。很想知道其他人對此有何看法!
至於你的結束問題,
這個斷言怎麼可能是假的?建構子中這個斷言的目標是什麼?
使用
assert()
(而不是require()
)表示這永遠不會失敗。例如,我只能想像這是必要的,以確保您不會意外地對繼承做一些不正確的事情。這個想法是,“在繼續部署到主網之前驗證這個非常重要的細節——如果這個關鍵的事情是錯誤的,就中止。”