deploy-config

When deploying the rollup, by default it is set to rollup mode: all transactions are sent to L1. If we want to change that behavior,
we specify these fields in the deploy-config of our rollup contracts:

  "enableDAC": true,
  "dacPublicKeys": [
    "10c36f69c5f73a0ae95fa1768e68a58973d0a3a61f1e9bf889050217388ebb24c57341fb5528b8f2b6138d5149d88c611003f241a22da86d76e15cdfdc06d6ea86845d5f662e3209044716add654d98aa6a9c99632b2d647ac280e36d9da5756",
    "1866562f34d7339fc7831b4b6a47defe714007f4720d03849f2e90b0ee8330d56d76e0957f500fe76f24e6a730016bcf091e3ba87744ceefd90503b120550eb9554f5683b739fb1cbdd6e56ac7b89288e9f35ce7e32d40008f347b21e036602c",
    "1830f58c42f446a5659c08a5c39a2734cdbca673007076612384387d3f79e6c44c2427012cac0b011c698b9c0d5834920a7ec51884e4f7b43d73a683d1038c1b940dd4c1aa69bd097419b8ed69ff9447e44c9da1e8ea38ac916655260a42b14e"
  ],
  "dacHonnestMembersAssumption": 2

This will generate a rollup configuration that embeds these information.

rollup-config

In the rollup.json, we add a data_availability_committee field that describes the properties of the DAC. This means that the DAC is part of the rollup configuration :

  "data_availability_committee": {
    "public_keys": [
      "07e23eb4be09609d92e73a4660f6b543ba26777d53db3e1ef64ef934177a82fe090f3bf31bb0fd0adb9ee7a2e4cf3260184ea695cfbb36ffeb1bc6183268c3ff0799699cdfa067b6aea70e908b3b8b31e924fa70fc105fda531b80f9ccbb528e",
      "0f630b04de66c7a4120344dba4e46954bf48f9faa7b9085ee1fdb3a2880af43ae8c7dac640d2ad7d93ff38f5737c3d1000070a64414e9607dd75ca886f52cfdb4745d3f443332e69c5f73ee23fcff62593b24504b29b65f3fb5aaa2a6516d729",
      "0bf160cda8786d5c50ef3841a1412fce870f718cc838dce3bd1ef1ef2e3a6a8141d374ceb45f17b7dcd0d628782549110295a32173312d888a6a75c9b5ed917624cd81c70cde56fe8cea304cb537f5cf6ea0dd74ea00996a36640cd8ae38a37f"
    ],
    "honnest_members_assumption": 2
  },

Code updates

da.Client interface

type BatchRef interface {
  ToTx() (Tx, error)
}

type Client interface {
  PostBatch(data []byte) (BatchRef, error)
  GetBatch(ref []byte) ([]byte, error)
}

We propose a simple implementation of a Data Availability Client. A DA client should be able to

  1. Post a batch. This method should return what we call a batch reference. A batch reference should contain enough information to retrieve the original payload. It should also be serializable to an L1 transaction.
    • In the basic rollup mode this is a no-op. The reference is the payload itself.
    • In the DAC mode it will upload the payload to the DAC and return all the information required to verify signatures and fetch the payload later.
  2. Retrieve a batch. From a serialized batch reference, it must return the associated payload.
    • In the basic rollup mode it means returning the reference itself, because the reference is the payload.
    • In the DAC mode, it means deserialize the batch reference and query the DAC to get the payload back.

Config instanciation

When we instanciate a node. The only thing we now need to do is create the correct DA client. By default we provide a rollup mode.
If the rollup configuration specifies a Data Availability Committee, we enter DAC mode.

  // by default use rollup mode
  daClient := rollupda.NewClient(rollupConfig.BatchInboxAddress)
  daURL := ctx.GlobalString(flags.CentralizedDAApiFlag.Name)
  if rollupConfig.DataAvailabilityComittee != nil {
    log.Info("initializing DAC da client", "url", daURL)
    log.Info("public keys", "public_keys", rollupConfig.DataAvailabilityComittee.PublicKeys)
    keyset, err := dac.NewKeySetFromString(rollupConfig.DataAvailabilityComittee.PublicKeys)
    if err != nil {
      return nil, fmt.Errorf("could not create DAC keyset: %w", err)
    }
    daClient = dac.NewClient(daURL, rollupConfig.BatchInboxAddress, keyset)
  }

op-batcher

We modified op-batcher to make it publish batch references. It will let the DA client implementation chose what to post or not to post. The DA client will also make relevant calls it needs to do to store the given payload.

  // delegate DA posting logic to the client
  batchRef, err := l.DA.PostBatch(data)
  if err != nil {
    l.log.Error("unable to publish data to DA", "err", err, "data_size", len(data))
    return
  }

  tx, err := batchRef.ToTx()
  if err != nil {
    l.log.Error("unable to construct tx from batch ref", "err")
  }

op-node derivation

At the derivation step, each transaction contains a batch reference. Since the DA mode is described in the rollup configuration, we can safely pass the batch reference to the DA client implementation that will do what it needs to do to fetch the correct payload.

      // delegate getting batch data to the DA client
      ref := tx.Data()
      data, err := daClient.GetBatch(ref)
      if err != nil {
        return nil, fmt.Errorf("could not retrieve batch from ref: %w", err)
      }

Other implementations

To make a new implementation, one needs to :

  1. Implement a DA client
  2. Add the relevant configuration in the deploy configuration and/or the rollup configuration.

We provide an implementation of a DAC in our optimism fork.