Skip to content

Conversation

@ypatil12
Copy link
Collaborator

@ypatil12 ypatil12 commented May 8, 2025

Motivation:

Initial interfaces for multi chain.

Modifications:

TableCalculator

The separation here is designed to decouple

  • Curve-Specific Calculation
  • Generic Table Calculation Getters (applicable for all curve types)
  • Weighting. IOperatorWeightCalculator is a calculation contract that defines how to weigh stakes of an operatorSet. This contract may or may not be stateless. In practice, this can be an external contract or library.
classDiagram
    IOperatorWeightCalculator <-- IOperatorTableCalculator : uses many
    IOperatorTableCalculator <|-- IECDSATableCalculator : implements
    IOperatorTableCalculator <|-- IBN254TableCalculator : implements

    
    class IOperatorWeightCalculator {
        +getOperatorWeights(OperatorSet)
    }
    
    class IOperatorTableCalculator {
        +setOperatorWeightCalculator(OperatorSet, IOperatorWeightCalculator)
        +calculateOperatorTableBytes(OperatorSet) returns (bytes)
        +getOperatorWeightCalculator(OperatorSet) returns (IOperatorWeightCalculator)
    }
    
    class IECDSATableCalculator {
        +calculateOperatorTable(OperatorSet) returns (ECDSAOperatorInfo[])
    }
    
    class IBN254TableCalculator {
        +calculateOperatorTable(OperatorSet) returns (BN254OperatorSetInfo)
        +getOperatorInfos(OperatorSet) returns (BN254OperatorInfo[])
    }
Loading

CertificateVerifier

The CertificateVerifier decouples setting of the table and verification. See below:

classDiagram
    ICertificateVerifier <|-- IBN254CertificateVerifier: implements
    IBN254TableManager <|-- IBN254CertificateVerifier: implements
    
    class ICertificateVerifier {
        <<interface>>
        +setOperatorTableUpdater(address)
        +setEjector(address)
        +setMaxOperatorTableStaleness(uint32)
        +operatorSet() returns (OperatorSet)
        +operatorTableUpdater() returns (address)
        +ejector() returns (address)
        +maxOperatorTableStaleness() returns (uint32)
        +latestReferenceTimestamp() returns (uint32)
    }
    
    class IBN254TableManager {
        <<interface>>
        +updateOperatorTable(OperatorSet, uint32, BN254OperatorSetInfo)
        +ejectOperators(OperatorSet, uint32, uint32[], BN254OperatorInfoWitness[])
    }
    
    class IBN254CertificateVerifier {
        <<interface>>
        +verifyCertificate(BN254Certificate) returns (uint96[])
        +verifyCertificateProportion(BN254Certificate, uint16[]) returns (bool)
        +verifyCertificateNominal(BN254Certificate, uint96[]) returns (bool)
    }
Loading

Migration Story
We want a migration path to store all tables in a singleton core contract. In order to do so, we future-proofed the transportation interface to pass in an operatorSet when updating an operatorTable. Permissions setting can be done by an EOA, so we don't need to make that forwards compatible. If all the tables live in a single contract, then for Bn254 caching, the verification must cache stakes in the singleton.

Result:

Initial Interfaces. I see these changing for the following reasons:

  • Encoding leafs with a salt
  • Table generation-based trusted operator table updates
  • Multiquorum sig support (but EigenDA can build their own)

@ypatil12 ypatil12 marked this pull request as ready for review May 8, 2025 22:20
/// @notice A contract that calculates the weights for all operators in a given operatorSet
/// @notice This is a base interface to send operator weights to the `IOperatorTableCalculator`
/// @notice We separate this out to be able to plug-in different operator weight calculators for each operatorSet
interface IOperatorWeightCalculator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate external calculator contract per operatorSet. The TableCalculator is global for all operatorSets. The IOperatorWeightCalculator is for a single operatorSet

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So many contracts :( can we just put it all in this thing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes we can, but leaving decoupled for now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like we want abstract contracts rather than interfaces? maybe im being pedantic

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the current impl has abstract contracts. We definitely can implement it that way

@ypatil12 ypatil12 merged commit 8b20633 into release-dev/multichain May 12, 2025
5 checks passed
@ypatil12 ypatil12 deleted the yash/multichain-interfaces branch May 12, 2025 13:48
Comment on lines +52 to +53
/// @notice the address of the entity that can eject operators
function ejector() external returns (address);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why the Ejector is in this contract vs something like the AVSRegistrar?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to eject on L2s, and the AVSRegistrar isn't there

ypatil12 added a commit that referenced this pull request Jul 10, 2025
**Motivation:**

Initial interfaces for multi chain. 

**Modifications:**

***TableCalculator***

The separation here is designed to decouple
- Curve-Specific Calculation
- Generic Table Calculation Getters (applicable for all curve types)
- Weighting. `IOperatorWeightCalculator` is a calculation contract that
defines how to weigh stakes of an operatorSet. This contract may or may
not be stateless. In practice, this can be an external contract or
library.

```mermaid
classDiagram
    IOperatorWeightCalculator <-- IOperatorTableCalculator : uses many
    IOperatorTableCalculator <|-- IECDSATableCalculator : implements
    IOperatorTableCalculator <|-- IBN254TableCalculator : implements

    
    class IOperatorWeightCalculator {
        +getOperatorWeights(OperatorSet)
    }
    
    class IOperatorTableCalculator {
        +setOperatorWeightCalculator(OperatorSet, IOperatorWeightCalculator)
        +calculateOperatorTableBytes(OperatorSet) returns (bytes)
        +getOperatorWeightCalculator(OperatorSet) returns (IOperatorWeightCalculator)
    }
    
    class IECDSATableCalculator {
        +calculateOperatorTable(OperatorSet) returns (ECDSAOperatorInfo[])
    }
    
    class IBN254TableCalculator {
        +calculateOperatorTable(OperatorSet) returns (BN254OperatorSetInfo)
        +getOperatorInfos(OperatorSet) returns (BN254OperatorInfo[])
    }
```

***CertificateVerifier***

The `CertificateVerifier` decouples setting of the table and
verification. See below:

```mermaid
classDiagram
    ICertificateVerifier <|-- IBN254CertificateVerifier: implements
    IBN254TableManager <|-- IBN254CertificateVerifier: implements
    
    class ICertificateVerifier {
        <<interface>>
        +setOperatorTableUpdater(address)
        +setEjector(address)
        +setMaxOperatorTableStaleness(uint32)
        +operatorSet() returns (OperatorSet)
        +operatorTableUpdater() returns (address)
        +ejector() returns (address)
        +maxOperatorTableStaleness() returns (uint32)
        +latestReferenceTimestamp() returns (uint32)
    }
    
    class IBN254TableManager {
        <<interface>>
        +updateOperatorTable(OperatorSet, uint32, BN254OperatorSetInfo)
        +ejectOperators(OperatorSet, uint32, uint32[], BN254OperatorInfoWitness[])
    }
    
    class IBN254CertificateVerifier {
        <<interface>>
        +verifyCertificate(BN254Certificate) returns (uint96[])
        +verifyCertificateProportion(BN254Certificate, uint16[]) returns (bool)
        +verifyCertificateNominal(BN254Certificate, uint96[]) returns (bool)
    }
```

***Migration Story***
We want a migration path to store all tables in a singleton core
contract. In order to do so, we future-proofed the _transportation_
interface to pass in an `operatorSet` when updating an operatorTable.
Permissions setting can be done by an EOA, so we don't need to make that
forwards compatible. If all the tables live in a single contract, then
for Bn254 caching, the verification must cache stakes in the singleton.

**Result:**

Initial Interfaces. I see these changing for the following reasons:

- Encoding leafs with a salt
- Table generation-based trusted operator table updates
- Multiquorum sig support (but EigenDA can build their own)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants