Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testnets: grant sequencer enclaveID permission on L1 #2185

Merged
merged 5 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions .github/workflows/manual-deploy-testnet-l2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,46 @@ jobs:
./.github/workflows/runner-scripts/wait-node-healthy.sh --host=obscuronode-0-${{ github.event.inputs.testnet_type }}.uksouth.cloudapp.azure.com
./.github/workflows/runner-scripts/wait-node-healthy.sh --host=obscuronode-1-${{ github.event.inputs.testnet_type }}.uksouth.cloudapp.azure.com
./.github/workflows/runner-scripts/wait-node-healthy.sh --host=obscuronode-2-${{ github.event.inputs.testnet_type }}.uksouth.cloudapp.azure.com


deploy-l2-contracts:
grant-sequencer-enclaves:
needs:
- build
- check-obscuro-is-healthy
runs-on: ubuntu-latest
environment:
name: ${{ github.event.inputs.testnet_type }}
steps:
- uses: actions/checkout@v4

- name: 'Grant permission to sequencer enclave(s)'
id: grantSequencerPermission
shell: bash
run: |
go run ./testnet/launcher/l1grantsequencers/cmd \
-l1_http_url=${{ secrets.L1_HTTP_URL }} \
-private_key=${{ secrets.ACCOUNT_PK_WORKER }} \
-management_contract_addr=${{ needs.build.outputs.MGMT_CONTRACT_ADDR }} \
-docker_image=${{ vars.L2_HARDHATDEPLOYER_DOCKER_BUILD_TAG }} \
-sequencer_url=http://obscuronode-0-${{ github.event.inputs.testnet_type }}.uksouth.cloudapp.azure.com:80

- name: 'Save sequencer permissioning container logs'
run: |
docker logs `docker ps -aqf "name=grant-sequencers"` > grant-sequencers.out 2>&1

- name: 'Upload sequencer permissioning container logs'
uses: actions/upload-artifact@v4
with:
name: grant-sequencers
path: |
grant-sequencers.out
retention-days: 7

deploy-l2-contracts:
needs:
- build
- grant-sequencer-enclaves
runs-on: ubuntu-latest
environment:
name: ${{ github.event.inputs.testnet_type }}
steps:
Expand Down Expand Up @@ -417,7 +451,7 @@ jobs:

update-loadbalancer:
needs:
- check-obscuro-is-healthy
- grant-sequencer-enclaves
runs-on: ubuntu-latest
environment:
name: ${{ github.event.inputs.testnet_type }}
Expand Down Expand Up @@ -450,7 +484,7 @@ jobs:
testnet_type: ${{ github.event.inputs.testnet_type }}
secrets: inherit
needs:
- check-obscuro-is-healthy
- grant-sequencer-enclaves

obscuro-test-repository-dispatch:
runs-on: ubuntu-latest
Expand Down
10 changes: 6 additions & 4 deletions contracts/scripts/sequencer/001_grant_sequencers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ const grantSequencerStatus = async function (mgmtContractAddr: string, enclaveID
}
};

const args = process.argv.slice(2);
if (args.length !== 2) {
throw new Error("Required arguments: <mgmtContractAddr> <enclaveIDs>");
const mgmtContractAddr = process.env.MGMT_CONTRACT_ADDRESS;
const enclaveIDs = process.env.ENCLAVE_IDS;

if (!mgmtContractAddr || !enclaveIDs) {
console.error("Missing required environment variables: MGMT_CONTRACT_ADDRESS and ENCLAVE_IDS.");
process.exit(1);
}

const [mgmtContractAddr, enclaveIDs] = args as [string, string];
grantSequencerStatus(mgmtContractAddr, enclaveIDs)
.then(() => process.exit(0))
.catch((error) => {
Expand Down
34 changes: 6 additions & 28 deletions testnet/launcher/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package launcher

import (
"fmt"
"strings"
"time"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -138,6 +137,11 @@ func (t *Testnet) Start() error {
return fmt.Errorf("unable to configure the l2 contract deployer - %w", err)
}

err = t.grantSequencerStatus(networkConfig.ManagementContractAddress)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sequencer needs to be permissioned before L2 contracts can be deployed.

if err != nil {
return fmt.Errorf("failed to grant sequencer status: %w", err)
}

err = l2ContractDeployer.Start()
if err != nil {
return fmt.Errorf("unable to start the l2 contract deployer - %w", err)
Expand All @@ -149,11 +153,6 @@ func (t *Testnet) Start() error {
}
fmt.Println("L2 Contracts were successfully deployed...")

err = t.grantSequencerStatus(networkConfig.ManagementContractAddress)
if err != nil {
return fmt.Errorf("failed to grant sequencer status: %w", err)
}

faucetPort := 99
faucetInst, err := faucet.NewDockerFaucet(
faucet.NewFaucetConfig(
Expand Down Expand Up @@ -304,35 +303,14 @@ func waitForHealthyNode(port int) error { // todo: hook the cfg
func (t *Testnet) grantSequencerStatus(mgmtContractAddr string) error {
// fetch enclaveIDs
hostURL := fmt.Sprintf("http://localhost:%d", 80)
client, err := rpc.NewNetworkClient(hostURL)
if err != nil {
return fmt.Errorf("failed to create network client: %w", err)
}
defer client.Stop()

obsClient := obsclient.NewObsClient(client)
health, err := obsClient.Health()
if err != nil {
return fmt.Errorf("failed to get health status: %w", err)
}

if len(health.Enclaves) == 0 {
return fmt.Errorf("could not retrieve enclave IDs from health endpoint")
}

var enclaveIDs []string
for _, status := range health.Enclaves {
enclaveIDs = append(enclaveIDs, status.EnclaveID.String())
}
enclaveIDsStr := strings.Join(enclaveIDs, ",")

l1grantsequencers, err := l1gs.NewGrantSequencers(
l1gs.NewGrantSequencerConfig(
l1gs.WithL1HTTPURL("http://eth2network:8025"),
l1gs.WithPrivateKey("f52e5418e349dccdda29b6ac8b0abe6576bb7713886aa85abea6181ba731f9bb"),
l1gs.WithDockerImage(t.cfg.contractDeployerDockerImage),
l1gs.WithMgmtContractAddress(mgmtContractAddr),
l1gs.WithEnclaveIDs(enclaveIDsStr),
l1gs.WithSequencerURL(hostURL),
),
)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions testnet/launcher/l1grantsequencers/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type L1GrantSequencersConfigCLI struct {
mgmtContractAddress string
enclaveIDs string
dockerImage string
sequencerURL string
}

// ParseConfigCLI returns a NodeConfigCLI based the cli params and defaults.
Expand All @@ -23,13 +24,15 @@ func ParseConfigCLI() *L1GrantSequencersConfigCLI {
mgmtContractAddress := flag.String(mgmtContractAddressFlag, "", flagUsageMap[mgmtContractAddressFlag])
enclaveIDs := flag.String(enclaveIDsFlag, "", flagUsageMap[enclaveIDsFlag])
dockerImage := flag.String(dockerImageFlag, "testnetobscuronet.azurecr.io/obscuronet/hardhatdeployer:latest", flagUsageMap[dockerImageFlag])
sequencerURL := flag.String(sequencerURLFlag, "", flagUsageMap[sequencerURLFlag])
flag.Parse()

cfg.l1HTTPURL = *l1HTTPURL
cfg.privateKey = *privateKey
cfg.mgmtContractAddress = *mgmtContractAddress
cfg.enclaveIDs = *enclaveIDs
cfg.dockerImage = *dockerImage
cfg.sequencerURL = *sequencerURL

return cfg
}
6 changes: 4 additions & 2 deletions testnet/launcher/l1grantsequencers/cmd/cli_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ package main
const (
l1HTTPURLFlag = "l1_http_url"
privateKeyFlag = "private_key"
mgmtContractAddressFlag = "mgmt_contract_address"
mgmtContractAddressFlag = "management_contract_addr"
enclaveIDsFlag = "enclave_ids"
dockerImageFlag = "docker_image"
contractsEnvFileFlag = "contracts_env_file"
sequencerURLFlag = "sequencer_url"
)

// Returns a map of the flag usages.
Expand All @@ -17,8 +18,9 @@ func getFlagUsageMap() map[string]string {
l1HTTPURLFlag: "Layer 1 network http RPC addr",
privateKeyFlag: "L1 and L2 private key used in the node",
mgmtContractAddressFlag: "L1 management contract address",
enclaveIDsFlag: "List of enclave public keys",
enclaveIDsFlag: "List of enclave public keys to grant sequencer role",
dockerImageFlag: "Docker image to run",
contractsEnvFileFlag: "If set, it will write the contract addresses to the file",
sequencerURLFlag: "Sequencer RPC URL to fetch enclave IDs (required if enclaveIDs are not provided)",
}
}
11 changes: 9 additions & 2 deletions testnet/launcher/l1grantsequencers/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ func main() {

l1grantsequencers, err := l1gs.NewGrantSequencers(
l1gs.NewGrantSequencerConfig(
l1gs.WithL1HTTPURL("http://eth2network:8025"),
l1gs.WithPrivateKey("f52e5418e349dccdda29b6ac8b0abe6576bb7713886aa85abea6181ba731f9bb"),
l1gs.WithL1HTTPURL(cliConfig.l1HTTPURL),
l1gs.WithPrivateKey(cliConfig.privateKey),
l1gs.WithDockerImage(cliConfig.dockerImage),
l1gs.WithMgmtContractAddress(cliConfig.mgmtContractAddress),
l1gs.WithEnclaveIDs(cliConfig.enclaveIDs),
l1gs.WithSequencerURL(cliConfig.sequencerURL),
),
)
if err != nil {
Expand All @@ -30,5 +31,11 @@ func main() {
os.Exit(1)
}

err = l1grantsequencers.WaitForFinish()
if err != nil {
fmt.Println("unexpected error waiting for grant sequnecer permission script to finish - %w", err)
os.Exit(1)
}
fmt.Println("L1 Sequencer permissions were successfully granted...")
os.Exit(0)
}
8 changes: 8 additions & 0 deletions testnet/launcher/l1grantsequencers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ type Config struct {
mgmtContractAddress string
enclaveIDs string
dockerImage string
sequencerURL string

// debugEnabled bool
}

Expand Down Expand Up @@ -53,6 +55,12 @@ func WithDockerImage(s string) Option {
}
}

func WithSequencerURL(s string) Option {
return func(c *Config) {
c.sequencerURL = s
}
}

//func WithDebugEnabled(b bool) Option {
// return func(c *Config) {
// c.debugEnabled = b
Expand Down
93 changes: 91 additions & 2 deletions testnet/launcher/l1grantsequencers/docker.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
package l1grantsequencers

import (
"bytes"
"context"
"fmt"
"io"
"strings"
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/ten-protocol/go-ten/go/common/docker"
"github.com/ten-protocol/go-ten/go/obsclient"
"github.com/ten-protocol/go-ten/go/rpc"
)

type GrantSequencers struct {
Expand All @@ -18,14 +27,26 @@ func NewGrantSequencers(cfg *Config) (*GrantSequencers, error) {
}

func (s *GrantSequencers) Start() error {
fmt.Printf("Starting grant sequencers with config: %s\n", s.cfg)
var enclaveIDs string
var err error
if s.cfg.enclaveIDs != "" {
enclaveIDs = s.cfg.enclaveIDs
} else if s.cfg.sequencerURL != "" {
enclaveIDs, err = fetchEnclaveIDs(s.cfg.sequencerURL)
if err != nil {
return err
}
} else {
return fmt.Errorf("enclaveIDs or sequencerURL must be provided")
}
cmds := []string{
"npx",
"hardhat",
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This script didn't seem to be running properly, it needed the hardhat command to use the --network flag and I couldn't get it to work with positional args so changed them to env vars.

"run",
"--network",
"layer1",
"scripts/sequencer/001_grant_sequencers.ts",
s.cfg.mgmtContractAddress,
s.cfg.enclaveIDs,
}

envs := map[string]string{
Expand All @@ -37,8 +58,12 @@ func (s *GrantSequencers) Start() error {
"accounts": [ "%s" ]
}
}`, s.cfg.l1HTTPURL, s.cfg.privateKey),
"MGMT_CONTRACT_ADDRESS": s.cfg.mgmtContractAddress,
"ENCLAVE_IDS": enclaveIDs,
}

fmt.Printf("Starting grant sequencer script. MgntContractAddress: %s, EnclaveIDs: %s\n", s.cfg.mgmtContractAddress, enclaveIDs)

containerID, err := docker.StartNewContainer(
"grant-sequencers",
s.cfg.dockerImage,
Expand All @@ -55,3 +80,67 @@ func (s *GrantSequencers) Start() error {
s.containerID = containerID
return nil
}

func (s *GrantSequencers) WaitForFinish() error {
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return fmt.Errorf("failed to create docker client: %w", err)
}
defer cli.Close()

// make sure the container has finished execution
err = docker.WaitForContainerToFinish(s.containerID, 15*time.Minute)
if err != nil {
fmt.Println("Error waiting for container to finish: ", err)
s.PrintLogs(cli)
return err
}

return nil
}

func fetchEnclaveIDs(url string) (string, error) {
// fetch enclaveIDs
client, err := rpc.NewNetworkClient(url)
if err != nil {
return "", fmt.Errorf("failed to create network client (%s): %w", url, err)
}
defer client.Stop()

obsClient := obsclient.NewObsClient(client)
health, err := obsClient.Health()
if err != nil {
return "", fmt.Errorf("failed to get health status: %w", err)
}

if len(health.Enclaves) == 0 {
return "", fmt.Errorf("could not retrieve enclave IDs from health endpoint - no enclaves found")
}

var enclaveIDs []string
for _, status := range health.Enclaves {
enclaveIDs = append(enclaveIDs, status.EnclaveID.String())
}
return strings.Join(enclaveIDs, ","), nil
}

func (s *GrantSequencers) PrintLogs(cli *client.Client) {
logsOptions := types.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
}

// Read the container logs
out, err := cli.ContainerLogs(context.Background(), s.containerID, logsOptions)
if err != nil {
fmt.Printf("Error printing out container %s logs... %v\n", s.containerID, err)
}
defer out.Close()

var buf bytes.Buffer
_, err = io.Copy(&buf, out)
if err != nil {
fmt.Printf("Error getting logs for container %s\n", s.containerID)
}
fmt.Println(buf.String())
}
Loading