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

Feature/beethoven #44

Closed
wants to merge 7 commits into from
Closed
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
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# CONTAINER FOR BUILDING BINARY
FROM golang:1.21 AS build

# TODO: REMOVE SSH BEFORE MERGING, ONCE AGGLAYER IS PUBLIC

# SSH KEY
ARG SSH_PRIVATE_KEY

Choose a reason for hiding this comment

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

There is another option to do it via git token

Dockerfile:

ENV GOPRIVATE="github.com/0xPolygon/beethoven"
ADD scripts/git-configure.sh .gittoken ./
RUN mkdir -p -m 0600 ~/.ssh && \
  ssh-keyscan github.com >> ~/.ssh/known_hosts && \
  sh ./git-configure.sh

scripts/git-configure.sh

#!/bin/sh

# This script is needed to support using packages from private repos.
# This script applies the given github token if exists, otherwise tells to use ssh instead of https for downloading repos.

export GITHUB_TOKEN=$(cat .gittoken)

if [[ -z "${GITHUB_TOKEN}" ]]; then
    git config --global url.ssh://[email protected]/.insteadOf https://github.com/
else
    git config --global url."https://$GITHUB_TOKEN:[email protected]/".insteadOf "https://github.com/"
fi

.gittoken (ignorred)

<git-token>

Also just FYI

RUN mkdir /root/.ssh/
RUN echo "${SSH_PRIVATE_KEY}" > /root/.ssh/id_rsa
RUN chmod 700 /root/.ssh/id_rsa
RUN echo "Host github.com\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config
RUN git config --global --add url."[email protected]:".insteadOf "https://github.com/"
ENV GOPRIVATE=github.com/0xPolygon/agglayer

# INSTALL DEPENDENCIES
RUN go install github.com/gobuffalo/packr/v2/[email protected]
COPY go.mod go.sum /src/
Expand All @@ -11,6 +22,9 @@ COPY . /src
RUN cd /src/db && packr2
RUN cd /src && make build

# REMOVE SSH PRIVATE KEY
RUN rm /root/.ssh/id_rsa

# CONTAINER FOR RUNNING BINARY
FROM alpine:3.18.0
COPY --from=build /src/dist/zkevm-node /app/zkevm-node
Expand Down
141 changes: 120 additions & 21 deletions aggregator/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import (
"context"
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
Expand All @@ -13,6 +14,9 @@
"time"
"unicode"

"github.com/0xPolygon/agglayer/client"
agglayerTypes "github.com/0xPolygon/agglayer/rpc/types"

Check failure on line 18 in aggregator/aggregator.go

View workflow job for this annotation

GitHub Actions / json-schema (1.21.x, amd64)

github.com/0xPolygon/[email protected]: invalid version: git ls-remote -q origin in /home/runner/go/pkg/mod/cache/vcs/7c387218d32c30b42d7f16ea9c6d5515d4d876b117f4d008fd68123e67afa92f: exit status 128:
"github.com/0xPolygon/agglayer/tx"

Check failure on line 19 in aggregator/aggregator.go

View workflow job for this annotation

GitHub Actions / json-schema (1.21.x, amd64)

github.com/0xPolygon/[email protected]: invalid version: git ls-remote -q origin in /home/runner/go/pkg/mod/cache/vcs/7c387218d32c30b42d7f16ea9c6d5515d4d876b117f4d008fd68123e67afa92f: exit status 128:
"github.com/0xPolygonHermez/zkevm-node/aggregator/metrics"
"github.com/0xPolygonHermez/zkevm-node/aggregator/prover"
"github.com/0xPolygonHermez/zkevm-node/config/types"
Expand All @@ -22,6 +26,7 @@
"github.com/0xPolygonHermez/zkevm-node/log"
"github.com/0xPolygonHermez/zkevm-node/state"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/jackc/pgx/v4"
"google.golang.org/grpc"
grpchealth "google.golang.org/grpc/health/grpc_health_v1"
Expand Down Expand Up @@ -64,6 +69,9 @@
srv *grpc.Server
ctx context.Context
exit context.CancelFunc

sequencerPrivateKey *ecdsa.PrivateKey
agglayerClient client.ClientInterface
}

// New creates a new aggregator.
Expand All @@ -72,6 +80,8 @@
stateInterface stateInterface,
ethTxManager ethTxManager,
etherman etherman,
agglayerClient client.ClientInterface,
sequencerPrivateKey *ecdsa.PrivateKey,
) (Aggregator, error) {
var profitabilityChecker aggregatorTxProfitabilityChecker
switch cfg.TxProfitabilityCheckerType {
Expand All @@ -81,6 +91,23 @@
profitabilityChecker = NewTxProfitabilityCheckerAcceptAll(stateInterface, cfg.IntervalAfterWhichBatchConsolidateAnyway.Duration)
}

if cfg.SettlementBackend == agglayer {
if sequencerPrivateKey == nil {
return Aggregator{}, fmt.Errorf("the private key of the sequencer needs to be provided")
}
sequencerAddr, err := etherman.GetSequencerAddr()
if err != nil {
return Aggregator{}, err
}
actualAddr := crypto.PubkeyToAddress(sequencerPrivateKey.PublicKey)
if sequencerAddr != actualAddr {
return Aggregator{}, fmt.Errorf(
"the private key of the sequencer needs to be provided. Provided private key is for addr %s but sequencer addr is %s",
actualAddr.Hex(), sequencerAddr.Hex(),
)
}
}

a := Aggregator{
cfg: cfg,

Expand All @@ -92,7 +119,9 @@
TimeSendFinalProofMutex: &sync.RWMutex{},
TimeCleanupLockedProofs: cfg.CleanupLockedProofsInterval,

finalProof: make(chan finalProofMsg),
finalProof: make(chan finalProofMsg),
agglayerClient: agglayerClient,
sequencerPrivateKey: sequencerPrivateKey,
}

return a, nil
Expand Down Expand Up @@ -266,27 +295,22 @@

log.Infof("Final proof inputs: NewLocalExitRoot [%#x], NewStateRoot [%#x]", inputs.NewLocalExitRoot, inputs.NewStateRoot)

// add batch verification to be monitored
sender := common.HexToAddress(a.cfg.SenderAddress)
to, data, err := a.Ethman.BuildTrustedVerifyBatchesTxData(proof.BatchNumber-1, proof.BatchNumberFinal, &inputs)
if err != nil {
log.Errorf("Error estimating batch verification to add to eth tx manager: %v", err)
a.handleFailureToAddVerifyBatchToBeMonitored(ctx, proof)
continue
}
monitoredTxID := buildMonitoredTxID(proof.BatchNumber, proof.BatchNumberFinal)
err = a.EthTxManager.Add(ctx, ethTxManagerOwner, monitoredTxID, sender, to, nil, data, a.cfg.GasOffset, nil)
if err != nil {
mTxLogger := ethtxmanager.CreateLogger(ethTxManagerOwner, monitoredTxID, sender, to)
mTxLogger.Errorf("Error to add batch verification tx to eth tx manager: %v", err)
a.handleFailureToAddVerifyBatchToBeMonitored(ctx, proof)
continue
}
log.Infof("Final proof inputs: NewLocalExitRoot [%#x], NewStateRoot [%#x]", inputs.NewLocalExitRoot, inputs.NewStateRoot)

// process monitored batch verifications before starting a next cycle
a.EthTxManager.ProcessPendingMonitoredTxs(ctx, ethTxManagerOwner, func(result ethtxmanager.MonitoredTxResult, dbTx pgx.Tx) {
a.handleMonitoredTxResult(result)
}, nil)
switch a.cfg.SettlementBackend {
case L1:
if success := a.settleProofToL1(ctx, proof, inputs); !success {
continue
}
case agglayer:
if success := a.settleProofToagglayer(ctx, proof, inputs); !success {
continue
}
default:
if success := a.settleProofToL1(ctx, proof, inputs); !success {
continue
}
}

a.resetVerifyProofTime()
a.endProofVerification()
Expand Down Expand Up @@ -1094,3 +1118,78 @@
runes[0] = unicode.ToUpper(runes[0])
return string(runes)
}

func (a *Aggregator) settleProofToL1(ctx context.Context, proof *state.Proof, inputs ethmanTypes.FinalProofInputs) (success bool) {
// add batch verification to be monitored
sender := common.HexToAddress(a.cfg.SenderAddress)
to, data, err := a.Ethman.BuildTrustedVerifyBatchesTxData(proof.BatchNumber-1, proof.BatchNumberFinal, &inputs)
if err != nil {
log.Errorf("Error estimating batch verification to add to eth tx manager: %v", err)
a.handleFailureToAddVerifyBatchToBeMonitored(ctx, proof)
return false
}
monitoredTxID := buildMonitoredTxID(proof.BatchNumber, proof.BatchNumberFinal)
err = a.EthTxManager.Add(ctx, ethTxManagerOwner, monitoredTxID, sender, to, nil, data, a.cfg.GasOffset, nil)
if err != nil {
log := log.WithFields("tx", monitoredTxID)
log.Errorf("Error to add batch verification tx to eth tx manager: %v", err)
a.handleFailureToAddVerifyBatchToBeMonitored(ctx, proof)
return false
}

// process monitored batch verifications before starting a next cycle
a.EthTxManager.ProcessPendingMonitoredTxs(ctx, ethTxManagerOwner, func(result ethtxmanager.MonitoredTxResult, dbTx pgx.Tx) {
a.handleMonitoredTxResult(result)
}, nil)
return true
}

func (a *Aggregator) settleProofToagglayer(ctx context.Context, proof *state.Proof, inputs ethmanTypes.FinalProofInputs) (success bool) {
l1Contract := a.Ethman.GetL1ContractAddress()
proofStrNo0x := strings.TrimPrefix(inputs.FinalProof.Proof, "0x")
proofBytes := common.Hex2Bytes(proofStrNo0x)
tx := tx.Tx{
L1Contract: l1Contract,
LastVerifiedBatch: agglayerTypes.ArgUint64(proof.BatchNumber - 1),
NewVerifiedBatch: agglayerTypes.ArgUint64(proof.BatchNumberFinal),
ZKP: tx.ZKP{
NewStateRoot: common.BytesToHash(inputs.NewStateRoot),
NewLocalExitRoot: common.BytesToHash(inputs.NewLocalExitRoot),
Proof: agglayerTypes.ArgBytes(proofBytes),
},
}
signedTx, err := tx.Sign(a.sequencerPrivateKey)
if err != nil {
log.Errorf("failed to sign tx: %v", err)
a.handleFailureToSendToagglayer(ctx, proof)
return false
}
log.Debug("final proof signedTx: ", signedTx.Tx.ZKP.Proof.Hex())
txHash, err := a.agglayerClient.SendTx(*signedTx)
if err != nil {
log.Errorf("failed to send tx to the interop: %v", err)
a.handleFailureToSendToagglayer(ctx, proof)
return false
}
log.Infof("tx %s sent to agglayer, waiting to be mined", txHash.Hex())
log.Debugf("Timeout set to %f seconds", a.cfg.agglayerTxTimeout.Duration.Seconds())
waitCtx, cancelFunc := context.WithDeadline(ctx, time.Now().Add(a.cfg.agglayerTxTimeout.Duration))
defer cancelFunc()
if err := a.agglayerClient.WaitTxToBeMined(txHash, waitCtx); err != nil {
log.Errorf("interop didn't mine the tx: %v", err)
a.handleFailureToSendToagglayer(ctx, proof)
return false
}
// TODO: wait for synchronizer to catch up
return true
}

func (a *Aggregator) handleFailureToSendToagglayer(ctx context.Context, proof *state.Proof) {
log := log.WithFields("proofId", proof.ProofID, "batches", fmt.Sprintf("%d-%d", proof.BatchNumber, proof.BatchNumberFinal))
proof.GeneratingSince = nil
err := a.State.UpdateGeneratedProof(ctx, proof, nil)
if err != nil {
log.Errorf("Failed updating proof state (false): %v", err)
}
a.endProofVerification()
}
10 changes: 5 additions & 5 deletions aggregator/aggregator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func TestSendFinalProof(t *testing.T) {
stateMock := mocks.NewStateMock(t)
ethTxManager := mocks.NewEthTxManager(t)
etherman := mocks.NewEtherman(t)
a, err := New(cfg, stateMock, ethTxManager, etherman)
a, err := New(cfg, stateMock, ethTxManager, etherman, nil, nil)
require.NoError(err)
a.ctx, a.exit = context.WithCancel(context.Background())
m := mox{
Expand Down Expand Up @@ -685,7 +685,7 @@ func TestTryAggregateProofs(t *testing.T) {
ethTxManager := mocks.NewEthTxManager(t)
etherman := mocks.NewEtherman(t)
proverMock := mocks.NewProverMock(t)
a, err := New(cfg, stateMock, ethTxManager, etherman)
a, err := New(cfg, stateMock, ethTxManager, etherman, nil, nil)
require.NoError(err)
aggregatorCtx := context.WithValue(context.Background(), "owner", "aggregator") //nolint:staticcheck
a.ctx, a.exit = context.WithCancel(aggregatorCtx)
Expand Down Expand Up @@ -958,7 +958,7 @@ func TestTryGenerateBatchProof(t *testing.T) {
ethTxManager := mocks.NewEthTxManager(t)
etherman := mocks.NewEtherman(t)
proverMock := mocks.NewProverMock(t)
a, err := New(cfg, stateMock, ethTxManager, etherman)
a, err := New(cfg, stateMock, ethTxManager, etherman, nil, nil)
require.NoError(err)
aggregatorCtx := context.WithValue(context.Background(), "owner", "aggregator") //nolint:staticcheck
a.ctx, a.exit = context.WithCancel(aggregatorCtx)
Expand Down Expand Up @@ -1235,7 +1235,7 @@ func TestTryBuildFinalProof(t *testing.T) {
ethTxManager := mocks.NewEthTxManager(t)
etherman := mocks.NewEtherman(t)
proverMock := mocks.NewProverMock(t)
a, err := New(cfg, stateMock, ethTxManager, etherman)
a, err := New(cfg, stateMock, ethTxManager, etherman, nil, nil)
require.NoError(err)
aggregatorCtx := context.WithValue(context.Background(), "owner", "aggregator") //nolint:staticcheck
a.ctx, a.exit = context.WithCancel(aggregatorCtx)
Expand Down Expand Up @@ -1365,7 +1365,7 @@ func TestIsSynced(t *testing.T) {
ethTxManager := mocks.NewEthTxManager(t)
etherman := mocks.NewEtherman(t)
proverMock := mocks.NewProverMock(t)
a, err := New(cfg, stateMock, ethTxManager, etherman)
a, err := New(cfg, stateMock, ethTxManager, etherman, nil, nil)
require.NoError(err)
aggregatorCtx := context.WithValue(context.Background(), "owner", "aggregator") //nolint:staticcheck
a.ctx, a.exit = context.WithCancel(aggregatorCtx)
Expand Down
22 changes: 22 additions & 0 deletions aggregator/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ func (t *TokenAmountWithDecimals) UnmarshalText(data []byte) error {
return nil
}

// SettlementBackend different supported backends where ZKPs are sent
type SettlementBackend string

const (
// agglayer specifies to send ZKPs to agglayer service
agglayer SettlementBackend = "agglayer"
// L1 specifies to send ZKPs to L1 chain
L1 SettlementBackend = "l1"
)

// Config represents the configuration of the aggregator
type Config struct {
// Host for the grpc server
Expand Down Expand Up @@ -85,4 +95,16 @@ type Config struct {
// gas offset: 100
// final gas: 1100
GasOffset uint64 `mapstructure:"GasOffset"`

// SettlementBackend indicates where ZKPs are settled. It can be "l1" or "agglayer"
SettlementBackend SettlementBackend `mapstructure:"SettlementBackend"`

// agglayerTxTimeout is the interval time to wait for a tx to be mined from the agglayer
agglayerTxTimeout types.Duration `mapstructure:"agglayerTxTimeout"`

// agglayerURL url of the agglayer service
agglayerURL string `mapstructure:"agglayerURL"`

// SequencerPrivateKey of the sequencer, used to authorize txs sent to the agglayer
SequencerPrivateKey types.KeystoreFileConfig `mapstructure:"SequencerPrivateKey"`
}
2 changes: 2 additions & 0 deletions aggregator/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ type ethTxManager interface {
type etherman interface {
GetLatestVerifiedBatchNum() (uint64, error)
BuildTrustedVerifyBatchesTxData(lastVerifiedBatch, newVerifiedBatch uint64, inputs *ethmanTypes.FinalProofInputs) (to *common.Address, data []byte, err error)
GetSequencerAddr() (common.Address, error)
GetL1ContractAddress() common.Address
}

// aggregatorTxProfitabilityChecker interface for different profitability
Expand Down
42 changes: 42 additions & 0 deletions aggregator/mocks/mock_etherman.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading