Devnet Descriptors
The devnet descriptor is a standardized format that describes the complete topology and configuration of an Optimism devnet deployment. This standard serves as a bridge between different devnet implementations and the higher-level tooling provided by the devnet-sdk.
Universal Descriptor Format
Both kurtosis-devnet
and netchef
emit the same descriptor format, despite being completely different devnet implementations:
- kurtosis-devnet: Uses Kurtosis to orchestrate containerized devnet deployments
- netchef: Provides a lightweight, local devnet deployment
This standardization enables a powerful ecosystem where tools can be built independently of the underlying devnet implementation.
Descriptor Structure
A devnet descriptor provides a complete view of a running devnet:
{
"l1": {
"name": "l1",
"id": "900",
"services": {
"geth": {
"name": "geth",
"endpoints": {
"rpc": {
"host": "localhost",
"port": 8545
}
}
}
},
"nodes": [...],
"addresses": {
"deployer": "0x...",
"admin": "0x..."
},
"wallets": {
"admin": {
"address": "0x...",
"private_key": "0x..."
}
}
},
"l2": [
{
"name": "op-sepolia",
"id": "11155420",
"services": {...},
"nodes": [...],
"addresses": {...},
"wallets": {...}
}
],
"features": ["eip1559", "shanghai"]
}
Enabling Devnet-Agnostic Tooling
The power of the descriptor format lies in its ability to make any compliant devnet implementation immediately accessible to the entire devnet-sdk toolset:
- Universal Interface: Any devnet that can emit this descriptor format can be managed through devnet-sdk's tools
- Automatic Integration: New devnet implementations only need to implement the descriptor format to gain access to:
- System interface for chain interaction
- Testing framework
- Shell integration tools
- Wallet management
- Transaction processing
Benefits
This standardization provides several key advantages:
- Portability: Tools built against the devnet-sdk work with any compliant devnet implementation
- Consistency: Developers get the same experience regardless of the underlying devnet
- Extensibility: New devnet implementations can focus on deployment mechanics while leveraging existing tooling
- Interoperability: Tools can be built that work across different devnet implementations
Implementation Requirements
To make a devnet implementation compatible with devnet-sdk, it needs to:
- Provide a mechanism to output the descriptor (typically as JSON)
- Ensure all required services and endpoints are properly described
Once these requirements are met, the devnet automatically gains access to the full suite of devnet-sdk capabilities.
Status
The descriptor format is currently in active development, particularly regarding endpoint specifications:
Endpoint Requirements
- Current State: The format does not strictly specify which endpoints must be included in a compliant descriptor
- Minimum Known Requirements:
- RPC endpoints are essential for basic chain interaction
- Other endpoints may be optional depending on use case
Implementation Notes
kurtosis-devnet
currently outputs all service endpoints by default, including many that may not be necessary for testing- Other devnet implementations can be more selective about which endpoints they expose
- Different testing scenarios may require different sets of endpoints
Future Development
We plan to develop more specific recommendations for:
- Required vs optional endpoints
- Standard endpoint naming conventions
- Service-specific endpoint requirements
- Best practices for endpoint exposure
Until these specifications are finalized, devnet implementations should:
- Always include RPC endpoints
- Document which additional endpoints they expose
- Consider their specific use cases when deciding which endpoints to include
Example Usage
Here's how a tool might use the descriptor to interact with any compliant devnet:
// Load descriptor from any compliant devnet
descriptor, err := descriptors.Load("devnet.json")
if err != nil {
log.Fatal(err)
}
// Use the descriptor with devnet-sdk tools
system, err := system.FromDescriptor(descriptor)
if err != nil {
log.Fatal(err)
}
// Now you can use all devnet-sdk features
l1 := system.L1()
l2 := system.L2(descriptor.L2[0].ID)
This standardization enables a rich ecosystem of tools that work consistently across different devnet implementations, making development and testing more efficient and reliable.