Skip to content

Commit

Permalink
op-deployer: Add support for alt-DA deployments (ethereum-optimism#12798
Browse files Browse the repository at this point in the history
)

* op-deployer: Add support for alt-DA deployments

Gives users the ability to deploy an alt-DA chain by specifying an alt-DA config in their chain's intent. The chain will be deployed using OPCM, then an additional pipeline step will deploy the alt-DA challenge contracts. The owner of the challenge contract is set to the L1 proxy admin owner.

To reflect the experimental nature of this feature, the field in the intent is prefixed with `Dangerous`. Users should not use this for production chains until we have performed further testing.

This may not appear like an important feature on its surface. However, without it we cannot delete the legacy allocs files. Since it was low lift I figured I'd just knock it out, and get us one step closer to being able to rip out the legacy deployment scripts and tooling once and for all.

* semgrep

* forge fmt

* label

* flip args
  • Loading branch information
mslipper authored Nov 5, 2024
1 parent 9948426 commit dec8c60
Show file tree
Hide file tree
Showing 13 changed files with 718 additions and 6 deletions.
12 changes: 6 additions & 6 deletions op-chain-ops/genesis/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -597,18 +597,18 @@ func (d *L2CoreDeployConfig) Check(log log.Logger) error {
// AltDADeployConfig configures optional AltDA functionality.
type AltDADeployConfig struct {
// UseAltDA is a flag that indicates if the system is using op-alt-da
UseAltDA bool `json:"useAltDA"`
UseAltDA bool `json:"useAltDA" toml:"useAltDA"`
// DACommitmentType specifies the allowed commitment
DACommitmentType string `json:"daCommitmentType"`
DACommitmentType string `json:"daCommitmentType" toml:"daCommitmentType"`
// DAChallengeWindow represents the block interval during which the availability of a data commitment can be challenged.
DAChallengeWindow uint64 `json:"daChallengeWindow"`
DAChallengeWindow uint64 `json:"daChallengeWindow" toml:"daChallengeWindow"`
// DAResolveWindow represents the block interval during which a data availability challenge can be resolved.
DAResolveWindow uint64 `json:"daResolveWindow"`
DAResolveWindow uint64 `json:"daResolveWindow" toml:"daResolveWindow"`
// DABondSize represents the required bond size to initiate a data availability challenge.
DABondSize uint64 `json:"daBondSize"`
DABondSize uint64 `json:"daBondSize" toml:"daBondSize"`
// DAResolverRefundPercentage represents the percentage of the resolving cost to be refunded to the resolver
// such as 100 means 100% refund.
DAResolverRefundPercentage uint64 `json:"daResolverRefundPercentage"`
DAResolverRefundPercentage uint64 `json:"daResolverRefundPercentage" toml:"daResolverRefundPercentage"`
}

var _ ConfigChecker = (*AltDADeployConfig)(nil)
Expand Down
11 changes: 11 additions & 0 deletions op-chain-ops/script/cheatcodes_utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,17 @@ func (c *CheatCodesPrecompile) ParseTomlAddress_65e7c844(tomlStr string, key str
panic("should never get here")
}

func (c *CheatCodesPrecompile) ComputeCreate2Address_890c283b(salt, codeHash [32]byte) (common.Address, error) {
data := make([]byte, 1+20+32+32)
data[0] = 0xff
copy(data[1:], DeterministicDeployerAddress.Bytes())
copy(data[1+20:], salt[:])
copy(data[1+20+32:], codeHash[:])
finalHash := crypto.Keccak256(data)
// Take the last 20 bytes of the hash to get the address
return common.BytesToAddress(finalHash[12:]), nil
}

// unsupported
//func (c *CheatCodesPrecompile) CreateWallet() {}

Expand Down
11 changes: 11 additions & 0 deletions op-chain-ops/script/cheatcodes_utilities_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,14 @@ func TestParseTomlAddress(t *testing.T) {
require.NoError(t, err)
require.Equal(t, common.HexToAddress("0xff4ce7b6a91a35c31d7d62b327d19617c8da6f23"), addr)
}

func TestComputeCreate2Address(t *testing.T) {
c := &CheatCodesPrecompile{}
var salt [32]byte
salt[31] = 'S'
var codeHash [32]byte
codeHash[31] = 'C'
addr, err := c.ComputeCreate2Address_890c283b(salt, codeHash)
require.NoError(t, err)
require.EqualValues(t, common.HexToAddress("0x2f29AF1b5a7083bf98C4A89976c2f17FF980735f"), addr)
}
5 changes: 5 additions & 0 deletions op-deployer/pkg/deployer/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ func ApplyPipeline(
return pipeline.DeployOPChainGenesisStrategy(env, intent, st, chainID)
}
},
}, pipelineStage{
fmt.Sprintf("deploy-alt-da-%s", chainID.Hex()),
func() error {
return pipeline.DeployAltDA(env, intent, st, chainID)
},
}, pipelineStage{
fmt.Sprintf("generate-l2-genesis-%s", chainID.Hex()),
func() error {
Expand Down
43 changes: 43 additions & 0 deletions op-deployer/pkg/deployer/integration_test/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
"testing"
"time"

altda "github.com/ethereum-optimism/optimism/op-alt-da"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/inspect"
"github.com/ethereum-optimism/optimism/op-node/rollup"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"

"github.com/ethereum-optimism/optimism/op-chain-ops/script"
Expand Down Expand Up @@ -404,6 +408,45 @@ func TestInteropDeployment(t *testing.T) {
checkStorageSlot(t, st.L1StateDump.Data.Accounts, chainState.SystemConfigProxyAddress, depManagerSlot, proxyAdminOwnerHash)
}

func TestAltDADeployment(t *testing.T) {
op_e2e.InitParallel(t)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

env, bundle, intent, st := setupGenesisChain(t)
altDACfg := genesis.AltDADeployConfig{
UseAltDA: true,
DACommitmentType: altda.KeccakCommitmentString,
DAChallengeWindow: 10,
DAResolveWindow: 10,
DABondSize: 100,
DAResolverRefundPercentage: 50,
}
intent.Chains[0].DangerousAltDAConfig = altDACfg

require.NoError(t, deployer.ApplyPipeline(
ctx,
env,
bundle,
intent,
st,
))

chainState := st.Chains[0]
require.NotEmpty(t, chainState.DataAvailabilityChallengeProxyAddress)
require.NotEmpty(t, chainState.DataAvailabilityChallengeImplAddress)

_, rollupCfg, err := inspect.GenesisAndRollup(st, chainState.ID)
require.NoError(t, err)
require.EqualValues(t, &rollup.AltDAConfig{
CommitmentType: altda.KeccakCommitmentString,
DAChallengeWindow: altDACfg.DAChallengeWindow,
DAChallengeAddress: chainState.DataAvailabilityChallengeProxyAddress,
DAResolveWindow: altDACfg.DAResolveWindow,
}, rollupCfg.AltDAConfig)
}

func TestInvalidL2Genesis(t *testing.T) {
op_e2e.InitParallel(t)

Expand Down
63 changes: 63 additions & 0 deletions op-deployer/pkg/deployer/opcm/alt_da.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package opcm

import (
"fmt"
"math/big"

"github.com/ethereum-optimism/optimism/op-chain-ops/script"
"github.com/ethereum/go-ethereum/common"
)

type DeployAltDAInput struct {
Salt common.Hash
ProxyAdmin common.Address
ChallengeContractOwner common.Address
ChallengeWindow *big.Int
ResolveWindow *big.Int
BondSize *big.Int
ResolverRefundPercentage *big.Int
}

type DeployAltDAOutput struct {
DataAvailabilityChallengeProxy common.Address
DataAvailabilityChallengeImpl common.Address
}

type DeployAltDAScript struct {
Run func(input, output common.Address) error
}

func DeployAltDA(
host *script.Host,
input DeployAltDAInput,
) (DeployAltDAOutput, error) {
var output DeployAltDAOutput
inputAddr := host.NewScriptAddress()
outputAddr := host.NewScriptAddress()

cleanupInput, err := script.WithPrecompileAtAddress[*DeployAltDAInput](host, inputAddr, &input)
if err != nil {
return output, fmt.Errorf("failed to insert DeployAltDAInput precompile: %w", err)
}
defer cleanupInput()

cleanupOutput, err := script.WithPrecompileAtAddress[*DeployAltDAOutput](host, outputAddr, &output,
script.WithFieldSetter[*DeployAltDAOutput])
if err != nil {
return output, fmt.Errorf("failed to insert DeployAltDAOutput precompile: %w", err)
}
defer cleanupOutput()

implContract := "DeployAltDA"
deployScript, cleanupDeploy, err := script.WithScript[DeployAltDAScript](host, "DeployAltDA.s.sol", implContract)
if err != nil {
return output, fmt.Errorf("failed to laod %s script: %w", implContract, err)
}
defer cleanupDeploy()

if err := deployScript.Run(inputAddr, outputAddr); err != nil {
return output, fmt.Errorf("failed to run %s script: %w", implContract, err)
}

return output, nil
}
43 changes: 43 additions & 0 deletions op-deployer/pkg/deployer/opcm/alt_da_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package opcm

import (
"math/big"
"testing"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)

func TestDeployAltDA(t *testing.T) {
_, artifacts := testutil.LocalArtifacts(t)

host, err := env.DefaultScriptHost(
broadcaster.NoopBroadcaster(),
testlog.Logger(t, log.LevelInfo),
common.Address{'D'},
artifacts,
0,
)
require.NoError(t, err)

input := DeployAltDAInput{
Salt: common.HexToHash("0x1234"),
ProxyAdmin: common.Address{'P'},
ChallengeContractOwner: common.Address{'O'},
ChallengeWindow: big.NewInt(100),
ResolveWindow: big.NewInt(200),
BondSize: big.NewInt(300),
ResolverRefundPercentage: big.NewInt(50), // must be < 100
}

output, err := DeployAltDA(host, input)
require.NoError(t, err)

require.NotEmpty(t, output.DataAvailabilityChallengeProxy)
require.NotEmpty(t, output.DataAvailabilityChallengeImpl)
}
56 changes: 56 additions & 0 deletions op-deployer/pkg/deployer/pipeline/alt_da.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package pipeline

import (
"fmt"
"math/big"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state"
"github.com/ethereum/go-ethereum/common"
)

func DeployAltDA(env *Env, intent *state.Intent, st *state.State, chainID common.Hash) error {
lgr := env.Logger.New("stage", "deploy-alt-da")

chainIntent, err := intent.Chain(chainID)
if err != nil {
return fmt.Errorf("failed to get chain intent: %w", err)
}

chainState, err := st.Chain(chainID)
if err != nil {
return fmt.Errorf("failed to get chain state: %w", err)
}

if !shouldDeployAltDA(chainIntent, chainState) {
lgr.Info("alt-da deployment not needed")
return nil
}

var dao opcm.DeployAltDAOutput
lgr.Info("deploying alt-da contracts")
dao, err = opcm.DeployAltDA(env.L1ScriptHost, opcm.DeployAltDAInput{
Salt: st.Create2Salt,
ProxyAdmin: st.ImplementationsDeployment.OpcmProxyAddress,
ChallengeContractOwner: chainIntent.Roles.L1ProxyAdminOwner,
ChallengeWindow: new(big.Int).SetUint64(chainIntent.DangerousAltDAConfig.DAChallengeWindow),
ResolveWindow: new(big.Int).SetUint64(chainIntent.DangerousAltDAConfig.DAResolveWindow),
BondSize: new(big.Int).SetUint64(chainIntent.DangerousAltDAConfig.DABondSize),
ResolverRefundPercentage: new(big.Int).SetUint64(chainIntent.DangerousAltDAConfig.DAResolverRefundPercentage),
})
if err != nil {
return fmt.Errorf("failed to deploy alt-da contracts: %w", err)
}

chainState.DataAvailabilityChallengeProxyAddress = dao.DataAvailabilityChallengeProxy
chainState.DataAvailabilityChallengeImplAddress = dao.DataAvailabilityChallengeImpl
return nil
}

func shouldDeployAltDA(chainIntent *state.ChainIntent, chainState *state.ChainState) bool {
if !chainIntent.DangerousAltDAConfig.UseAltDA {
return false
}

return chainState.DataAvailabilityChallengeImplAddress == common.Address{}
}
5 changes: 5 additions & 0 deletions op-deployer/pkg/deployer/state/deploy_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ func CombineDeployConfig(intent *Intent, chainIntent *ChainIntent, state *State,
}
}

if chainIntent.DangerousAltDAConfig.UseAltDA {
cfg.AltDADeployConfig = chainIntent.DangerousAltDAConfig
cfg.L1DependenciesConfig.DAChallengeProxy = chainState.DataAvailabilityChallengeProxyAddress
}

// The below dummy variables are set in order to allow the deploy
// config to pass validation. The validation checks are useful to
// ensure that the L2 is properly configured. They are not used by
Expand Down
8 changes: 8 additions & 0 deletions op-deployer/pkg/deployer/state/intent.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"math/big"

"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
Expand Down Expand Up @@ -163,6 +165,8 @@ type ChainIntent struct {
Roles ChainRoles `json:"roles" toml:"roles"`

DeployOverrides map[string]any `json:"deployOverrides" toml:"deployOverrides"`

DangerousAltDAConfig genesis.AltDADeployConfig `json:"dangerousAltDAConfig,omitempty" toml:"dangerousAltDAConfig,omitempty"`
}

type ChainRoles struct {
Expand Down Expand Up @@ -207,5 +211,9 @@ func (c *ChainIntent) Check() error {
return fmt.Errorf("batcher must be set")
}

if c.DangerousAltDAConfig.UseAltDA {
return c.DangerousAltDAConfig.Check(nil)
}

return nil
}
2 changes: 2 additions & 0 deletions op-deployer/pkg/deployer/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ type ChainState struct {
PermissionedDisputeGameAddress common.Address `json:"permissionedDisputeGameAddress"`
DelayedWETHPermissionedGameProxyAddress common.Address `json:"delayedWETHPermissionedGameProxyAddress"`
DelayedWETHPermissionlessGameProxyAddress common.Address `json:"delayedWETHPermissionlessGameProxyAddress"`
DataAvailabilityChallengeProxyAddress common.Address `json:"dataAvailabilityChallengeProxyAddress"`
DataAvailabilityChallengeImplAddress common.Address `json:"dataAvailabilityChallengeImplAddress"`

Allocs *GzipData[foundry.ForgeAllocs] `json:"allocs"`

Expand Down
Loading

0 comments on commit dec8c60

Please sign in to comment.