Skip to content

Commit

Permalink
Testnets: configure two enclaves for HA sequencer node (#2201)
Browse files Browse the repository at this point in the history
  • Loading branch information
BedrockSquirrel authored Dec 16, 2024
1 parent 16ae5cd commit 00fc8d3
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 44 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/manual-deploy-testnet-l2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ jobs:
host_id: 1
- node_l1_ws_lookup: L1_WS_URL_2
host_id: 2
# sequencer has an HA setup with 2 enclaves
- num_enclaves: 2
host_id: 0
- num_enclaves: 1
host_id: 1
- num_enclaves: 1
host_id: 2

steps:
- name: 'Extract branch name'
Expand Down Expand Up @@ -336,6 +343,7 @@ jobs:
&& sudo go run /home/obscuro/go-obscuro/go/node/cmd \
-is_genesis=${{ matrix.is_genesis }} \
-node_type=${{ matrix.node_type }} \
-num_enclaves=${{ matrix.num_enclaves }} \
-is_sgx_enabled=true \
-host_id=${{ vars[matrix.node_addr_lookup] }} \
-l1_ws_url=${{ secrets[matrix.node_l1_ws_lookup] }} \
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/manual-upgrade-testnet-l2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ jobs:
host_id: 1
- node_l1_ws_lookup: L1_WS_URL_2
host_id: 2
# sequencer has an HA setup with 2 enclaves
- num_enclaves: 2
host_id: 0
- num_enclaves: 1
host_id: 1
- num_enclaves: 1
host_id: 2

steps:
- name: 'Extract branch name'
Expand Down Expand Up @@ -162,6 +169,7 @@ jobs:
&& sudo go run /home/obscuro/go-obscuro/go/node/cmd \
-is_genesis=${{ matrix.is_genesis }} \
-node_type=${{ matrix.node_type }} \
-num_enclaves=${{ matrix.num_enclaves }} \
-is_sgx_enabled=true \
-host_id=${{ vars[matrix.node_addr_lookup] }} \
-l1_ws_url=${{ secrets[matrix.node_l1_ws_lookup] }} \
Expand Down
14 changes: 11 additions & 3 deletions go/node/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type NodeConfigCLI struct {
nodeAction string
nodeType string
isGenesis bool
numEnclaves int
isSGXEnabled bool
enclaveDockerImage string
hostDockerImage string
Expand Down Expand Up @@ -64,6 +65,7 @@ func ParseConfigCLI() *NodeConfigCLI {
nodeName := flag.String(nodeNameFlag, "obscuronode", flagUsageMap[nodeNameFlag])
nodeType := flag.String(nodeTypeFlag, "", flagUsageMap[nodeTypeFlag])
isGenesis := flag.Bool(isGenesisFlag, false, flagUsageMap[isGenesisFlag])
numEnclaves := flag.Int(numEnclavesFlag, 1, flagUsageMap[numEnclavesFlag])
isSGXEnabled := flag.Bool(isSGXEnabledFlag, false, flagUsageMap[isSGXEnabledFlag])
enclaveDockerImage := flag.String(enclaveDockerImageFlag, "", flagUsageMap[enclaveDockerImageFlag])
hostDockerImage := flag.String(hostDockerImageFlag, "", flagUsageMap[hostDockerImageFlag])
Expand Down Expand Up @@ -98,6 +100,7 @@ func ParseConfigCLI() *NodeConfigCLI {
cfg.nodeName = *nodeName
cfg.nodeType = *nodeType
cfg.isGenesis = *isGenesis
cfg.numEnclaves = *numEnclaves
cfg.isSGXEnabled = *isSGXEnabled
cfg.enclaveDockerImage = *enclaveDockerImage
cfg.hostDockerImage = *hostDockerImage
Expand Down Expand Up @@ -166,6 +169,11 @@ func NodeCLIConfigToTenConfig(cliCfg *NodeConfigCLI) *config.TenConfig {
fmt.Printf("Error loading default Ten config: %v\n", err)
os.Exit(1)
}
enclaveAddresses := make([]string, cliCfg.numEnclaves)
for i := 0; i < cliCfg.numEnclaves; i++ {
enclaveAddresses[i] = fmt.Sprintf("%s-enclave-%d:%d",
cliCfg.nodeName, i, cliCfg.enclaveWSPort)
}

tenCfg.Network.L1.ChainID = int64(cliCfg.l1ChainID)
tenCfg.Network.L1.L1Contracts.ManagementContract = gethcommon.HexToAddress(cliCfg.managementContractAddr)
Expand Down Expand Up @@ -199,7 +207,7 @@ func NodeCLIConfigToTenConfig(cliCfg *NodeConfigCLI) *config.TenConfig {
tenCfg.Host.DB.UseInMemory = false // these nodes always use a persistent DB
tenCfg.Host.DB.PostgresHost = cliCfg.postgresDBHost
tenCfg.Host.Debug.EnableDebugNamespace = cliCfg.isDebugNamespaceEnabled
tenCfg.Host.Enclave.RPCAddresses = []string{fmt.Sprintf("%s:%d", cliCfg.nodeName+"-enclave", cliCfg.enclaveWSPort)}
tenCfg.Host.Enclave.RPCAddresses = enclaveAddresses
tenCfg.Host.L1.WebsocketURL = cliCfg.l1WebsocketURL
tenCfg.Host.L1.L1BeaconUrl = cliCfg.l1BeaconUrl
tenCfg.Host.L1.L1BlobArchiveUrl = cliCfg.l1BlobArchiveUrl
Expand All @@ -209,8 +217,8 @@ func NodeCLIConfigToTenConfig(cliCfg *NodeConfigCLI) *config.TenConfig {
tenCfg.Host.RPC.WSPort = uint64(cliCfg.hostWSPort)
tenCfg.Host.Log.Level = cliCfg.logLevel

tenCfg.Enclave.DB.UseInMemory = false // these nodes always use a persistent DB
tenCfg.Enclave.DB.EdgelessDBHost = cliCfg.nodeName + "-edgelessdb"
tenCfg.Enclave.DB.UseInMemory = false // these nodes always use a persistent DB
tenCfg.Enclave.DB.EdgelessDBHost = cliCfg.nodeName + "-edgelessdb-" + "0" // will be dynamically set for HA
tenCfg.Enclave.Debug.EnableDebugNamespace = cliCfg.isDebugNamespaceEnabled
tenCfg.Enclave.EnableAttestation = cliCfg.isSGXEnabled
tenCfg.Enclave.RPC.BindAddress = fmt.Sprintf("0.0.0.0:%d", cliCfg.enclaveWSPort)
Expand Down
4 changes: 3 additions & 1 deletion go/node/cmd/cli_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const (
nodeNameFlag = "node_name"
nodeTypeFlag = "node_type"
isGenesisFlag = "is_genesis"
numEnclavesFlag = "num_enclaves"
hostIDFlag = "host_id"
isSGXEnabledFlag = "is_sgx_enabled"
enclaveDockerImageFlag = "enclave_docker_image"
Expand Down Expand Up @@ -43,7 +44,8 @@ func getFlagUsageMap() map[string]string {
return map[string]string{
nodeNameFlag: "Specifies the node base name",
nodeTypeFlag: "The node's type (e.g. sequencer, validator)",
isGenesisFlag: "Wether the node is the genesis node of the network",
isGenesisFlag: "Whether the node is the genesis node of the network",
numEnclavesFlag: "The number of enclaves to run as an HA setup (default 1, no HA pool)",
hostIDFlag: "The 20 bytes of the address of the Obscuro host this enclave serves",
isSGXEnabledFlag: "Whether the it should run on an SGX is enabled CPU",
enclaveDockerImageFlag: "Docker image for the enclave",
Expand Down
2 changes: 1 addition & 1 deletion go/node/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func main() {

tenCfg := NodeCLIConfigToTenConfig(cliConfig)

dockerNode := node.NewDockerNode(tenCfg, cliConfig.hostDockerImage, cliConfig.enclaveDockerImage, cliConfig.edgelessDBImage, false, cliConfig.pccsAddr)
dockerNode := node.NewDockerNode(tenCfg, cliConfig.hostDockerImage, cliConfig.enclaveDockerImage, cliConfig.edgelessDBImage, false, cliConfig.pccsAddr, cliConfig.numEnclaves)
var err error
switch cliConfig.nodeAction {
case startAction:
Expand Down
67 changes: 42 additions & 25 deletions go/node/docker_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,36 @@ type DockerNode struct {
edgelessDBImage string
enclaveDebugMode bool
pccsAddr string // optional specified PCCS address
numEnclaves int // number of enclaves to start for the node as an HA setup
}

func NewDockerNode(cfg *config.TenConfig, hostImage, enclaveImage, edgelessDBImage string, enclaveDebug bool, pccsAddr string) *DockerNode {
func NewDockerNode(cfg *config.TenConfig, hostImage, enclaveImage, edgelessDBImage string, enclaveDebug bool, pccsAddr string, numEnclaves int) *DockerNode {
return &DockerNode{
cfg: cfg,
hostImage: hostImage,
enclaveImage: enclaveImage,
edgelessDBImage: edgelessDBImage,
enclaveDebugMode: enclaveDebug,
pccsAddr: pccsAddr,
numEnclaves: numEnclaves,
}
}

func (d *DockerNode) Start() error {
// todo (@pedro) - this should probably be removed in the future
d.cfg.PrettyPrint() // dump config to stdout

err := d.startEdgelessDB()
if err != nil {
return fmt.Errorf("failed to start edgelessdb: %w", err)
}
var err error
for i := 0; i < d.numEnclaves; i++ {
err = d.startEdgelessDB(i)
if err != nil {
return fmt.Errorf("failed to start edgelessdb: %w", err)
}

err = d.startEnclave()
if err != nil {
return fmt.Errorf("failed to start enclave: %w", err)
err = d.startEnclave(i)
if err != nil {
return fmt.Errorf("failed to start enclave: %w", err)
}
}

err = d.startHost()
Expand All @@ -62,9 +67,11 @@ func (d *DockerNode) Stop() error {
return err
}

err = docker.StopAndRemove(d.cfg.Node.Name + "-enclave")
if err != nil {
return err
for i := 0; i < d.numEnclaves; i++ {
err = docker.StopAndRemove(d.cfg.Node.Name + "-enclave-" + strconv.Itoa(i))
if err != nil {
return err
}
}

return nil
Expand All @@ -84,10 +91,12 @@ func (d *DockerNode) Upgrade(networkCfg *NetworkConfig) error {
d.cfg.Network.L1.L1Contracts.MessageBusContract = common.HexToAddress(networkCfg.MessageBusAddress)
d.cfg.Network.L1.StartHash = common.HexToHash(networkCfg.L1StartHash)

fmt.Println("Starting upgraded host and enclave")
err = d.startEnclave()
if err != nil {
return err
fmt.Println("Starting upgraded host and enclaves")
for i := 0; i < d.numEnclaves; i++ {
err = d.startEnclave(i)
if err != nil {
return err
}
}

err = d.startHost()
Expand Down Expand Up @@ -124,7 +133,7 @@ func (d *DockerNode) startHost() error {
return err
}

func (d *DockerNode) startEnclave() error {
func (d *DockerNode) startEnclave(enclaveIdx int) error {
devices := map[string]string{}
exposedPorts := []int{}

Expand All @@ -134,6 +143,9 @@ func (d *DockerNode) startEnclave() error {
}

if d.enclaveDebugMode {
if d.numEnclaves > 1 {
return fmt.Errorf("cannot run multiple enclaves in debug mode")
}
cmd = []string{
"dlv",
"--listen=:2345",
Expand All @@ -147,6 +159,9 @@ func (d *DockerNode) startEnclave() error {
exposedPorts = append(exposedPorts, 2345)
}

// we set the edgeless DB address dynamically for each enclave
d.cfg.Enclave.DB.EdgelessDBHost = fmt.Sprintf("%s-edgelessdb-%d", d.cfg.Node.Name, enclaveIdx)

envVariables := d.cfg.ToEnvironmentVariables()

if d.cfg.Enclave.EnableAttestation {
Expand All @@ -163,16 +178,21 @@ func (d *DockerNode) startEnclave() error {
cmd = append(cmd, "-willAttest=false")
}

volumeName := fmt.Sprintf("%s-enclave-volume-%d", d.cfg.Node.Name, enclaveIdx)
containerName := fmt.Sprintf("%s-enclave-%d", d.cfg.Node.Name, enclaveIdx)

// we need the enclave volume to store the db credentials
enclaveVolume := map[string]string{d.cfg.Node.Name + "-enclave-volume": _enclaveDataDir}
_, err := docker.StartNewContainer(d.cfg.Node.Name+"-enclave", d.enclaveImage, cmd, exposedPorts, envVariables, devices, enclaveVolume, true)
enclaveVolume := map[string]string{volumeName: _enclaveDataDir}
_, err := docker.StartNewContainer(containerName, d.enclaveImage, cmd, exposedPorts, envVariables, devices, enclaveVolume, true)

return err
}

func (d *DockerNode) startEdgelessDB() error {
func (d *DockerNode) startEdgelessDB(enclaveIdx int) error {
containerName := fmt.Sprintf("%s-edgelessdb-%d", d.cfg.Node.Name, enclaveIdx)
volumeName := fmt.Sprintf("%s-db-volume-%d", d.cfg.Node.Name, enclaveIdx)
envs := map[string]string{
"EDG_EDB_CERT_DNS": d.cfg.Node.Name + "-edgelessdb",
"EDG_EDB_CERT_DNS": containerName,
}
devices := map[string]string{}

Expand All @@ -188,11 +208,8 @@ func (d *DockerNode) startEdgelessDB() error {
envs["PCCS_ADDR"] = d.pccsAddr
}

// todo - do we need this volume?
//dbVolume := map[string]string{d.cfg.Node.Name + "-db-volume": "/data"}
//_, err := docker.StartNewContainer(d.cfg.Node.Name+"-edgelessdb", d.cfg.edgelessDBImage, nil, nil, envs, devices, dbVolume)

_, err := docker.StartNewContainer(d.cfg.Node.Name+"-edgelessdb", d.edgelessDBImage, nil, nil, envs, devices, nil, true)
dbVolume := map[string]string{volumeName: "/data"}
_, err := docker.StartNewContainer(containerName, d.edgelessDBImage, nil, nil, envs, devices, dbVolume, true)

return err
}
16 changes: 2 additions & 14 deletions testnet/launcher/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,7 @@ func (t *Testnet) Start() error {
sequencerCfg.Network.L1.L1Contracts.ManagementContract = common.HexToAddress(networkConfig.ManagementContractAddress)
sequencerCfg.Network.L1.L1Contracts.MessageBusContract = common.HexToAddress(networkConfig.MessageBusAddress)

sequencerNode := node.NewDockerNode(sequencerCfg,
"testnetobscuronet.azurecr.io/obscuronet/host:latest",
"testnetobscuronet.azurecr.io/obscuronet/enclave:latest",
edgelessDBImage,
false,
"", // no PCCS override
)
sequencerNode := node.NewDockerNode(sequencerCfg, "testnetobscuronet.azurecr.io/obscuronet/host:latest", "testnetobscuronet.azurecr.io/obscuronet/enclave:latest", edgelessDBImage, false, "", 0)

err = sequencerNode.Start()
if err != nil {
Expand All @@ -93,13 +87,7 @@ func (t *Testnet) Start() error {
validatorNodeCfg.Network.L1.L1Contracts.ManagementContract = common.HexToAddress(networkConfig.ManagementContractAddress)
validatorNodeCfg.Network.L1.L1Contracts.MessageBusContract = common.HexToAddress(networkConfig.MessageBusAddress)

validatorNode := node.NewDockerNode(validatorNodeCfg,
"testnetobscuronet.azurecr.io/obscuronet/host:latest",
"testnetobscuronet.azurecr.io/obscuronet/enclave:latest",
edgelessDBImage,
false,
"", // no PCCS override
)
validatorNode := node.NewDockerNode(validatorNodeCfg, "testnetobscuronet.azurecr.io/obscuronet/host:latest", "testnetobscuronet.azurecr.io/obscuronet/enclave:latest", edgelessDBImage, false, "", 0)
err = validatorNode.Start()
if err != nil {
return fmt.Errorf("unable to start the obscuro node - %w", err)
Expand Down

0 comments on commit 00fc8d3

Please sign in to comment.