diff --git a/bridge/standard/cmd/relayer/main.go b/bridge/standard/cmd/relayer/main.go index 4f2748fd2..2cfa78df3 100644 --- a/bridge/standard/cmd/relayer/main.go +++ b/bridge/standard/cmd/relayer/main.go @@ -112,6 +112,41 @@ var ( EnvVars: []string{"STANDARD_BRIDGE_RELAYER_SETTLEMENT_CONTRACT_ADDR"}, Required: true, }) + + optionPgHost = altsrc.NewStringFlag(&cli.StringFlag{ + Name: "pg-host", + Usage: "PostgreSQL host", + EnvVars: []string{"STANDARD_BRIDGE_RELAYER_PG_HOST"}, + Value: "localhost", + }) + + optionPgPort = altsrc.NewIntFlag(&cli.IntFlag{ + Name: "pg-port", + Usage: "PostgreSQL port", + EnvVars: []string{"STANDARD_BRIDGE_RELAYER_PG_PORT"}, + Value: 5432, + }) + + optionPgUser = altsrc.NewStringFlag(&cli.StringFlag{ + Name: "pg-user", + Usage: "PostgreSQL user", + EnvVars: []string{"STANDARD_BRIDGE_RELAYER_PG_USER"}, + Value: "postgres", + }) + + optionPgPassword = altsrc.NewStringFlag(&cli.StringFlag{ + Name: "pg-password", + Usage: "PostgreSQL password", + EnvVars: []string{"STANDARD_BRIDGE_RELAYER_PG_PASSWORD"}, + Value: "postgres", + }) + + optionPgDbname = altsrc.NewStringFlag(&cli.StringFlag{ + Name: "pg-dbname", + Usage: "PostgreSQL database name", + EnvVars: []string{"STANDARD_BRIDGE_RELAYER_PG_DBNAME"}, + Value: "mev_commit_bridge", + }) ) func main() { @@ -127,6 +162,11 @@ func main() { optionSettlementRPCUrl, optionL1ContractAddr, optionSettlementContractAddr, + optionPgHost, + optionPgPort, + optionPgUser, + optionPgPassword, + optionPgDbname, } app := &cli.App{ @@ -183,6 +223,11 @@ func start(c *cli.Context) error { L1GatewayContractAddr: common.HexToAddress(c.String(optionL1ContractAddr.Name)), SettlementRPCURL: c.String(optionSettlementRPCUrl.Name), SettlementContractAddr: common.HexToAddress(c.String(optionSettlementContractAddr.Name)), + PgHost: c.String(optionPgHost.Name), + PgPort: c.Int(optionPgPort.Name), + PgUser: c.String(optionPgUser.Name), + PgPassword: c.String(optionPgPassword.Name), + PgDB: c.String(optionPgDbname.Name), }) if err != nil { return fmt.Errorf("failed to create node: %w", err) diff --git a/bridge/standard/pkg/node/node.go b/bridge/standard/pkg/node/node.go index 55680a638..769445083 100644 --- a/bridge/standard/pkg/node/node.go +++ b/bridge/standard/pkg/node/node.go @@ -37,6 +37,11 @@ type Options struct { L1GatewayContractAddr common.Address SettlementRPCURL string SettlementContractAddr common.Address + PgHost string + PgPort int + PgUser string + PgPassword string + PgDB string } type StartableObjWithDesc struct { @@ -67,15 +72,20 @@ func NewNode(opts *Options) (*Node, error) { metrics: prometheus.NewRegistry(), } + db, err := initDB(opts) + if err != nil { + return nil, fmt.Errorf("failed to init DB: %w", err) + } + ctx, cancel := context.WithCancel(context.Background()) - err := n.createGatewayContract( + err = n.createGatewayContract( ctx, "l1", opts.Logger, opts.L1RPCURL, opts.Signer, opts.L1GatewayContractAddr, - nil, + db, ) if err != nil { cancel() @@ -89,7 +99,7 @@ func NewNode(opts *Options) (*Node, error) { opts.SettlementRPCURL, opts.Signer, opts.SettlementContractAddr, - nil, + db, ) if err != nil { cancel() @@ -136,6 +146,7 @@ func NewNode(opts *Options) (*Node, error) { n.closeFn = func() error { cancel() + _ = db.Close() closeCtx, closeCancel := context.WithTimeout(context.Background(), 5*time.Second) defer closeCancel() @@ -316,3 +327,29 @@ func (n *Node) createGatewayContract( return nil } + +func initDB(opts *Options) (db *sql.DB, err error) { + // Connection string + psqlInfo := fmt.Sprintf( + "host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", + opts.PgHost, opts.PgPort, opts.PgUser, opts.PgPassword, opts.PgDB, + ) + + // Open a connection + db, err = sql.Open("postgres", psqlInfo) + if err != nil { + return nil, err + } + + // Check the connection + err = db.Ping() + if err != nil { + return nil, err + } + + db.SetMaxOpenConns(50) + db.SetMaxIdleConns(25) + db.SetConnMaxLifetime(1 * time.Hour) + + return db, err +} diff --git a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-bridge.nomad.j2 b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-bridge.nomad.j2 index 0ce05afd7..f778bd078 100644 --- a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-bridge.nomad.j2 +++ b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-bridge.nomad.j2 @@ -36,6 +36,101 @@ job "{{ job.name }}" { {% endfor %} } + task "db" { + driver = "exec" + + lifecycle { + hook = "prestart" + sidecar = true + } + + {% if profile == 'testnet' %} + resources { + cores = 4 + memory = 8192 + } + {% elif profile == 'stressnet' %} + resources { + memory = 4096 + } + {% endif %} + + template { + data = <<-EOH + POSTGRES_VERSION="15" + POSTGRES_DB="mev_commit_bridge" + POSTGRES_USERNAME="mev_commit_bridge" + POSTGRES_PASSWORD="{{ lookup('password', '/dev/null', length=64) }}" + POSTGRES_DATA="/local/pgdata-{% raw %}{{ env "NOMAD_ALLOC_INDEX" }}{% endraw %}" + EOH + destination = "alloc/data/postgres.env" + env = true + } + + template { + data = <<-EOH + #!/usr/bin/env bash + + {% raw %} + {{- range nomadService "datadog-agent-logs-collector" }} + {{ if contains "tcp" .Tags }} + exec > >(nc {{ .Address }} {{ .Port }}) 2>&1 + {{ end }} + {{- end }} + + if [ -d "${POSTGRES_DATA}" ]; then + echo "Initialized and configured database found." + cp "${POSTGRES_DATA}/.env" /alloc/data/postgres.env + source "${POSTGRES_DATA}/.env" + postgres -D ${POSTGRES_DATA} + exit $? + fi + + export PATH="/usr/lib/postgresql/${POSTGRES_VERSION}/bin:${PATH}" + mkdir -p /var/run/postgresql > /dev/null 2>&1 + pg_ctl initdb --silent --pgdata="${POSTGRES_DATA}" + if [ $? -ne 0 ]; then + echo "Failed to initialize PostgreSQL." + exit 1 + fi + cp /alloc/data/postgres.env "${POSTGRES_DATA}/.env" + + pg_ctl start --pgdata="${POSTGRES_DATA}" --silent --wait --timeout=300 > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Failed to start PostgreSQL." + exit 1 + fi + + createuser --superuser postgres > /dev/null 2>&1 + createuser --username=postgres --createdb "${POSTGRES_USERNAME}" + createdb --username="${POSTGRES_USERNAME}" "${POSTGRES_DB}" + psql --quiet \ + --username="${POSTGRES_USERNAME}" \ + --dbname="${POSTGRES_DB}" \ + --command="ALTER USER ${POSTGRES_USERNAME} WITH PASSWORD '${POSTGRES_PASSWORD}'; \ + GRANT ALL PRIVILEGES ON DATABASE ${POSTGRES_DB} TO ${POSTGRES_USERNAME};" + echo "Database initialized and configured successfully." + + pg_ctl stop --pgdata="${POSTGRES_DATA}" --silent --wait --timeout=300 > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Failed to stop PostgreSQL." + exit 1 + fi + + exec postgres -D "${POSTGRES_DATA}" + {% endraw %} + EOH + destination = "local/run.sh" + change_mode = "noop" + perms = "0755" + } + + config { + command = "bash" + args = ["-c", "exec local/run.sh"] + } + } + task "relayer" { driver = "exec" @@ -96,6 +191,12 @@ job "{{ job.name }}" { STANDARD_BRIDGE_RELAYER_SETTLEMENT_RPC_URL="http://{{ .Address }}:{{ .Port }}" {{- end }} {{- end }} + {{- range nomadService "{% endraw %}{{ job.name }}{% raw %}" }} + {{- if contains "db" .Tags }} + STANDARD_BRIDGE_RELAYER_PG_HOST="localhost" + STANDARD_BRIDGE_RELAYER_PG_PORT="{{ .Port }}" + {{- end }} + {{- end }} {% endraw %} STANDARD_BRIDGE_RELAYER_L1_RPC_URL="{{ job.env['l1_rpc_url'] }}" STANDARD_BRIDGE_RELAYER_PRIV_KEY_FILE="secrets/relayer_key" @@ -140,6 +241,16 @@ job "{{ job.name }}" { {{- end }} {% endraw %} + source alloc/data/postgres.env + export STANDARD_BRIDGE_RELAYER_PG_USER="${POSTGRES_USERNAME}" + export STANDARD_BRIDGE_RELAYER_PG_PASSWORD="${POSTGRES_PASSWORD}" + export STANDARD_BRIDGE_RELAYER_PG_DBNAME="${POSTGRES_DB}" + + if ! timeout 5m bash -c 'until pg_isready -h ${STANDARD_BRIDGE_RELAYER_PG_HOST} -p ${STANDARD_BRIDGE_RELAYER_PG_PORT} -U ${STANDARD_BRIDGE_RELAYER_PG_USER} -d ${STANDARD_BRIDGE_RELAYER_PG_DBNAME}; do sleep 2; done'; then + echo "Waiting for PostgreSQL to start..." + sleep 3 + fi + chmod +x local/relayer exec ./local/relayer start EOH