Commit 92ed64e1 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Use the deterministic deployer when broadcasting with CREATE2 (#11915)

parent 8341f340
package script
import "github.com/ethereum/go-ethereum/common"
var (
// DeterministicDeployerAddress is the address of the deterministic deployer Forge uses
// to provide deterministic contract addresses.
DeterministicDeployerAddress = common.HexToAddress("0x4e59b44847b379578588920ca78fbf26c0b4956c")
)
...@@ -54,6 +54,13 @@ func (h *Host) handleCaller(caller vm.ContractRef) vm.ContractRef { ...@@ -54,6 +54,13 @@ func (h *Host) handleCaller(caller vm.ContractRef) vm.ContractRef {
if len(h.callStack) > 0 { if len(h.callStack) > 0 {
parentCallFrame := h.callStack[len(h.callStack)-1] parentCallFrame := h.callStack[len(h.callStack)-1]
if parentCallFrame.Prank != nil && caller.Address() != VMAddr { // pranks do not apply to the cheatcode precompile if parentCallFrame.Prank != nil && caller.Address() != VMAddr { // pranks do not apply to the cheatcode precompile
if parentCallFrame.Prank.Broadcast && parentCallFrame.LastOp == vm.CREATE2 && h.useCreate2Deployer {
return &prankRef{
prank: DeterministicDeployerAddress,
ref: caller,
}
}
if parentCallFrame.Prank.Sender != nil { if parentCallFrame.Prank.Sender != nil {
return &prankRef{ return &prankRef{
prank: *parentCallFrame.Prank.Sender, prank: *parentCallFrame.Prank.Sender,
......
...@@ -105,6 +105,10 @@ type Host struct { ...@@ -105,6 +105,10 @@ type Host struct {
// and prepare the ephemeral tx context again, // and prepare the ephemeral tx context again,
// to make gas accounting of a broadcast sub-call more accurate. // to make gas accounting of a broadcast sub-call more accurate.
isolateBroadcasts bool isolateBroadcasts bool
// useCreate2Deployer uses the Create2Deployer for broadcasted
// create2 calls.
useCreate2Deployer bool
} }
type HostOption func(h *Host) type HostOption func(h *Host)
...@@ -132,6 +136,16 @@ func WithIsolatedBroadcasts() HostOption { ...@@ -132,6 +136,16 @@ func WithIsolatedBroadcasts() HostOption {
} }
} }
// WithCreate2Deployer proxies each CREATE2 call through the CREATE2 deployer
// contract located at 0x4e59b44847b379578588920cA78FbF26c0B4956C. This is the Arachnid
// Create2Deployer contract Forge uses. See https://github.com/Arachnid/deterministic-deployment-proxy
// for the implementation.
func WithCreate2Deployer() HostOption {
return func(h *Host) {
h.useCreate2Deployer = true
}
}
// NewHost creates a Host that can load contracts from the given Artifacts FS, // NewHost creates a Host that can load contracts from the given Artifacts FS,
// and with an EVM initialized to the given executionContext. // and with an EVM initialized to the given executionContext.
// Optionally src-map loading may be enabled, by providing a non-nil srcFS to read sources from. // Optionally src-map loading may be enabled, by providing a non-nil srcFS to read sources from.
......
...@@ -117,8 +117,8 @@ func TestScriptBroadcast(t *testing.T) { ...@@ -117,8 +117,8 @@ func TestScriptBroadcast(t *testing.T) {
Nonce: 0, // first action of 0x123456 Nonce: 0, // first action of 0x123456
}, },
{ {
From: cafeAddr, From: DeterministicDeployerAddress,
To: crypto.CreateAddress2(cafeAddr, salt, crypto.Keccak256(expectedInitCode)), To: crypto.CreateAddress2(DeterministicDeployerAddress, salt, crypto.Keccak256(expectedInitCode)),
Input: expectedInitCode, Input: expectedInitCode,
Value: (*hexutil.U256)(uint256.NewInt(0)), Value: (*hexutil.U256)(uint256.NewInt(0)),
Type: BroadcastCreate2, Type: BroadcastCreate2,
...@@ -141,7 +141,7 @@ func TestScriptBroadcast(t *testing.T) { ...@@ -141,7 +141,7 @@ func TestScriptBroadcast(t *testing.T) {
hook := func(broadcast Broadcast) { hook := func(broadcast Broadcast) {
broadcasts = append(broadcasts, broadcast) broadcasts = append(broadcasts, broadcast)
} }
h := NewHost(logger, af, nil, DefaultContext, WithBroadcastHook(hook)) h := NewHost(logger, af, nil, DefaultContext, WithBroadcastHook(hook), WithCreate2Deployer())
addr, err := h.LoadContract("ScriptExample.s.sol", "ScriptExample") addr, err := h.LoadContract("ScriptExample.s.sol", "ScriptExample")
require.NoError(t, err) require.NoError(t, err)
...@@ -164,5 +164,7 @@ func TestScriptBroadcast(t *testing.T) { ...@@ -164,5 +164,7 @@ func TestScriptBroadcast(t *testing.T) {
require.EqualValues(t, 0, h.GetNonce(senderAddr)) require.EqualValues(t, 0, h.GetNonce(senderAddr))
require.EqualValues(t, 3, h.GetNonce(scriptAddr)) require.EqualValues(t, 3, h.GetNonce(scriptAddr))
require.EqualValues(t, 2, h.GetNonce(coffeeAddr)) require.EqualValues(t, 2, h.GetNonce(coffeeAddr))
require.EqualValues(t, 1, h.GetNonce(cafeAddr)) // This is zero because the deterministic deployer is the
// address that actually deploys the contract using CREATE2.
require.EqualValues(t, 0, h.GetNonce(cafeAddr))
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment