Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2b1c0df
runbook v1
arnaubennassar Feb 26, 2026
06084aa
add plan
arnaubennassar Feb 26, 2026
f40b94c
typo
arnaubennassar Feb 26, 2026
b5b6908
plan implemented
arnaubennassar Feb 26, 2026
68b2ccf
case 1 passing
arnaubennassar Mar 2, 2026
9e2d799
add vscode debugger in docker op-pp
arnaubennassar Mar 2, 2026
c2136f0
aggsender use same derivation logic than validator for FromBlock of t…
arnaubennassar Mar 2, 2026
d660598
TestBackwardForwardLET_Case2 passing
arnaubennassar Mar 3, 2026
ef720dd
all tests pass individually
arnaubennassar Mar 3, 2026
1d72c49
tests passing when running together
arnaubennassar Mar 4, 2026
2b53bb8
parallelize l1 -> l2 and l2 -> l1 post test bridges to speed up tests
arnaubennassar Mar 4, 2026
ee6ff39
fix test speedup
arnaubennassar Mar 5, 2026
48c1448
fix linter
arnaubennassar Mar 5, 2026
1cedc0d
update aggsender docs
arnaubennassar Mar 5, 2026
b359f1b
lint
arnaubennassar Mar 5, 2026
2dd1ec1
Merge branch 'develop' into feat/back-and-for-let
arnaubennassar Mar 5, 2026
91555b3
fix uts
arnaubennassar Mar 5, 2026
e74f9a2
Merge branch 'develop' into feat/back-and-for-let
arnaubennassar Mar 6, 2026
6f4563c
fix uts
arnaubennassar Mar 6, 2026
8b6ada8
fix: resolve golangci-lint failures on CI
arnaubennassar Mar 6, 2026
53efa0c
fix vulnerabilities related to docker debug
arnaubennassar Mar 6, 2026
10edbee
imporvements from code review
arnaubennassar Mar 6, 2026
3eb00ba
fix linter
arnaubennassar Mar 6, 2026
9e55897
remove unused files
arnaubennassar Mar 6, 2026
69e834a
Merge branch 'develop' into feat/back-and-for-let
arnaubennassar Mar 6, 2026
4966607
inprovements from code review
arnaubennassar Mar 9, 2026
9cbe915
inprovements from code review
arnaubennassar Mar 9, 2026
083783c
linter
arnaubennassar Mar 9, 2026
5def0d0
wip
arnaubennassar Mar 9, 2026
d162344
remove debugSendCert
arnaubennassar Mar 10, 2026
501aa3a
remove .vscode/launch.json from tracking
arnaubennassar Mar 10, 2026
d6ea909
move unmarshal logic to aggsender/rpc
arnaubennassar Mar 10, 2026
f498b04
refactor GetLastLocalExitRoot --> GetInitialLocalExitRoot
arnaubennassar Mar 10, 2026
a673437
use initial LER insteaad of empty LER at bridgesync processor
arnaubennassar Mar 10, 2026
8e152fe
add timeour for db on bridgesync/processor again
arnaubennassar Mar 10, 2026
2c67c78
lint
arnaubennassar Mar 10, 2026
86a1e2f
fix file permissions
arnaubennassar Mar 10, 2026
f0644e8
fix: run aggkit container as host user to allow DB writes from test p…
arnaubennassar Mar 10, 2026
8bf9bdf
Only call GetInitialLER once
arnaubennassar Mar 11, 2026
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
32 changes: 32 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Version control
.git/
.gitignore

# Sensitive / secret files
.env
.env.*
*.pem
*.key
*.p12
*.pfx
*.crt
*.cer

# Editor and OS artifacts
.idea/
.vscode/
*.swp
*.swo
.DS_Store

# Build artifacts (not needed β€” built inside the container)
/out/

# Test fixtures and E2E env (may contain keys/configs)
test/e2e/envs/

# Temporary E2E test data (aggkit bind-mount data, may be owned by container UID)
tmp/

# Local developer configs
*.local
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ build/*
data
*.sqlite-shm
*.sqlite-wal
**aggkit-001-data**
.vscode
47 changes: 47 additions & 0 deletions Dockerfile.debug
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# ================================
# STAGE 1: Build debug binary + dlv
# ================================
FROM golang:1.25.7-alpine AS builder

RUN apk add --no-cache gcc musl-dev make sqlite-dev git

Check warning on line 6 in Dockerfile.debug

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Sort these package names alphanumerically.

See more on https://sonarcloud.io/project/issues?id=agglayer_aggkit&issues=AZyvTIj0YQHP3U53wvEV&open=AZyvTIj0YQHP3U53wvEV&pullRequest=1502

WORKDIR /home/aigent/repos/aggkit

COPY go.mod go.sum ./
RUN go mod download

COPY . .

# Install delve
RUN go install github.com/go-delve/delve/cmd/dlv@latest

# Build debug binary (disable inlining and optimizations for proper debugging)
RUN CGO_ENABLED=1 go build \
-gcflags="all=-N -l" \
-o /out/aggkit \
./cmd

# ================================
# STAGE 2: Debug runtime image
# ================================
FROM alpine:3.22

RUN apk add --no-cache sqlite-libs ca-certificates \
&& addgroup -S appgroup \
&& adduser -S appuser -G appgroup

COPY --from=builder /go/bin/dlv /usr/local/bin/dlv
COPY --from=builder /out/aggkit /usr/local/bin/aggkit

# Run as non-root. Note: the container must be started with
# --cap-add=SYS_PTRACE so that delve can trace the target process.
USER appuser

EXPOSE 5576/tcp
EXPOSE 40000/tcp

# Default: run aggkit under delve headless. App args are provided by
# the compose file's `command:` block (appended after the `--` separator).
CMD ["dlv", "exec", "/usr/local/bin/aggkit", \
"--headless", "--listen=:40000", "--api-version=2", \
"--accept-multiclient", "--log"]
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ build-docker-ci: ## Builds a docker image with the aggkit binary for CI (include
build-docker-nc: ## Builds a docker image with the aggkit binary - but without build cache
docker build --no-cache=true -t aggkit:local -f ./Dockerfile .

.PHONY: build-docker-debug
build-docker-debug: ## Builds a debug docker image (dlv headless on :40000, no optimizations)
docker build -t aggkit:local-debug -f ./Dockerfile.debug .

.PHONY: test-unit
test-unit: ## Runs the unit tests
trap '$(STOP)' EXIT; MallocNanoZone=0 go test -count=1 -short -race -p 1 -covermode=atomic -coverprofile=coverage.out -timeout 15m ./...
Expand Down
8 changes: 7 additions & 1 deletion agglayer/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,13 @@ func (b *BridgeExit) UnmarshalJSON(data []byte) error {
b.DestinationAddress = aux.DestinationAddress
var ok bool
if !strings.Contains(aux.Amount, nilStr) {
b.Amount, ok = new(big.Int).SetString(aux.Amount, base10)
base := base10
amountStr := aux.Amount
if strings.HasPrefix(amountStr, "0x") || strings.HasPrefix(amountStr, "0X") {
base = 16
amountStr = amountStr[2:]
}
b.Amount, ok = new(big.Int).SetString(amountStr, base)
if !ok {
return fmt.Errorf("failed to convert amount to big.Int: %s", aux.Amount)
}
Expand Down
47 changes: 47 additions & 0 deletions agglayer/types/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1897,3 +1897,50 @@ func createTreeDBForTest(t *testing.T) *sql.DB {
require.NoError(t, err)
return treeDB
}

// TestBridgeExit_UnmarshalJSON_HexAmount verifies that BridgeExit correctly deserializes
// amounts with a "0x"-prefixed hex string (added in this branch).
func TestBridgeExit_UnmarshalJSON_HexAmount(t *testing.T) {
t.Parallel()

tests := []struct {
name string
amountJSON string
expectedAmount *big.Int
}{
{
name: "decimal amount",
amountJSON: `"1000"`,
expectedAmount: big.NewInt(1000),
},
{
name: "0x-prefixed hex amount",
amountJSON: `"0x3e8"`,
expectedAmount: big.NewInt(1000),
},
{
name: "0X-prefixed hex amount (uppercase)",
amountJSON: `"0X3E8"`,
expectedAmount: big.NewInt(1000),
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

jsonData := fmt.Sprintf(`{
"leaf_type": "Transfer",
"token_info": {"origin_network": 1, "origin_token_address": "0x0000000000000000000000000000000000000001"},
"dest_network": 2,
"dest_address": "0x0000000000000000000000000000000000000002",
"amount": %s,
"metadata": null
}`, tc.amountJSON)

var be BridgeExit
require.NoError(t, json.Unmarshal([]byte(jsonData), &be))
require.Equal(t, tc.expectedAmount, be.Amount)
})
}
}
32 changes: 19 additions & 13 deletions aggsender/aggsender.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func New(
l2Client aggkittypes.BaseEthereumClienter,
rollupDataQuerier types.RollupDataQuerier,
committeeQuerier types.MultisigQuerier,
initialLER common.Hash,
) (*AggSender, error) {
mode, err := committeeQuerier.ResolveAutoMode(cfg.Mode)
if err != nil {
Expand Down Expand Up @@ -106,6 +107,7 @@ func New(
rollupDataQuerier,
committeeQuerier,
certificateSendTrigger,
initialLER,
)
}

Expand All @@ -122,6 +124,7 @@ func newAggsender(
rollupDataQuerier types.RollupDataQuerier,
committeeQuerier types.MultisigQuerier,
certificateSendTrigger types.CertificateSendTrigger,
initialLER common.Hash,
) (*AggSender, error) {
storageConfig := db.AggSenderSQLStorageConfig{
DBPath: cfg.StoragePath,
Expand All @@ -133,6 +136,19 @@ func newAggsender(
return nil, err
}

aggchainFEPCaller, err := query.NewAggchainFEPQuerier(logger, cfg.Mode,
cfg.SovereignRollupAddr, l1Client)
if err != nil {
return nil, fmt.Errorf("error creating aggchain FEP caller: %w", err)
}

certQuerier := query.NewCertificateQuerier(
l2Syncer,
aggchainFEPCaller,
aggLayerClient,
initialLER,
)

flowManager, err := flows.NewBuilderFlow(
ctx,
cfg,
Expand All @@ -144,6 +160,8 @@ func newAggsender(
l2Syncer,
rollupDataQuerier,
committeeQuerier,
certQuerier,
initialLER,
)
if err != nil {
return nil, fmt.Errorf("error creating flow manager: %w", err)
Expand All @@ -161,18 +179,6 @@ func newAggsender(
compatibility.NewKeyValueToCompatibilityStorage[db.RuntimeData](storage, aggkitcommon.AGGSENDER),
)

aggchainFEPCaller, err := query.NewAggchainFEPQuerier(logger, cfg.Mode,
cfg.SovereignRollupAddr, l1Client)
if err != nil {
return nil, fmt.Errorf("error creating aggchain FEP caller: %w", err)
}

certQuerier := query.NewCertificateQuerier(
l2Syncer,
aggchainFEPCaller,
aggLayerClient,
)

verifierFlow, err := flows.NewLocalVerifier(
ctx,
cfg,
Expand All @@ -197,7 +203,7 @@ func newAggsender(
verifierFlow,
l1InfoTreeQuerier,
certQuerier,
query.NewLERDataQuerier(cfg.RollupCreationBlockL1, rollupDataQuerier),
initialLER,
),
)

Expand Down
8 changes: 4 additions & 4 deletions aggsender/aggsender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func TestAggSenderStart(t *testing.T) {
rollupQuerierMock,
committeQuerierMock,
sendTrigger,
bridgetypes.EmptyLER,
)
require.NoError(t, err)
require.NotNil(t, aggSender)
Expand Down Expand Up @@ -232,7 +233,6 @@ func TestSendCertificate_NoClaims(t *testing.T) {
mockL1Querier := mocks.NewL1InfoTreeDataQuerier(t)
mockAggLayerClient := agglayermocks.NewAgglayerClientMock(t)
mockSendTrigger := mocks.NewCertificateSendTrigger(t)
mockLERQuerier := mocks.NewLERQuerier(t)
logger := log.WithFields("aggsender-test", "no claims test")
signer := signer.NewLocalSignFromPrivateKey("ut", log.WithFields("aggsender", 1), privateKey, 0)
mockLocalValidator := mocks.NewCertificateValidateAndSigner(t)
Expand All @@ -250,7 +250,7 @@ func TestSendCertificate_NoClaims(t *testing.T) {
localValidator: mockLocalValidator,
flow: flows.NewPPBuilderFlow(logger,
flows.NewBaseFlow(logger, mockL2BridgeQuerier, mockStorage,
mockL1Querier, mockLERQuerier, flows.NewBaseFlowConfigDefault()),
mockL1Querier, bridgetypes.EmptyLER, nil, flows.NewBaseFlowConfigDefault()),
mockStorage, mockL1Querier, mockL2BridgeQuerier, signer, true, 0),
}

Expand Down Expand Up @@ -559,6 +559,7 @@ func TestNewAggSender(t *testing.T) {
nil, // l2 client
mockRollupQuerier,
mockCommitteeQuerier,
bridgetypes.EmptyLER,
)
require.NoError(t, err)
require.NotNil(t, sut)
Expand Down Expand Up @@ -827,7 +828,6 @@ func newAggsenderTestData(t *testing.T, creationFlags testDataFlags) *aggsenderT
l2BridgeQuerier := mocks.NewBridgeQuerier(t)
agglayerClientMock := agglayermocks.NewAgglayerClientMock(t)
l1InfoTreeQuerierMock := mocks.NewL1InfoTreeDataQuerier(t)
lerQuerier := mocks.NewLERQuerier(t)
logger := log.WithFields("aggsender-test", "checkLastCertificateFromAgglayer")
var storageMock *mocks.AggSenderStorage
var storage db.AggSenderStorage
Expand Down Expand Up @@ -862,7 +862,7 @@ func newAggsenderTestData(t *testing.T, creationFlags testDataFlags) *aggsenderT
},
flow: flows.NewPPBuilderFlow(logger,
flows.NewBaseFlow(logger, l2BridgeQuerier, storage,
l1InfoTreeQuerierMock, lerQuerier, flows.NewBaseFlowConfigDefault()),
l1InfoTreeQuerierMock, bridgetypes.EmptyLER, nil, flows.NewBaseFlowConfigDefault()),
storage, l1InfoTreeQuerierMock, l2BridgeQuerier, signer, true, 0),
}
var flowMock *mocks.AggsenderBuilderFlow
Expand Down
5 changes: 3 additions & 2 deletions aggsender/aggsender_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
aggkitcommon "github.com/agglayer/aggkit/common"
"github.com/agglayer/aggkit/grpc"
signertypes "github.com/agglayer/go_signer/signer/types"
ethcommon "github.com/ethereum/go-ethereum/common"
)

var (
Expand All @@ -34,10 +35,10 @@ func NewAggsenderValidator(ctx context.Context,
aggLayerClient agglayer.AggLayerClientCertificateIDQuerier,
certQuerier types.CertificateQuerier,
aggchainFEPQuerier types.AggchainFEPRollupQuerier,
lerQuerier types.LERQuerier,
initialLER ethcommon.Hash,
signer signertypes.Signer) (*AggsenderValidator, error) {
validatorCert := validator.NewAggsenderValidator(
logger, flow, l1InfoTreeDataQuerier, certQuerier, lerQuerier)
logger, flow, l1InfoTreeDataQuerier, certQuerier, initialLER)
grpcServer, err := grpc.NewServer(cfg.ServerConfig)
if err != nil {
return nil, err
Expand Down
25 changes: 11 additions & 14 deletions aggsender/db/aggsender_db_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,39 +138,36 @@ func NewAggSenderSQLStorage(logger aggkitcommon.Logger, cfg AggSenderSQLStorageC
retainPolicy: &cfg.RetainCertificatesPolicy}, nil
}

// GetCertificateHeadersByStatus returns a list of certificate headers by their status
// GetCertificateHeadersByStatus returns a list of certificate headers by their status.
// If statuses is nil or empty, all certificates are returned.
func (a *AggSenderSQLStorage) GetCertificateHeadersByStatus(
statuses []agglayertypes.CertificateStatus) ([]*types.CertificateHeader, error) {
condition := ""

whereClause := ""
args := make([]any, len(statuses))

if len(statuses) > 0 {
placeholders := make([]string, len(statuses))
// Build the WHERE clause for status filtering
for i := range statuses {
placeholders[i] = fmt.Sprintf("$%d", i+1)
args[i] = statuses[i]
}

// Build the WHERE clause with the joined placeholders
condition += "status IN (" + strings.Join(placeholders, ", ") + ")"
whereClause = "status IN (" + strings.Join(placeholders, ", ") + ")"
}

// Add ordering by creation date (oldest first)
condition += " ORDER BY height ASC"

return a.getCerts(nil, tableCertificate, condition, args)
return a.getCerts(nil, tableCertificate, whereClause, "ORDER BY height ASC", args)
}

func (a *AggSenderSQLStorage) getCerts(tx dbtypes.Querier, table tableName,
condition string, args []any) ([]*types.CertificateHeader, error) {
whereClause string, suffix string, args []any) ([]*types.CertificateHeader, error) {
if tx == nil {
tx = a.db
}
query := fmt.Sprintf("SELECT * FROM %s", table)
if condition != "" {
query += " WHERE " + condition
if whereClause != "" {
query += " WHERE " + whereClause
}
if suffix != "" {
query += " " + suffix
}
var certificates []*types.CertificateHeader
if err := meddler.QueryAll(tx, &certificates, query, args...); err != nil {
Expand Down
4 changes: 2 additions & 2 deletions aggsender/db/retain_certificates_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ func TestRetainPolicy_NCerts(t *testing.T) {
}
}
// Check the expected number of certs in the main table
certs, err := storage.getCerts(nil, tableCertificate, "", nil)
certs, err := storage.getCerts(nil, tableCertificate, "", "", nil)
require.NoError(t, err)
certKeys := certsToCertificateKey(certs)
require.Equal(t, tc.expectedCentificateInfo, certKeys)
// Check the expected number of certs in the history table
certs, err = storage.getCerts(nil, tableCertificateHistory, "", nil)
certs, err = storage.getCerts(nil, tableCertificateHistory, "", "", nil)
require.NoError(t, err)
certKeys = certsToCertificateKey(certs)
require.Equal(t, tc.expectedCentificateInfoHistory, certKeys)
Expand Down
Loading
Loading