Skip to content

Commit

Permalink
Management contract challenge period (#2245)
Browse files Browse the repository at this point in the history
* add challenge period to management contract
  • Loading branch information
badgersrus authored Jan 15, 2025
1 parent c82525d commit 1320a97
Show file tree
Hide file tree
Showing 9 changed files with 403 additions and 6 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/manual-deploy-testnet-l2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,40 @@ jobs:
grant-sequencers.out
retention-days: 7

set-challenge-period:
needs:
- build
- check-obscuro-is-healthy
runs-on: ubuntu-latest
environment:
name: ${{ github.event.inputs.testnet_type }}
steps:
- uses: actions/checkout@v4

- name: 'Set challenge period on management contract'
id: setChallengePeriod
shell: bash
run: |
go run ./testnet/launcher/l1challengeperiod/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 }} \
-l1_challenge_period=${{ vars.L1_CHALLENGE_PERIOD }} \
echo "Setting challenge period to ${{ vars.L1_CHALLENGE_PERIOD }}"
- name: 'Save challenge period container logs'
run: |
docker logs `docker ps -aqf "name=set-challenge-period"` > set-challenge-period.out 2>&1
- name: 'Upload challenge period container logs'
uses: actions/upload-artifact@v4
with:
name: set-challenge-period
path: |
set-challenge-period.out
retention-days: 7

deploy-l2-contracts:
needs:
- build
Expand Down
56 changes: 54 additions & 2 deletions contracts/generated/ManagementContract/ManagementContract.go

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions contracts/scripts/delay/001_set_challenge_period.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ethers } from "hardhat";
import { ManagementContract } from "../../typechain-types";

const setChallengePeriod = async function (mgmtContractAddr: string, challengPeriod: number) {
const managementContract = await ethers.getContractAt(
"ManagementContract",
mgmtContractAddr
) as ManagementContract;


console.log(`Setting challenge period to: ${challengPeriod}`);
const tx = await managementContract.SetChallengePeriod(BigInt(challengPeriod));
await tx.wait();
console.log(`Successfully set challenge period to: ${challengPeriod}`);

const mgmtContractChallengePeriod = await managementContract.GetChallengePeriod();
if (BigInt(challengPeriod) !== mgmtContractChallengePeriod) {
throw new Error(`Failed to set the challenge period to: ${challengPeriod}. Returned value is: ${mgmtContractChallengePeriod}`);
}
}

const mgmtContractAddr = process.env.MGMT_CONTRACT_ADDRESS;
const challengePeriod = process.env.L1_CHALLENGE_PERIOD ?
Number(process.env.L1_CHALLENGE_PERIOD) : 0;


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

setChallengePeriod(mgmtContractAddr, challengePeriod)
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

export default setChallengePeriod;
21 changes: 17 additions & 4 deletions contracts/src/management/ManagementContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ contract ManagementContract is Initializable, OwnableUpgradeable {

bytes32 public lastBatchHash;

uint256 private challengePeriod;

function initialize() public initializer {
__Ownable_init(msg.sender);
lastBatchSeqNo = 0;
Expand Down Expand Up @@ -118,7 +120,7 @@ contract ManagementContract is Initializable, OwnableUpgradeable {
require(block.number < (blockNum + 255), "Block binding too old");
require(block.number != blockNum, "Cannot bind to the block that is being currently mined");

bytes32 knownBlockHash = blockhash(blockNum);
bytes32 knownBlockHash = blockhash(blockNum);
require(knownBlockHash != 0x0, "Unknown block hash");
require(knownBlockHash == providedBlockHash, "Block binding mismatch");
require(rollups.toUniqueForkID[rollupNumber] == forkID, "Invalid forkID");
Expand All @@ -131,14 +133,15 @@ contract ManagementContract is Initializable, OwnableUpgradeable {
bytes32 bundleHash = bytes32(0);

for(uint256 i = 0; i < crossChainHashes.length; i++) {
merkleMessageBus.addStateRoot(bytes32(crossChainHashes[i]), block.timestamp); //todo: change the activation time.
merkleMessageBus.addStateRoot(
bytes32(crossChainHashes[i]), block.timestamp + challengePeriod
);
bundleHash = keccak256(abi.encode(bundleHash, bytes32(crossChainHashes[i])));
}

isBundleSaved[bundleHash] = true;
}

// TODO: ensure challenge period is added on top of block timestamp.
function pushCrossChainMessages(Structs.HeaderCrossChainData calldata crossChainData) internal {
uint256 messagesLength = crossChainData.messages.length;
for (uint256 i = 0; i < messagesLength; ++i) {
Expand Down Expand Up @@ -263,4 +266,14 @@ contract ManagementContract is Initializable, OwnableUpgradeable {
function GetImportantContractKeys() public view returns(string[] memory) {
return importantContractKeys;
}
}

// Return the challenge period delay for message bus root
function GetChallengePeriod() public view returns (uint256) {
return challengePeriod;
}

// Sets the challenge period for message bus root (owner only)
function SetChallengePeriod(uint256 _delay) public onlyOwner {
challengePeriod = _delay;
}
}
35 changes: 35 additions & 0 deletions testnet/launcher/l1challengeperiod/cmd/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"flag"
)

// L1ChallengePeriodConfigCLI represents the configurations needed to grant enclaves sequencer roles over CLI
type L1ChallengePeriodConfigCLI struct {
l1HTTPURL string
privateKey string
mgmtContractAddress string
dockerImage string
challengePeriod int
}

// ParseConfigCLI returns a NodeConfigCLI based the cli params and defaults.
func ParseConfigCLI() *L1ChallengePeriodConfigCLI {
cfg := &L1ChallengePeriodConfigCLI{}
flagUsageMap := getFlagUsageMap()

l1HTTPURL := flag.String(l1HTTPURLFlag, "http://eth2network:8025", flagUsageMap[l1HTTPURLFlag])
privateKey := flag.String(privateKeyFlag, "", flagUsageMap[privateKeyFlag])
mgmtContractAddress := flag.String(mgmtContractAddressFlag, "", flagUsageMap[mgmtContractAddressFlag])
dockerImage := flag.String(dockerImageFlag, "testnetobscuronet.azurecr.io/obscuronet/hardhatdeployer:latest", flagUsageMap[dockerImageFlag])
challengePeriod := flag.Int(challengePeriodFlag, 0, flagUsageMap[challengePeriodFlag])
flag.Parse()

cfg.l1HTTPURL = *l1HTTPURL
cfg.privateKey = *privateKey
cfg.mgmtContractAddress = *mgmtContractAddress
cfg.dockerImage = *dockerImage
cfg.challengePeriod = *challengePeriod

return cfg
}
24 changes: 24 additions & 0 deletions testnet/launcher/l1challengeperiod/cmd/cli_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

// Flag names.
const (
l1HTTPURLFlag = "l1_http_url"
privateKeyFlag = "private_key"
mgmtContractAddressFlag = "management_contract_addr"
dockerImageFlag = "docker_image"
contractsEnvFileFlag = "contracts_env_file"
challengePeriodFlag = "l1_challenge_period"
)

// Returns a map of the flag usages.
// While we could just use constants instead of a map, this approach allows us to test that all the expected flags are defined.
func getFlagUsageMap() map[string]string {
return 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",
dockerImageFlag: "Docker image to run",
contractsEnvFileFlag: "If set, it will write the contract addresses to the file",
challengePeriodFlag: "L1 delay when setting message bus root for the challenge period",
}
}
40 changes: 40 additions & 0 deletions testnet/launcher/l1challengeperiod/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package main

import (
"fmt"
"os"

l1cp "github.com/ten-protocol/go-ten/testnet/launcher/l1challengeperiod"
)

func main() {
cliConfig := ParseConfigCLI()

l1challengeperiod, err := l1cp.NewSetChallengePeriod(
l1cp.NewChallengePeriodConfig(
l1cp.WithL1HTTPURL(cliConfig.l1HTTPURL),
l1cp.WithPrivateKey(cliConfig.privateKey),
l1cp.WithDockerImage(cliConfig.dockerImage),
l1cp.WithMgmtContractAddress(cliConfig.mgmtContractAddress),
l1cp.WithChallengePeriod(cliConfig.challengePeriod),
),
)
if err != nil {
fmt.Println("unable to configure l1 contract deployer - %w", err)
os.Exit(1)
}

err = l1challengeperiod.Start()
if err != nil {
fmt.Println("unable to start l1 contract deployer - %w", err)
os.Exit(1)
}

err = l1challengeperiod.WaitForFinish()
if err != nil {
fmt.Println("unexpected error waiting for set challenge period script to finish - %w", err)
os.Exit(1)
}
fmt.Println("L1 challenge period was successfully set...")
os.Exit(0)
}
55 changes: 55 additions & 0 deletions testnet/launcher/l1challengeperiod/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package l1grantsequencers

// Option is a function that applies configs to a Config Object
type Option = func(c *Config)

// Config holds the properties that configure the package
type Config struct {
l1HTTPURL string
privateKey string
mgmtContractAddress string
dockerImage string
challengePeriod int

// debugEnabled bool
}

func NewChallengePeriodConfig(opts ...Option) *Config {
defaultConfig := &Config{}

for _, opt := range opts {
opt(defaultConfig)
}

return defaultConfig
}

func WithL1HTTPURL(s string) Option {
return func(c *Config) {
c.l1HTTPURL = s
}
}

func WithPrivateKey(s string) Option {
return func(c *Config) {
c.privateKey = s
}
}

func WithMgmtContractAddress(s string) Option {
return func(c *Config) {
c.mgmtContractAddress = s
}
}

func WithDockerImage(s string) Option {
return func(c *Config) {
c.dockerImage = s
}
}

func WithChallengePeriod(i int) Option {
return func(c *Config) {
c.challengePeriod = i
}
}
105 changes: 105 additions & 0 deletions testnet/launcher/l1challengeperiod/docker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package l1grantsequencers

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

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

type SetChallengePeriod struct {
cfg *Config
containerID string
}

func NewSetChallengePeriod(cfg *Config) (*SetChallengePeriod, error) {
return &SetChallengePeriod{
cfg: cfg,
}, nil
}

func (s *SetChallengePeriod) Start() error {
var err error
cmds := []string{
"npx",
"hardhat",
"run",
"--network",
"layer1",
"scripts/delay/001_set_challenge_period.ts",
}

envs := map[string]string{
"NETWORK_JSON": fmt.Sprintf(`{
"layer1": {
"url": "%s",
"live": false,
"saveDeployments": true,
"accounts": [ "%s" ]
}
}`, s.cfg.l1HTTPURL, s.cfg.privateKey),
"MGMT_CONTRACT_ADDRESS": s.cfg.mgmtContractAddress,
"L1_CHALLENGE_PERIOD": strconv.Itoa(s.cfg.challengePeriod),
}

containerID, err := docker.StartNewContainer(
"set-challenge-period",
s.cfg.dockerImage,
cmds,
nil,
envs,
nil,
nil,
false,
)
if err != nil {
return err
}
s.containerID = containerID
return nil
}

func (s *SetChallengePeriod) 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 (s *SetChallengePeriod) 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())
}

0 comments on commit 1320a97

Please sign in to comment.